Skip to content

15 · 第 7 步 · 定稿与作图

日期:2026-08-08 起 · 2026-08-09 完成主体 状态:7.0–7.4 全完成 · 7.5 进行中

这一步在回答什么

前六步产出的是判定,这一步产出的是能投出去的东西:29 张成稿图、47 张发表版表格, 以及一套「让下次不再犯同样错」的断言。

本步最重要的一条经验

断言全绿 ≠ 图是对的。 本轮至少有 8 类错误是所有既有断言都查不出、 只能靠看图量产物发现的。每发现一类,就把它变成一条新断言 —— 第 7 步真正的产出,一半是图,一半是这些断言。


一、做了什么(7.0 → 7.5)

子步内容状态
7.1产物清理:删候选分级 tier、删 legacy_step4_survivor、发表版导出、ChEMBL 复核✅ 4/4
7.2补齐作图缺失的输入(实查 4 个不存在)✅ 4/4
7.3作图基础设施:画布白名单 / 字号 / 配色 / 图注 / 双层断言
7.4按 v4 流程步序作图F0→F1→F2→F-DM→F3→F4→F4X→F富→F5→F6→F711/11 步,29 张图
7.5图注四要素 · 全量审计 · docs 重写 · 本页实录🔶

二、作图标准(高分 SCI 口径,由断言强制)

取值怎么强制
画布宽度只允许 89 / 120 / 183 mmcheck_width() 传别的值直接 stop()
字号5–7 pt,按最终印刷尺寸出图,⛔ 不许先画大图再缩放assert_theme_sizes()(G2)+ size_pt()(G2b)
配色Okabe-Ito 八色,⛔ 禁 rainbow、禁红绿组合assert_palette()(G7)
字体DejaVu Sans,不换用户 2026-08-08 再次确认
格式PDF + TIFF(600 dpi LZW RGB) + PNG 一次出齐save_both()
图注不进图片,同代码生成 <图名>.caption.txtwrite_caption()(G6)

图放各自数据目录的 figures/ 下,文件名不带 F 前缀,图号只写在图注首行。

断言分两层

  • 出图前(R,analysis/_viz_common.R):G1 画布 · G2 字号 · G6 图注 · G7 配色 · G8 面板宽度 —— 都是 stop() 级,不合规根本出不来图
  • 出图后(Python,analysis/_fig_assert.py):G1 复核 · G3 内部 ID · G4 文字截断 · G5 字体 · G6 配对 · G9 TIFF 规格 · G10 体积 —— 这些只能在产物上查。

跑审计必须 sudo -u research

PIL 只装在 research 用户下。用默认用户跑,G9 会静默空转,报告照样印「全部通过 G9」。 已改成缺依赖硬报错,但用错用户仍然跑不了。

审计通过 ≠ 本次跑成功

脚本挂掉时磁盘上的旧 PDF 还在,审计照样全过。 2026-08-09 实测:7 个脚本因一处语法错全部 halted,审计仍打印「20 张全过」。 两件事必须分开看:跑批日志看「这次跑成没成」,审计看「产物合不合规」。


三、三条防「自己创方法」的约束

起因:F0a 遗传相关热图。同一份数据(两个仓库 cmp 逐字节相同),我画出来跟既有实现 面目全非,用户第一反应是「你是不是编数据了」。查下来数据一个没动, 但我做了三处未经批准、也无依据的改动,三条的「理由」都是我自己的审美。

#约束
已有实现即基线。任何差异逐条列出、经用户点头才生效。旧的 N 张、新的 N−1 张也算差异。
图上只许出现源文件里有的数。不许把 A 表的量搬进 B 表的位置。
跑前预期必须单列「与既有实现的差异 + 依据」。依据只认文献原文 / 规范原文 / 用户指示;⛔「我觉得更好」不算;⛔ 搜索摘要不算原文

★ 约束③ 是有实例的:我曾在注释里写「搜索摘要说 rg 热图通常对角线放 h²」, 去读原页并无此说,摘要是编的


四、29 张成稿图

