c13_radar 多维画像 (Multivariable) IEEE Cell Nature

Radar / Spider Multidimensional Profiling Chart

极坐标多维雷达图 (Spider Chart),用于多模型基准评估、临床多维度评分或样本能力画像直观对比。

🔬 矢量预览 (Vector Preview) 600 DPI Ready
Radar / Spider Multidimensional Profiling Chart

📊 统计学特性 (Statistical Features)

  • 极坐标维度等角均分
  • 多维指标归一化 (0-100)
  • 半透明多边形填充覆盖
  • 同心多边形网格刻度

🛡️ QC 质检要点 (QC Highlights)

  • 各极轴刻度文字清晰不倒置
  • 多边形重叠透明度控制 (Alpha 0.2-0.35)
  • 闭合曲线平滑连接
  • 图例清晰标明实体
🎨 顶刊色彩提取器 (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) 约束性 语义说明与值域约束
entity categorical 必需 (Required) Model, algorithm, or candidate profile name
Reasoning continuous 必需 (Required) Reasoning benchmark score (min: 0, max: 100)
Coding continuous 必需 (Required) Coding benchmark score (min: 0, max: 100)
Math continuous 必需 (Required) Mathematics benchmark score (min: 0, max: 100)
Context_Window continuous 必需 (Required) Context window efficiency score (min: 0, max: 100)
Safety continuous 必需 (Required) Safety & alignment score (min: 0, max: 100)
Efficiency continuous 必需 (Required) Inference efficiency score (min: 0, max: 100)
组内最小样本量: n ≥ 1
最大允许缺失率: 0%

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

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

#!/usr/bin/env python3
"""FigureCraft Chart Engine: Radar / Spider Multidimensional Chart (c13_radar)."""

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 = "c13_radar"


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=["entity"])

    # Extract dimensions (all non-entity columns)
    dim_cols = [c for c in df.columns if c != "entity"]
    num_vars = len(dim_cols)

    # Compute angles for polar axes
    angles = np.linspace(0, 2 * np.pi, num_vars, endpoint=False).tolist()
    # Close polygon loop
    angles += angles[:1]

    fig, ax = plt.subplots(figsize=(6.0, 5.5), subplot_kw=dict(polar=True))

    for i, (_, row) in enumerate(df.iterrows()):
        entity_name = str(row["entity"]).replace("_", " ")
        values = row[dim_cols].values.flatten().tolist()
        values += values[:1]
        color = palette[i % len(palette)]

        # Draw boundary line
        ax.plot(angles, values, color=color, linewidth=1.8, label=entity_name, zorder=3)
        # Fill polygon
        ax.fill(angles, values, color=color, alpha=0.18, zorder=2)
        # Draw point markers
        ax.scatter(angles[:-1], values[:-1], color=color, s=24, edgecolors="#FFFFFF", linewidth=0.5, zorder=4)

    # Configure polar axis
    ax.set_theta_offset(np.pi / 2)
    ax.set_theta_direction(-1)

    # Dimension spoke labels
    ax.set_xticks(angles[:-1])
    formatted_dims = [d.replace("_", " ") for d in dim_cols]
    ax.set_xticklabels(formatted_dims, fontsize=7.5, fontweight="medium")

    # Concentric rings
    ax.set_rscale("linear")
    ax.set_ylim(0, 100)
    ax.set_yticks([20, 40, 60, 80, 100])
    ax.set_yticklabels(["20%", "40%", "60%", "80%", "100%"], fontsize=6.5, color="#6B7280")
    ax.grid(color="#E5E7EB", linestyle="--", linewidth=0.6)

    ax.set_title("Multi-Dimensional Benchmark Capability Profiling", pad=20, y=1.08)
    ax.legend(loc="upper right", bbox_to_anchor=(1.25, 1.1), 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 Radar / Spider Chart")
    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}")