c13_radar 多维画像 (Multivariable)
IEEE Cell Nature
Radar / Spider Multidimensional Profiling Chart
极坐标多维雷达图 (Spider Chart),用于多模型基准评估、临床多维度评分或样本能力画像直观对比。
🔬 矢量预览 (Vector Preview)
600 DPI Ready
格式支持: SVG, PDF, PNG (600 DPI), TIFF
📊 统计学特性 (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)。
| 字段名称 (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}")