目录图号
ldsc_R9_dm/figures/ldsc_genetic_correlation · ldsc_heritabilityF0a · F0c
platform_check/figures/input_acceptance_checksF0b
screen_R9_dm/figures/instrument_selection_funnel · mr_volcano_all_outcomes · mr_forest_complications · mr_effect_heatmap_complications · candidate_forest_by_complicationF1 · F2a · F2b · F2c · F7b-forest
diabetes_contrast/figures/diabetes_contrast_scatter_signed · diabetes_contrast_classesF-DM-a · F-DM-b
source_compare/figures/control_arm_source_sensitivityF-DM-c
reverse_mr/figures/reverse_mr_directionalityF3
external_replication/figures/external_replication_triage · epitope_pav_investigationF4 · F4X
enrichment/figures/enrichment_by_mhcF富
coloc/figures/colocalisation_tiers · colocalisation_upset · locus_{WARS,IFNAR1,NUDT5,APOE}F5a · F5b · F5c×4
crossomics_eqtl/figures/crosslayer_colocalisation · layer_coverageF6-0 · F6-0b
ontarget_phewas/figures/ontarget_benefit_risk · offtarget_phenotype_domainsF6-1 · F6-1b
druggability/figures/druggability_landscapeF6-2
candidate_summary/figures/wording_ladder · candidate_evidence_matrix · pipeline_overview_v4F7a · F7b · F7c

★ 全部 29 张通过 _fig_assert.py;16 个作图脚本一键重跑 tools/rerun_all_figures.sh0 失败

图必须体现该步的权限,而不只是展示数据

这是本轮定的总原则。v4 各步权限不同,图就得画得不一样:

  • 第 3 步 / 4X 步是否决点 → 画成否决(F3 三态、F4X 判定矩阵)
  • 第 4 步只分流 → 画成三分法,⛔ 不算复制率(算成功率就是把分流器说成筛子)
  • 第 5 步是措辞关卡 → 画成分档(F5a),并单出一张措辞阶梯(F7a)
  • 第 6 步只注释 → 11 个候选一个不少

五、★★ 八类「断言查不出、只能看图」的错

每一条后面都跟着它催生的新断言。

#为什么断言查不出新断言
1条形排序错(跨组重复标签只取首次出现的因子水平)数值全对水平加组名前缀 + nlevels == nrow
2旋转文字被 pdftotext 打散 → G4 假阴性文本层被拆成碎片
3base/grid 图(UpSetR)整个绕过 G2 字号检查 —— 没有 theme 对象,实测只有 3.7 ptG2 只遍历 theme 对象C7:同一个词在两张图里比宽度自标定
4geom_text(size=) 单位是 mm 不是 pt,实测 7 处 = 4.6–5.0 pt,低于下限却「全过」G2 查不到 geom 层size_pt() 换算 + 越界 stop()
5ggplot 对空水平只画图例标签、不画色块不是错误,是行为坐标为 NA 的 geom_point 占位层(drop=FALSE/limits=/geom_blank/override.aes 四种改法全无效
6白字画出了深色底框 → 白底白字,图上凭空少半句G4 只查裁切,查不到「有字但没对比度」G2c assert_text_fits()
7列表头之间横向碰撞(页边距内,不算裁切)G4 只看纸张边缘G2c 按实测列宽逐列比对
8文字竖向溢出灰框(框高写死,与行数无关)同上框高由行数算

G2c 自己也差点错:字体度量偏窄 7.9%

text_mm() 第一版在默认 pdf 设备下量宽度。该设备按 PostScript 字体库查 DejaVu Sans查不到就静默换替补字体 —— 实测同一句 5.6 pt: 默认设备 41.28 mm vs ragg 设备 44.55 mm偏窄 7.9%。 拿偏窄的度量做「放得下」断言,等于把关卡整体放宽 8%,边界情形照样溢出。 → 已改为在 ragg 设备下量,且缺 ragg 硬报错,不许退回默认设备。


六、★★ 本轮挖出的实质问题(不只是画图)

6.1 我自己写错的两处,都靠断言/看图挡下

  1. FinnGen R12:F7 三张图注被我凭记忆写成 R12,manifest 实为 R9finngen_R9_*.gzrelease == "R9_dm")。9 张既有图注都写 R9 —— 图注之间互相矛盾,而 G1–G10 一条都查不出来(它们不读图注语义)。 项目里同时存在 FinnGen R13(R13/AMD 线),靠记性写必错。 → 新增 G6b assert_release():版本从 manifest 现取,写错即 stop()
  2. 把「转化注释」塞进「因果证据」的配色(两次):no_tractable_modality 被上成 「方向相反」、共定位 medium 0.731 被标成「方向一致」。 → 成药性/脱靶两列不上色只印数;状态标签改通用支持度三档。

