c06_time_trend 时间序列 (Time-Series) IEEE Nature The Economist

Multi-Series Time-Trend Plot with Confidence Interval Bands

多组别纵向时间趋势图,包含均值动态折线与半透明 95% 置信区间 (CI) 阴影填充带。

🔬 矢量预览 (Vector Preview) 600 DPI Ready
Multi-Series Time-Trend Plot with Confidence Interval Bands

📊 统计学特性 (Statistical Features)

  • 移动均值 / 分组聚合均值
  • Bootstrap 95% 置信区间
  • 时序节点连线平滑
  • 组间方差带叠加

🛡️ QC 质检要点 (QC Highlights)

  • 图例置于图内空白区域或顶部
  • 置信区间透明度 (Alpha 0.15-0.25)
  • 时间轴刻度格式统一
  • 线条粗细层级清晰
🎨 顶刊色彩提取器 (Palette Extractor)Nature

Crisp sans-serif typography, clean borderless spines, high-contrast palette with soft muted secondary accents.

🛡️ 无障碍评分:AAA (Deuteranopia & Protanopia Compliant)

📋 Data Contract 数据契约规范 Strict Schema

输入数据必须完全符合下列列名与数据类型规范,方可通过自动化数据前检 (Pre-flight Validation)。

📥 下载规范示例 CSV 数据
字段名称 (Column) 数据类型 (Type) 约束性 语义说明与值域约束
time_step continuous 必需 (Required) Temporal index, epoch, or continuous time measurement
series categorical 必需 (Required) Model, cohort, or series identifier
value continuous 必需 (Required) Continuous response or performance metric
ci_lower continuous 可选 (Optional) Lower bound of confidence interval
ci_upper continuous 可选 (Optional) Upper bound of confidence interval
组内最小样本量: n ≥ 3
最大允许缺失率: 5%

🐍 独立可复现 Python 绘图源码 Stand-alone Script

完全可复现的 Python 脚本,支持 CLI 参数 `--data`, `--style`, `--output-dir` 与模块化 `render()` 调用。

#!/usr/bin/env python3
"""FigureCraft Chart Engine: Multi-Series Time-Trend Plot (c06_time_trend)."""

import os
import sys
import argparse
from pathlib import Path
from typing import List, Dict, Optional
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

try:
    from engines.styles import apply_style, get_palette
except ImportError:
    sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
    from engines.styles import apply_style, get_palette

CHART_ID = "c06_time_trend"

MARKERS = ["o", "s", "^", "D", "v", "<", ">", "p"]


def render(
    data_path: Optional[str] = None,
    style: str = "nature",
    output_dir: str = "output",
    formats: Optional[List[str]] = None,
    dpi: int = 600,
) -> Dict[str, str]:
    if formats is None:
        formats = ["svg", "pdf", "png", "tiff"]
    if data_path is None:
        data_path = str(Path(__file__).resolve().parents[1] / "data" / f"{CHART_ID}.csv")

    apply_style(style)
    palette = get_palette(style)
    df = pd.read_csv(data_path)
    df = df.dropna(subset=["time_step", "series", "value"])

    series_names = list(df["series"].unique())

    fig, ax = plt.subplots(figsize=(6.5, 4.5))

    for i, s_name in enumerate(series_names):
        sub_df = df[df["series"] == s_name].sort_values("time_step")
        x = sub_df["time_step"].values
        y = sub_df["value"].values
        color = palette[i % len(palette)]
        marker = MARKERS[i % len(MARKERS)]

        # Line plot with markers
        ax.plot(
            x,
            y,
            label=s_name.replace("_", " "),
            color=color,
            linewidth=1.8,
            marker=marker,
            markersize=5.0,
            markeredgecolor="#FFFFFF",
            markeredgewidth=0.6,
            zorder=3,
        )

        # Shaded CI envelope
        if "ci_lower" in sub_df.columns and "ci_upper" in sub_df.columns:
            ci_low = sub_df["ci_lower"].values
            ci_high = sub_df["ci_upper"].values
            ax.fill_between(x, ci_low, ci_high, color=color, alpha=0.18, zorder=2)

    ax.set_xlabel("Training Epoch / Time Index")
    ax.set_ylabel("Performance Benchmark Metric (%)")
    ax.set_title("Multi-Series Performance Trajectories with 95% CI Bands")
    ax.legend(loc="lower right", frameon=False, fontsize=7.5)

    os.makedirs(output_dir, exist_ok=True)
    generated_files = {}
    for fmt in formats:
        out_path = os.path.join(output_dir, f"{CHART_ID}_{style}.{fmt}")
        fig.savefig(out_path, format=fmt, dpi=dpi, bbox_inches="tight")
        generated_files[fmt] = str(Path(out_path).resolve())

    plt.close(fig)
    return generated_files


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Render Multi-Series Time-Trend Plot")
    parser.add_argument("--data", type=str, default=None, help="Path to input CSV dataset")
    parser.add_argument("--style", type=str, default="nature", choices=["nature", "cell", "lancet", "ieee", "economist"], help="Journal style pack")
    parser.add_argument("--output-dir", type=str, default="output", help="Output directory")
    parser.add_argument("--formats", type=str, default="svg,pdf,png,tiff", help="Comma-separated export formats")
    parser.add_argument("--dpi", type=int, default=600, help="Raster DPI")
    args = parser.parse_args()

    fmt_list = [f.strip() for f in args.formats.split(",") if f.strip()]
    results = render(args.data, style=args.style, output_dir=args.output_dir, formats=fmt_list, dpi=args.dpi)
    for fmt, path in results.items():
        print(f"Generated {fmt.upper()}: {path}")