关于 paper-figures
paper-figures 是一项技能,可根据表格数据和自然语言说明制作适合发表的图表。它会生成并运行可复现的 matplotlib 脚本,再依据要求审查输出的 PNG。
主要功能
- 01支持 CSV、JSON 或内嵌数据
- 02自然语言图表规格
- 03使用 matplotlib 的 Python 脚本
- 04以 300 DPI 渲染 PNG
- 05渲染后审查并生成状态报告
适用场景
- 01将 CSV 中的实验结果绘成图表
- 02按自然语言描述生成图表
- 03根据数据和规格检查论文插图
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ evoscientist/ evoskills --skill paper-figures安装后在 Claude Code 中输入/paper-figures确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
requirements.txtreferences/chart-types.mdpublication-style.mdscripts/validate_figure.py详细介绍
论文图表
使用 matplotlib,根据表格数据和自然语言描述,系统地制作可直接用于出版的图表(PNG)。
何时使用此技能
- 用户提供 CSV、数据帧或内联数据,并要求绘制图表
- 用户用文字描述目标图表,并希望将其渲染出来
- 用户在论文或实验场景中提到“figure”“plot”“chart”“visualize”或“render”
输入和输出
Agent 将收到的输入:
- 数据源:CSV 文件路径、JSON 或内联表格。
- 描述:用自然语言指定图表类型、坐标轴、标题、颜色、注释、图例、场景等。有时描述很简短,有时是完整段落。描述就是完整规范——不会提供参考图像。
输出(始终提供):
- 独立的 Python 脚本
plot.py,该脚本会:- 从所提供的数据源加载数据
- 使用
matplotlib渲染图表 - 通过
plt.savefig(..., dpi=300, bbox_inches="tight")保存 PNG
- 与脚本放在同一目录下的渲染结果
plot.png(必须运行脚本并生成 PNG,不能只交付脚本)。
验证产物(有文件系统访问权限时写入):
figure-spec.md— 编码前提取的简明图表规范。audit.md— 渲染后的审查清单及所做的修复。final-status.md— 一个可见的状态标签:PASSED、PASSED_WITH_WARNINGS、REPAIRED或FAILED_NEEDS_HANDOFF。
输出目录:
- 如果用户指定了输出目录(例如“保存到
path/to/dir/”),请将plot.py和plot.png写入该目录。如果目录不存在,请创建它。 - 如果未指定目录,请写入当前工作目录。
- 文件名始终为
plot.py和plot.png。对不同输入重复运行时,应写入不同目录,而不是使用不同文件名——这样可稳定地在 PNG 所在目录中找到脚本,也便于批量比较。
设置
依赖项:pip install matplotlib pandas numpy scipy(也列在该技能根目录的 requirements.txt 中)。请安装到用户正在使用的环境中。
核心工作流
Step 1: Plan Figure -> verify: description/data ambiguity handled
Step 2: Inspect the data
Step 3: Write figure-spec.md -> verify: figure-spec.md has all required fields
Step 4: Pick the matplotlib idiom
Step 5: Apply publication-style defaults
Step 6: Write the script and run it -> verify: plot.py runs and plot.png exists
Step 7: Audit the result -> verify: chart matches spec, data, and description;
repair and re-audit until it does; final-status.md is honest
请将工作流视为一项小型验证流程,而不是一次性绘图任务。只有在审查通过,或明确标出尚未解决的问题后,图表才算完成。
状态标签
最终状态必须且只能使用以下一项:
| 状态 | 含义 |
|---|---|
PASSED | 图表符合所要求的图表类型、数据字段、比例尺、标签、数据系列、图例、注释和输出要求。 |
PASSED_WITH_WARNINGS | 图表可用且符合请求,但仍存在轻微的样式或布局差异,并已在 audit.md 中说明。 |
REPAIRED | 首次渲染未通过至少一项审查,随后修改了脚本,修复后的渲染结果现已通过。 |
FAILED_NEEDS_HANDOFF | 无法验证或修复必需字段、图表语义、软件包依赖项或视觉要求。请明确说明具体阻碍。 |
不能仅因脚本成功运行就标记为 PASSED。运行脚本只能证明 PNG 已生成,不能证明图表符合请求。
第 1 步:规划图表
在编写任何代码之前,请根据描述确定:
- 图表类型(折线图、柱状图、散点图、饼图、KDE、小提琴图、气泡图、龙卷风图、环形图、热力图,……)。如果不明确,优先采用描述中明确提到的类型;否则根据坐标轴/数据形态推断。
- 坐标轴:x 轴标签、y 轴标签、单位、刻度(线性/对数)、刻度格式。注意 子图之间共享的坐标轴、当两个系列共用 x 轴但 y 轴单位不同时使用双轴(
ax.twinx()/ax.twiny()),以及当数值范围相差很大时使用双坐标轴/断轴。 - 标题:如果描述中引用了标题,请原样使用。
- 系列/类别:数量、名称、顺序。
- 颜色:如果指定了具体颜色,请使用;否则采用默认配色。
- 注释:图例、网格线、参考线、数据标签。
如果描述提到了数值(“约 200”“刚高于 0”),请将其作为核对 CSV 的合理性检查依据——描述是转述,CSV 才是权威数据。
以下是一些反复出现的模式:
- 横截面数据的标题语境:如果数据是某个快照(某一年、某次实验),请在标题中注明这一语境,可以用括号、逗号分隔的后缀或引号括起的前缀。不要通过
fig.text或类似方式添加单独的“副标题”;matplotlib 没有简洁的副标题 API,临时添加的副标题往往会导致对齐和样式不一致。 - 区分多个系列,但不要重复编码:有多个系列时,读者必须能区分它们——可以使用线条末端的直接标签、图例,或搭配图例使用不同线型。不要重复标注(同一系列既用图例又用线条末端标签;同一点或区域既有图例项又有图上文字注释),但也不要完全省略标识:绘制多条曲线却不提供识别依据绝不可接受。
- 不要悄悄丢弃数据:输入中的每个系列和数据点都必须出现在图中,或得到说明。如果某个值超出坐标范围,请在边缘标注。如果省略了整个系列,描述必须说明理由。悄悄省略属于缺陷——读者无法仅凭图表看出缺少了什么。
- 不要擅自添加元素;但要计算描述要求的内容:严格绘制描述要求的内容,不要多画。不要添加需求中未要求的图例项、注释或视觉元素。不要虚构数据中不存在的行,也不要计算描述未提及的推断性汇总或聚合数据。但是:描述明确要求的派生统计(四分位数、均值、平滑曲线、回归拟合、密度估计等)必须忠实计算,不能省略。
如果需求存在会改变图表语义的关键歧义(例如有两个可能的 y 变量,或单位换算不明确),请提出一个具体问题。如果歧义仅涉及样式,请选择更简单的方案,并将其记录在 figure-spec.md 中。
第 2 步:检查数据
在编写绘图代码之前,先读取前约 10 行数据和列名。描述提供语义意图,CSV 提供结构事实。若两者对列名的说法不一致,请以 CSV 为准。
对于多系列数据,请检查数据是长格式(每个(系列、x、y)组合占一行)还是宽格式(每个系列占一列)。根据需要进行透视或熔化。
步骤 3:编写 figure-spec.md
开始编码前,先编写一份简洁的 Markdown 规范。审计会以此为准。使用以下格式:
# Figure Spec
- chart_type:
- data_sources:
- rows_in_scope:
- data_columns:
- x_axis:
- field:
- label:
- unit:
- scale:
- range:
- y_axis:
- field:
- label:
- unit:
- scale:
- range:
- additional_axes:
- series_or_categories:
- category_order:
- color_mapping:
- size_mapping:
- legend:
- required_annotations:
- forbidden_elements:
- layout_constraints:
- source_note:
- assumptions:
规则:
- 每个数值轴都必须明确指定
scale(linear、log、symlog等)。 forbidden_elements必须包含那些看似有用、但并未要求的视觉元素,例如回归线、对角参考线、所有数据点的标签、额外的大小图例或聚合。- 如果给出了类别顺序,
category_order必须遵循描述中的顺序。否则,除非明确要求排序,否则应保留数据顺序。 - 如果推导出统计量、聚合结果、拟合线或平滑曲线,必须在
assumptions中说明计算方法。
步骤 4:选择 matplotlib 用法
每种图表类型的绘制方法(每种受支持图表类型对应一段简短的 matplotlib 代码)请参见 references/chart-types.md。遇到不熟悉的类型,或需要回顾较复杂的类型(龙卷风图、环形图、KDE)时,请阅读该文件。
步骤 5:应用出版级默认设置
尺寸、字体、调色板、DPI 和 savefig 约定请参见 references/publication-style.md。除非描述中有明确相反要求,否则每次都应应用这些设置。
步骤 6:编写脚本并运行
- 编写脚本。
- 使用
python plot.py执行脚本。 - 确认已生成 PNG。
- 如果脚本报错,先修复并重新运行,再报告完成情况。
如果 scripts/validate_figure.py 可用,请在渲染后运行(脚本路径相对于此技能所在目录):
python scripts/validate_figure.py --output-dir <output-dir> --spec <output-dir>/figure-spec.md
步骤 7:审计结果
对照代码和数据重新阅读描述。Agent 目视检查 PNG 并不可靠,因此应通过结构化方式进行验证:
- 是否设置了描述要求的标题、两个轴标签和图例?
- 系列名称、顺序和颜色是否与描述一致?
- 数据中的峰值、最小值和趋势位置是否与文字描述一致(例如,如果描述说“峰值略高于 0”,数据是否确实在此处达到峰值)?
- 是否涵盖了描述提及的每个不同元素(网格线、参考线、注释)?
- 是否有描述未要求移除的坐标轴刻度消失了?如果调用了
ax.tick_params(length=0)、set_xticks([])或隐藏了坐标轴脊线,能否根据描述说明理由?默认状态是“显示刻度”——擅自隐藏刻度属于缺陷。 - 尤其要注意直方图:x 轴刻度就是分箱边界——绝不能隐藏。没有 x 轴刻度的直方图无法阅读。
- 如果有意移除了某组刻度(因为描述有此要求),是否提供了能确保可读性的替代方式,例如在线条端点直接标注、使用颜色条或标注数值?
- 坐标轴范围必须包含描述中提到的所有内容。 如果简述点名了特定区域、标注点或数值,
ax.set_xlim/ax.set_ylim必须将其纳入范围。紧凑取景导致图表中的指定特征被裁切,属于缺陷——等同于悄悄丢弃数据。
将任何遗漏都视为缺陷,并修复脚本。
在 audit.md 中记录审计结果:
# Figure Audit
- script_ran: yes/no
- png_exists: yes/no
- chart_type_matches_spec: pass/fail
- data_columns_match_spec: pass/fail
- axis_scales_match_spec: pass/fail
- labels_units_match_spec: pass/fail
- series_category_order_match_spec: pass/fail
- legend_complete_and_uncropped: pass/fail
- annotations_match_spec: pass/fail
- forbidden_elements_absent: pass/fail
- obvious_text_overlap_or_clipping: pass/fail
- repairs_made:
- remaining_warnings:
- final_status:
如果任何必需项未通过,请修改 plot.py,重新运行脚本并再次进行审计。必需项未通过时,不得将任务标记为完成。如果因输入相互矛盾或依赖项不可用而无法满足某项要求,请将 final_status: FAILED_NEEDS_HANDOFF,并说明确切原因。
核心设计规则
0. 忠实度优先于样式
优先级顺序:
- 匹配所要求的数据语义。
- 匹配图表类型、轴字段、刻度比例、单位、标签、图例、注释、类别顺序和视觉编码。
- 保持图表易读。
- 应用出版级样式。
出版级样式不得改变图表语义。除非描述明确要求,或 figure-spec.md 有依据,否则不要为了美观添加视觉元素。
1. 脚本必须独立且可复现
不要硬编码用户未要求的内容。请从提供的路径读取数据;如果存在 CSV,就不要编造数字。同一个 plot.py 应能在任何安装了 matplotlib 的机器上重新生成相同的 PNG。
2. 描述表达意图,CSV 才是事实依据
描述中的数值可能是概述或经过四舍五入的。如果文字与 CSV 冲突,请按 CSV 作图,但要符合描述所暗示的叙事形状(峰值位置、趋势、排序)——如果不一致,很可能说明你解析数据时出了错。
3. 一张图、一个文件、一次保存
最后只调用一次 plt.savefig(...)。不要到处插入中间的 plt.show() 调用(在无头环境中会阻塞)。除非明确要求,否则不要编写多图脚本。
4. 简单情况优先使用 matplotlib pyplot,复杂布局使用 OO 接口
单个 Axes 使用 plt.plot / plt.bar 即可。一旦需要子图、双坐标轴或针对各坐标轴分别设置样式,就改用 fig, ax = plt.subplots(...) 并调用 ax 的方法。在同一张图中混用两种接口会导致代码脆弱。
5. 颜色承载含义
如果描述指定了颜色(“低值用蓝色,高值用橙色”),就按要求使用——颜色能帮助读者理解含义。否则,默认使用感知均匀的调色板(分类数据可用 tab10;连续数据可用 viridis)。
6. 突出信息,不做装饰
网格、刻度、边框和注释都应有助于阅读。默认去除图表杂项:大多数图表中隐藏上、右边框(ax.spines[['top','right']].set_visible(False));只有在需要比较数值大小时才启用浅色 y 轴网格。
7. 为标题留出空间
tight_layout() 可能会把标题裁切到坐标轴顶部。请在 rcParams 代码块中设置 "axes.titlepad": 10(见 publication-style.md),或在 ax.set_title(...) 中传入 pad=10。标题紧贴坐标轴,是生成图表显得未完成的最常见原因。
8. 多面板布局使用 gridspec,而不是叠加多次 savefig
交付物必须是单个 PNG。描述要求多个子图(带侧面板的主图、2×2 对比网格、带插图的图表)时,请通过 fig.add_gridspec(...) 将它们组合在一张图中,并只调用一次 savefig。不要输出多个 PNG;评测工具只会读取一个。参见 chart-types.md → 多面板组合。
9. 使用 matplotlib 的高级 API;避免手动计算坐标
如果 matplotlib 已经提供了布局、注释或格式设置的辅助工具——例如用于锚定到数据的子坐标轴的 inset_axes、用于组合面板的 gridspec、用于为各条形添加数值标注的 bar_label、用于调整边距的 tight_layout / constrained_layout,以及用于设置坐标轴标签格式的 ticker.FuncFormatter——就应使用这些工具,而不是手动计算位置、变换或文本摆放位置。高级辅助工具能适应图形尺寸调整、DPI 变化以及后续的 subplots_adjust 调用;手动坐标变换则会在布局变化时失效。如果你发现自己在进行像素运算,或手动串接 ax.transData / ax.transAxes,请停下来,先查找是否有内置工具可用。
容易误解的注意事项
不要只看图表类型标签
描述中的“龙卷风图”在技术上可能是水平分组条形图(每个类别都有正向和负向条形)。选择绘图方案之前,请先理解描述暗示的形状,并与数据布局进行核对。
描述中的数字只是近似值
描述可能会说“约 200”,而实际值是 187.4。请绘制 187.4。只有在 CSV 明显有误时(例如描述纠正了单位不匹配),才偏离 CSV。
样式默认值优于临时调整
每次为单张图调整 rcParams,都会产生一种难以跨图比较的特例样式。请始终应用 publication-style.md 中的出版级默认样式——只有描述有明确要求时,才针对单张图进行覆盖。
参考导航
| 主题 | 参考文件 | 使用场景 |
|---|---|---|
| 图表类型示例 | chart-types.md | 需要为特定图表类型选择合适的 matplotlib 写法 |
| 出版物样式 | publication-style.md | 设置图形尺寸、字体、调色板、DPI、savefig |