6.2 两处发表级错误

  • data_sources.csv 原本没有暴露侧 → STROBE-MR Item 19 不完整。已补 UKB-PPP 行(6→7 行)。
  • config.yamldata_availability 写「结局 FinnGen R13」 —— 投稿声明会直接抄它。已改 R9。

6.3 一颗活雷

23_figure_phewas_domain.R48_trait_domains.R 写同一个路径results/phewas/dataset_domains.csv,但内容不兼容(前者写 EFO 父类,后者写三分类, 而 49_ontarget_phewas.R 明写以 48_ 为准)。23_ 会静默打断 49_ —— 不报错,只是算出错的数。已把 23_.deprecated 并在头注写明。

6.4 既有实现三处已坏(都是这轮才发现)

  • 12_figure_screen.R 过不了 check_width(连带 16 个 save_both 调用点)
  • 33_figures_new.R 图 3 因组名改 ASCII 变空图,且组大小写错(标 31/20,实测 28/17
  • 33_figures_new.R 图 4 的输入 target_decision_table.csv 已废弃

七、图注:四要素与「诚实的缺席」

计划要求每张图注含数据来源 + 样本量 + 方法 + 阈值29 张逐张读完后实测缺口: 来源 7 / 样本量 16 / 方法 10 / 阈值 7。

两条筛查正则自身的坑,是读的时候才发现的

strong tier / weak tier 是英文正词,被当成已删除的内部列名 tier误报 3 张; ② n = 142(关联条数)被当成样本量 → 漏报若干原始告警不是发现 —— 这两条都是实证。

做法

  • caption_data_note()outcome_manifest.csv + config.yaml 现算「来源 + 样本量」, 由 write_caption() 统一追加;⛔ 不读 data_sources.csv(那是导出步骤的派生物,会形成循环依赖)。
  • FIG_OUTCOMES 让每个脚本声明它实际用到哪些结局 —— 成药性 / PheWAS / 覆盖账三类图 不附结局样本量,否则就是把不相干的数字写进图注。
  • G6c 四要素断言,缺一 stop()

★ 有的图本来就没有阈值 —— 定法是「显式声明」

F0c 是纯估计、F6-2 与 F6-0b 是纯注释,强加一个阈值就是编。 规定写成 No significance threshold applies to this figure.,该句被断言接受 —— 于是声明过的缺席忘写的缺席在断言层面分得开。 这与本项目「阴性 / 不可评估 / 未测三者必须分得开」是同一条原则。

★ 关键词表也会误判正当方法:F4X 的方法是「PAV 注释 + LD 计算」,一个估计量名都没有。 补 linkage disequilibrium|annotat 后仍是实打实的方法,不是放水。

★ 补进图注的口径全部从源码核实,不凭印象:REPL_P <- 0.05(名义,且方向一致即通过)、 R2_MIN <- 0.8(Zhao 2023 原文)、LD_DISTINCT <- 0.2自定,图注已声明是自定)。


八、全量审计(tools/audit_publication.py

「遍历所有 CSV」照字面做会大面积误报

实测 results/ 下 213 个中间产物里,20 个含内部 ID、9 个含中文 —— 那是设计如此, 内部产物本来就用内部键。真正必须干净的是给读者看的东西

范围 = results/publication/ + 各 figures/但中间产物的数字仍然打印为 INFO,让「收窄了范围」这件事看得见, 而不是悄悄缩小口径后宣布全过。

检查内容
P1发表表格无内部 ID(data_sources.csv 豁免 —— 它的职责就是给出「展示名 ↔ 内部 ID」对照)
P2无中文列名 / 取值
P3tier
P4图与图注一一配对
P5 / P6图注无内部 ID、无中文(★ 模式特意不含 tier,因为图注里它是英文正词)
P7_fig_assert.py

反向测试过:注入 tier 列 + 中文取值 → P1/P2/P3 同时报错、退出码 1、还原后逐字节相同。


九、遗留

  • 7.6 数字同步:中英文 Word 重建 · PPT 同步 · rsID 匹配统一成一个函数 · STROBE-MR 6d 声明 · 性染色体那条要定「如实分述 vs 补过滤重跑」
  • 7.7 代码发表包F:\project\r9-paper-code):等数字冻结后再做,现在做会白做两遍
  • ⬜ 写作层四条:NUDT5 的 0.982 vs 0.033 必须正面写 · 主推顺序 WARS 已超 NUDT5 · IFNAR1「已有上市药」不能笼统写 · WARS「无药」要区分「测了没有」与「库里没有」

个人科研与运维文档 · 内容持续修订