Biofigure Memory — 生信 figure 学习库与复用引擎
本技能维护一个自进化的个人图库:把用户发来的文献图(论文 PDF、链接、公众号文章、截图)解剖成「语言无关的绘制配方 + R/Python 可运行模板」沉淀下来;等用户真正要画图时,优先复用库里已学会的画法,而不是每次从零设计。用户对复用结果满意时,再把这次的画法回收入库,形成闭环。
技能只有两个模式,按用户意图选择:
- 模式 A 学习(ingest):用户发来了含 figure 的材料 → 解剖、沉淀入库。
- 模式 B 复用(reuse):用户要画一张生信图 → 先查图库,命中就复用,未命中就走普通设计流程,满意后顺势提议入库。
核心心法:参考模仿,不是一比一照抄
图库条目是画法参考,不是可直接调用的成品管线。每次用户的数据结构、组数、目的都不同,所以:
- 复用时提取的是条目的技术骨架(图层组织、映射方式、配色逻辑、排版策略、注释手段),其余一切——轴、阈值、色值、分面数、面板构成、尺寸——都按用户当前数据和目的重新决定。用户的目的优先于记录里的任何细节
- 允许部分借用:条目与需求只有局部相似时,就只借那一部分(比如只学它的标签防重叠策略、或只学它的行序联动设计),不要硬套整张图
- 学习时也要以这个标准写记录:配方写到「技术」层面而非「参数」层面(记"qualitative 色板 + 密度中心标编号",不要记"必须 8 个群用这 8 个色号")。原稿的具体数值只作为缺省建议写入复用要点
- 简单说:把条目当「范帖」临摹,不当「模板」填空。交付语也应体现这一点("参考了 003 的高亮画法,配色/分组按你的数据重排了"),而不是"调用了 003"
触发场景与预期行为
对照下表选择行为;「主动问」仅限交互环境,非交互环境一律取该行「不打扰」侧的行为:
| 场景 | 预期行为 |
|---|---|
| 明确要求学习/入库("学一下这个图""记住这个画法"),材料为链接/PDF/公众号/截图 | 模式 A,直接执行,不再确认 |
| 用户发来文献材料但未提学习,材料中有值得学的 figure | 一句话问是否入库(例:"Fig.3 的点图画法不错,入库吗?");非交互不打扰 |
| 明确要求画生信图(点名图型或描述意图,如"生存分析画条曲线") | 模式 B,先查库再动手 |
| 数据分析任务隐含出图需求(如差异分析跑完需要呈现结果) | 结果呈现前查库;命中按复用流程,未命中正常设计 |
| "照这张图画 / 按这篇文献风格复刻"(给了参考图或文献) | 参考图即规格:先按模式 A 学习它(这就是明确意图,无需再问),再按其配方对用户数据出图 |
| 用户对刚交付的图表示满意 | 提议入库(manual 来源),同意即走模式 A |
| 用户问"你都会画哪些图 / 看看图库" | 读 INDEX.md,按 chart_types 分组展示,不逐条展开 |
| 用户要求把条目发到别的设备("把 003 发给服务器")或导入一个 bundle 包 | 跨设备导出/导入:导出跑 export_figure.py,导入跑 import_figure.py,直接执行(见「跨设备导出/导入」节) |
不触发的边界(防止过度打扰与错误接管):
- 纯文献阅读、翻译、总结,用户没有表现出任何画图/学习意图 → 不主动提入库
- 用户已给出完整明确的绘图代码或参数 → 照做,不往图库上套
- 与生物/医学数据无关的通用图表(商业图表、装饰性插图等)→ 本技能不接管,走正常画图流程
图库位置
图库内嵌在技能目录下(<本技能目录>/library/),与技能是同一个文件夹——把整个技能目录拷贝/同步到任何设备的任何 agent 的技能目录,技能与图库同时就位,无需任何配置。图库是纯文件,建议对技能目录做 git 版本管理(防误删,同步也有历史)。跨设备有两条路线:整库双向同步(私有 git 仓库或云盘),或按条目细粒度迁移(见「跨设备导出/导入」节)。
仅当用户明确要求把图库放在别处时,按以下顺序解析(脚本端同样遵守):
- 环境变量
BIOFIGURE_LIBRARY ~/.config/biofigure-self-evolve/config.json中的library_path字段- 回落到默认位置
<技能目录>/library/
图库结构(NNN 为三位递增序号,slug 用小写连字符英文):
<技能目录>/
├── SKILL.md
├── library/ # 图库(与技能一起同步)
│ ├── README.md
│ ├── INDEX.json # 机器可读索引,复用时先读这个
│ ├── INDEX.md # 人类可读索引,由脚本生成
│ └── figures/
│ └── 001-volcano-pathway-labels/
│ ├── figure.md # 学习记录:元数据 + 视觉解剖 + 配方(库的核心)
│ ├── reference.png # 原图(≤1600px 宽、<2MB)
│ ├── template.R # 自包含 R 模板,内嵌假数据,无参数运行即可出图
│ └── template.py # 自包含 Python 模板,同上
├── references/
└── scripts/
交互策略(先读这段)
每次进入任一模式前,先判断会话类型,行为随之固定:
交互环境(用户在场、可以提问):
- 学习:用户明确要求学习/入库 → 直接做,不再确认。用户只是发来材料没提学习 → 判断材料里是否有值得学的 figure,有则用一句话问(例:「Fig.2a 的富集点图画法不错,要入库学习吗?」),得到肯定才学。
- 复用:图库命中唯一且高置信 → 直接用,并在交付时说明用了哪条记录;有多个候选或置信不足 → 一次性列出候选(每条一行:id + 一句话区别),给出推荐项,让用户选。只在此时问,之后执行不再追问。
非交互环境(后台任务、管道、自动化流程、用户已声明不要询问):永远不要等待用户输入。
- 学习:仅在用户明确要求时执行;材料里没被要求学习的图不主动入库。
- 复用:选最匹配的一条直接画,把「用了图库哪条记录、基于什么假设做的适配」写进最终交付说明里。
模式 A:学习新 figure
A0 查重与归位(相似功能图的处理)
生信图大量"同功能、不同形":火山图、MA 图、显著性条形图都在"展示两组差异";KM 曲线、风险评分图、森林图都在"展示预后"。判断近似的标准是"用户要它回答什么问题",不是表面图类型。 学习前先读 INDEX.json,找出与新材料功能近似的已有条目(chart_types 相同、或 use_when 语义相近),然后三选一:
- 更新已有条目:新材料是同一画法的更清晰版本或细节补充 → 合并进旧条目(交互环境先问;非交互环境在新旧明显同款时默认更新)
- 登记为变体:核心画法相同但有实质差异(如带风险表的 KM vs 纯 KM 曲线)→ 新建条目,新旧双方 frontmatter 互写
related,并各自在正文「与相近条目的对比」一句话写清何时用谁——这是复用时多候选排序的依据 - 独立条目:仅图类型撞名、回答的问题确实不同 → 正常新建
宁可多建带 related 的变体条目,也不要把不同画法硬塞进一条记录里稀释配方精度。
A1 获取图像并确定学习单元
按材料类型取图,具体命令和各平台的坑见 references/ingest-sources.md(读取该文件后操作):
- 本地图片/截图 → 直接用
- PDF → pdftoppm 把对应页转成 PNG 再裁剪面板
- 文献链接/DOI → 优先走 PMC/出版社页面找开放获取的图片 URL
- 微信公众号链接 → 抓 HTML 里的
mmbiz.qpic.cn图片
追溯原始代码(材料有代码线索时必做——代码是配方的事实源,图像只是间接证据):
- 正文内嵌代码 → 直接作为一手配方(公众号教程常整段贴码,抓 HTML 时连正文文本一起提取)
- 文中提到 GitHub 仓库 → GitHub API 列文件树找绘图脚本(
api.github.com/repos/<user>/<repo>/git/trees/main?recursive=1,脚本名常含 fig/plot),raw 拉取(raw.githubusercontent.com/...) - 只给了论文 → 先解 DOI,WebFetch 其 PMC 全文的 "Data and code availability" 找仓库 URL,回到第 2 步
- 穷尽 1-3 未果 → 才回到看图反推,并在记录 source.ref 如实标注"代码未溯源,配方由图像解剖得出"
包名、几何对象、参数、数据整形一律以代码为准(实例:Fig.1E 肉眼看像 ggalluvial,代码揭示是 ggsankey)。细节命令见 references/ingest-sources.md 第 6 节。
取到图后,先判断图与图之间的关系,再决定学习单元的粒度——生信文献图的新意往往不在单图,而在组合与成对叙事。三种粒度:
- 单图条目:一个独立图表类型的画法(如一张编号 UMAP)
- 组合版式条目:多子图拼接本身是亮点(如 UMAP 纵列 + dotplot + 热图并排)→ 条目核心是「面板联动」:行序/列序/配色/编号在面板间如何共享,必须逐条写清
- 图序模式条目:多张图作为一组讲一个故事(如「总览编号 UMAP 的群编号 = 详情组图的行索引」,总览图的价值正在于此)→ 把成对/成组的图拼成一张 reference,条目记录叙事分工与联动关系
判断口诀:删掉其中一张图、另一张的信息是否受损?受损 → 这是图序模式;单独都成立但并排更强大 → 组合版式;完全独立 → 各自成条目并用 related 互链。同一材料里被选中学习的是什么、没学的是什么,汇报时逐图说明(见 A8)。
A2 解剖
用 Read 查看图像,小面板先裁剪放大成局部图再读,逐面板回答:
- 图类型:对照
references/chart-taxonomy.md的受控词表打chart_types标签 - 数据形状:这张图需要什么样的输入(宽矩阵/长表/成对/邻接表…)
- 图层与映射:从底到顶有哪些图层,x/y/color/size/fill 各映射了什么
- 坐标与变换:log 轴、反转、极坐标、分面等
- 配色与排版:离散/连续色板、图例位置、尺寸比例、字号、导出规格
- 适用范围:什么场景该用它(use_when)、什么场景不该(not_when)——这是复用时匹配的关键字段,写具体
A3 写学习记录
图库根目录下新建 figures/NNN-slug/,写 figure.md。格式 schema 和完整示例必须先读 references/figure-record.md,frontmatter 只使用其中定义的字段和受限语法(不用多行块、锚点等复杂 YAML,保证任何设备任何工具都能解析)。正文包含:视觉解剖、语言无关配方、模板自检记录、复用要点。
解剖保持客观:若用户在学习时当场表达风格意见("这种配色我不喜欢"),那是偏好信号,写进 library/PREFERENCES.md,不要因此歪曲对原图的记录。
A4 写双语言模板并自检
template.R 与 template.py 各写一份,要求:
- 自包含:脚本内嵌生成符合 data_shape 的逼真假数据,无参数运行即出图(PNG 300dpi + PDF 矢量各一份,输出到脚本所在目录)
- 结构与 figure.md 里的配方一一对应,中文注释关键步骤;复用时用户只需要替换数据载入段
- 语言按图的特点选最顺手的实现:R 用 ggplot2 生态(ComplexHeatmap、patchwork 等),Python 用 matplotlib/seaborn 生态;两份模板功能对等
- 实际运行验证:
Rscript template.R、python3 template.py,确认能出图。通过 → frontmatterverified: both;只有一边的运行时可用或某边失败 → 如实标partial或unverified,并在正文「模板自检记录」写明原因。宁可如实标注,不要标记未验证的条目为通过
A5 保存原图
原图或裁剪后的面板存为 reference.png,用 sips 或 PIL 缩到宽 ≤1600px、<2MB(图库要跨设备同步,大图会拖慢 git/云盘)。仅作个人本地学习参考;若日后要公开分享图库,注意原文献版权。
A6 完工自检(学习要点清单)
写完记录和模板后,逐项核对下面的清单。这是学习完成的最低标准——缺任何一项就不算学完,不得进入汇报。清单存在的意义:模型容易"看懂了"就宣布学完,实际漏掉的恰恰是复用时最需要的信息。
- 回答什么问题:use_when 写到了"用户拿它回答什么",不是图名复述
- 数据形状:读者只看 data_shape 一行,就能判断自己的表能不能套
- 图层解剖可复现:每层画什么、映射、顺序、参数量级——不看原图也能照配方写出代码
- 配色具体:色值或色板名,不是"红蓝配色"
- 排版规格:尺寸比例、字号层级、图例位置、导出规格
- 联动关系(组合/图序条目必查):面板间共享的行序、列序、配色、编号逐条写明
- 边界与坑:not_when 写了误用场景;已知坑写了真实易错点
- 关系登记:
related与近似条目互指,对比句写清"何时用谁" - 模板可运行:R/Python 双模板均实际运行出图,verified 如实标注
- 原图可溯:reference.png 已存且 <2MB;source 五字段齐全可溯源
- 代码溯源(材料有代码线索时必查):原始代码已追溯并以代码校准配方(包名/参数/整形逻辑);穷尽路径未果的,source.ref 已如实标注"代码未溯源"
A7 更新索引
figure.md 是唯一事实源,索引文件是它的投影:运行 python3 <skill目录>/scripts/build_index.py 全量重建 INDEX.json 和 INDEX.md(不要手改这两个文件),并留意脚本输出的警告(缺字段、id 与目录名不一致、related 悬空等),有则回改 figure.md。
A8 汇报
汇报三件事:逐图取舍——材料里每张图,学了什么条目、没学的原因(装饰图/常规画法/与已学重复,判断要具体,"常规画法"这种否决必须给出理由,警惕低估组合与成对叙事的价值);学到什么——条目 id + 一句话;验证状态——模板运行情况、存到哪。
模式 B:复用画图
B1 检索
读 INDEX.json(缺失、或 python3 <技能目录>/scripts/build_index.py --check 报不一致时,先跑 build_index.py 重建)和 library/PREFERENCES.md(若存在)。索引用语义匹配而非纯关键词:综合 chart_types + data_shape + use_when/not_when + aliases 判断哪条记录符合用户当前的数据和意图;偏好档案记录着用户跨会话的稳定习惯,供 B3 实例化时填充其未指定的细节。
B2 多候选排序与选择
同功能的条目常有多条同时命中(这正是 A0 里 related 变体群的场景),按下述优先级排序后处理:
- 数据形状匹配度:用户的表能直接套 > 稍作整形能套 > 结构差异大
- 意图匹配度:use_when 命中用户要回答的问题;not_when 是否触雷
- verified 状态:both > partial > unverified
- 交互环境:列 top ≤3 候选,每条一行「id + 与其他候选的一句关键差异」(信息优先来自条目的「与相近条目的对比」节),给出推荐及理由,等用户选。不要把全部命中一次甩出来
- 非交互环境:直接用第 1 名,交付时注明"另有
NNN-xxx也适用,因 XX 选了本条"
B3 临摹式适配(不是套模板)
打开命中条目的 figure.md(重点看「配方」「复用要点」「与相近条目的对比」三节),以配方为骨架、以用户数据和目的为准绳重画,而不是把用户数据塞进模板:
- 先核对再动手:复用要点里的检查项(列名、分组列、阈值习惯、标签列是否存在)逐项对照用户数据
- 缺什么补什么:数据形状不符时先整形到配方要求的形状;用户没有配方假定的某列(如通路注释列)时,降级到该画法的无此注释变体,并告诉用户差在哪
- 按目的裁剪:用户目的与条目 use_when 有偏差时,只借用的确服务当前目的的部分(借图层结构、借配色逻辑、借联动设计……),其余按需取舍
- 取值优先级:用户当前指令 > 稳定偏好(
PREFERENCES.md)> 条目缺省——用户没指定的细节(阈值、配色、图例位置、导出规格)先用稳定偏好填充,没有稳定偏好才用条目缺省 - 交付说明借用关系:说明"参考了
NNN-slug的哪些方面、按你的数据改了哪些",让用户知道哪些结果是临摹、哪些是适配决策
B4 交付与进化
- 交付时注明:复用了
NNN-slug、做了哪些适配假设 - 按反馈进化条目(用户对这张图画法本身的反馈——无论是想改还是提了更好的做法):回到图库条目落实,而不是只改一次性代码:
- 画法级反馈(图例位置、标签密度、配色体系、阈值/字号/尺寸缺省……)→ 直接改
template.R/template.py的缺省值,同步更新该条目「配方」「复用要点」,重跑双模板自检,并在 figure.md 的「演化记录」追加一行:日期 + 反馈 + 改了什么 - 数据级反馈("这批数据阈值要用 2")→ 不动模板缺省,写进「复用要点」的变体或坑
- 跨条目通用的习惯 → 同时写
library/PREFERENCES.md(见下条);改完条目后重建索引
- 画法级反馈(图例位置、标签密度、配色体系、阈值/字号/尺寸缺省……)→ 直接改
- 写回偏好(跨图习惯,"图库越长越像你"的另一机制):凡观察到合法偏好信号——用户明确的适配选择("阈值用 1.5")、对成图的反馈("图例放上面")、主动声明的习惯("以后都要 PDF")——按
references/preference-profile.md追加进library/PREFERENCES.md(先记单次观察,≥2 次一致晋升稳定偏好)。只记可观察信号,禁止脑补;没有信号就不写 - 未命中:按普通流程从头设计这张图(不要硬套相近条目),正常交付。交付后若用户表示满意,主动提议:「要不要把这次的画法入库?」→ 走模式 A 沉淀(source.type=manual,ref 记本次任务描述;manual 条目的 reference.png 存交付的成图,没有原文献图)。这是图库进化的主要入口之一
跨设备导出/导入
典型场景:在个人电脑读文献学图,在服务器上跑分析时用。条目以单文件 bundle(zip,内含清单与逐文件 sha256)迁移;技能只管打包与解包,传输用 scp / rsync 等任意手段。
导出(在学会条目的设备上):
python3 <技能目录>/scripts/export_figure.py 003 # 数字前缀或完整 id,可多个,可用 all
python3 <技能目录>/scripts/export_figure.py 004 --with-related # 连同 related 互指的条目一起打包
# --with-preferences 附带 PREFERENCES.md;template_output_* 验证产物默认不入包
导入(在目标设备上):
python3 <技能目录>/scripts/import_figure.py bundle.zip --list # 先预览包内容
python3 <技能目录>/scripts/import_figure.py bundle.zip # 校验完整性后导入,自动重建索引
冲突策略(目标已有同 id 条目):内容一致 → 跳过;内容不同 → 默认拒绝并提示,加 --force 覆盖,或 --rename 分配新编号(自动改写 frontmatter 的 id 与同批条目间的 related 互指)。非交互环境遇冲突跳过该项、继续导入其余条目。--dry-run 只走校验与判定不写盘。
导入后两件事:
- 体检:目标环境可能与学图时的机器不同(缺 R 包等),跑
python3 <技能目录>/scripts/verify_library.py把各模板复制到临时目录试运行;它只出报告不改图库,失败的条目按其报告处理(补依赖重跑,或更新 figure.md 的 verified 与「模板自检记录」) - 偏好档案:包内若带 PREFERENCES.md 而目标已有同名文件,脚本不覆盖——散文式合并由 agent 对比两份文件手工完成
维护
scripts/init_library.py [--path DIR]:初始化图库骨架(幂等);用--path指定非默认位置时自动写入~/.config/biofigure-self-evolve/config.jsonscripts/build_index.py [--library DIR]:扫描所有figures/*/figure.md,重建 INDEX.json + INDEX.md(无 PyYAML 也能跑),并告警缺字段、id 与目录名不一致、related 悬空、languages 与模板文件不符、reference.png 缺失或超 2MB;手动改过 figure.md 后运行scripts/build_index.py --check:只比对索引与记录是否一致(不一致退出码 1),不写文件;模式 B 检索前的快速新鲜度判定scripts/export_figure.py <id...>/scripts/import_figure.py <bundle.zip>:跨设备迁移条目,见「跨设备导出/导入」节scripts/verify_library.py:把各条目模板复制到临时目录试运行,只报告 pass / fail / skip,不改图库;条目导入新环境后跑一遍- 手动修改记录后必须重跑 build_index.py——figure.md 是唯一事实源,索引只是投影
- 跨设备:整库双向同步用私有 git 仓库或云盘(整个技能目录含 library/ 一起同步即可);按条目单向迁移用 export/import 脚本。不依赖 ZCode 或任何特定 agent 的特性
library/PREFERENCES.md是用户个人数据:公开分发图库时排除它(示例仓库的 .gitignore 已配置),私有同步仓库随库走- 新增条目编号取现有最大 NNN + 1;删除条目时连同目录一起删并重建索引,不要复用旧编号;删除后记得把其他条目
related里指向它的引用清掉(build_index.py 会对此告警)
参考文件
| 文件 | 何时读 |
|---|---|
references/figure-record.md |
模式 A 写记录前、模式 B 需要看字段含义时(必读) |
references/ingest-sources.md |
模式 A 第一步取图前(必读) |
references/chart-taxonomy.md |
模式 A 打标签、模式 B 检索匹配时 |
references/preference-profile.md |
模式 B 读写 PREFERENCES.md 前 |