☰
代码实现原理:scipilot-figure-skill 的 visual_qa 如何拦截缺字与乱码
2026/10/2 22:05:23 网站建设 项目流程

代码实现原理:scipilot-figure-skill 的 visual_qa 如何拦截缺字与乱码

【免费下载链接】scipilot-figure-skillSciPilot Skills family - Publication-grade scientific figure copilot for Claude Code项目地址: https://gitcode.com/gh_mirrors/sc/scipilot-figure-skill

scipilot-figure-skill 是 SciPilot Skills 家族的科研数据可视化顾问技能,而它的 scripts/visual_qa.py 正是出图后「程序自检」的机器层——专治 matplotlib 成图中最常见的缺字与乱码(中文变□□□豆腐块、负号变方框、±、μ、希腊字母缺字),并顺带检查文字越界裁切和刻度标签重叠,把排版问题挡在投稿之前。

为什么缺字乱码会"藏"到投稿才暴露?

matplotlib 处理缺字的方式非常"温柔":遇到缺失字符只发一条 warning,图照样画出来,不报错(根因分析见 references/viz_pitfalls.md 的 P16 条目)。而它的默认字体(DejaVu Sans 等)根本不含中文字符表,axes.unicode_minus=True时负号也可能渲染成方框。

于是常见事故就是:画的时候没注意终端里那行小字,投稿时审稿人看到的却是一张满是方框的图。visual_qa要解决的就是:把这两条告警通道变成必须过审的质检关卡。

设计定位:自检闭环里的"机器那一层"

v2.1 版本的视觉自检闭环分为两层分工(详见 references/visual_review.md):

层负责抓
程序自检(本文主角 visual_qa)确定性问题:缺字乱码、文字越界裁切、刻度标签重叠
AI 读图感知性问题:图例压数据、子图标签对齐、配色灰度可分

缺字乱码属于"确定性"问题——字体表里有没有这个字符,答案唯一,所以交给程序判断,又快又不会漏。

核心实现①:双通道拦截缺字告警

缺字检测的入口是_draw_and_collect_glyph_warnings。它的关键设计是同时挂住两条告警通道:

  • warnings 通道:用warnings.catch_warnings(record=True)记录渲染期间所有 warning(老版本 matplotlib 走这条);
  • logging 通道:自定义_GlyphLogHandler挂到matplotliblogger 上(新版本走这条)。

两边都用一组关键词过滤(_GLYPH_MARKERS:"missing from"、"Glyph"、"findfont"),命中即收集;最后去重并保持顺序。

渲染这一步很讲究:fig.savefig直接写进内存BytesIO,不落盘——目的不是存图,而是让 renderer 真正执行一次绘制(缺字告警只在真正绘制时触发),顺便让 renderer 就绪,供后续的文字越界测量复用。

核心实现②:缺字即 FAIL,并附上修复建议

audit_layout汇总所有检测结果,返回[(severity, msg), ...]列表,严重级别约定与 scripts/check_figure.py 保持一致:INFO < WARN < FAIL。

缺字被直接判定为FAIL(audit_layoutL148-L157),且告警信息不是冷冰冰的一句"出错",而是带着处方:

检测到缺字,成图会出现方框/乱码……中文图请先setup_style(lang='zh')配置 CJK 字体;若是负号方框,确认axes.unicode_minus=False。

这样 AI 或开发者拿到报告就能直接定位到 scripts/setup_style.py 的字体配置环节去修,而不是反复猜。

核心实现③:顺手把裁切和刻度重叠也查了

renderer 就绪之后,audit_layout还做两项 WARN 级检查:

  1. 文字越界裁切:遍历图中所有可见Text对象,用get_window_extent(renderer)量出包围盒,超出画布边界(留 2px 容差)就告警。注意它刻意跳过刻度标签——刻度贴边属于constrained_layout的自动处理范围,查它们只会误报(L168-L198);
  2. 刻度标签重叠:对相邻 tick label 的包围盒做水平/垂直相交判断(x 轴看水平、y 轴看垂直,容差 1px),相交即提示旋转刻度或减少刻度(_ticklabels_overlap)。

整个过程非破坏性:只渲染测量,不修改 fig 内容。

配套能力:render_preview 渲出"可被 AI 看见"的预览

程序查完确定性问题,感知性问题还得靠 AI 读图。render_preview负责把图栅格化成中分辨率 PNG(默认 150 dpi,bbox_inches='tight')——矢量 PDF/SVG 没法直接"看"像素重叠,必须先转位图。它接受三种输入:matplotlib Figure 对象(主路径)、已落盘的位图路径、PDF(需可选依赖 PyMuPDF)。

典型的自检闭环用法只有三行:

from visual_qa import render_preview, audit_layout, print_report render_preview(fig, "figs/_preview.png", dpi=150) # 给 AI 读图 print_report(audit_layout(fig)) # 缺字/裁切/重叠

随后用 Read 工具读这张 PNG,对照 references/visual_review.md 的 8 项读图清单逐条核对;发现问题回改、重渲、再读,直到通过(SKILL.md 第 6 步 有完整流程)。

相关文件导航

文件角色
scripts/visual_qa.py本文主角:双通道缺字拦截 + 裁切/重叠检查 + PNG 预览
references/visual_review.md视觉自检闭环协议:AI 读图 8 项清单 + 回改对应表
references/viz_pitfalls.mdP16 缺字乱码条目:根因分析与正确做法
scripts/setup_style.pyCJK 字体自动配置,从源头减少乱码
SKILL.md8 步核心工作流与自检闭环定义

一句话总结:visual_qa的精髓不在于"检测"本身,而在于它把 matplotlib 那条容易被忽略的缺字 warning,升级成了一条必须处理才能过检的 FAIL 关卡——再配合 AI 读图复核感知性问题,中文方框和乱码在导出之前就被拦下了。

【免费下载链接】scipilot-figure-skillSciPilot Skills family - Publication-grade scientific figure copilot for Claude Code项目地址: https://gitcode.com/gh_mirrors/sc/scipilot-figure-skill

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询