主题
图表清单与解读
跑完流水线会出 11 类图(每张都是 600 dpi PNG + 矢量 PDF 双份)。 这一页讲:每张图在哪、怎么读、能下什么结论、以及哪些坑不能踩。 数字列表见 结果怎么看,方法原理见 从零读懂 MR。
一、图在哪:一张总表
| 图 | 文件 | 出自 |
|---|---|---|
| 火山图(分面) | results/screen_<rel>/figures/volcano_all | 12_figure_screen.R |
| 效应热图 | results/screen_<rel>/figures/effect_heatmap | 12_figure_screen.R |
| UpSet 重叠图 | results/screen_<rel>/figures/upset | 02_visualize.R |
| 共享蛋白森林图 | results/screen_<rel>/figures/forest_shared | 02_visualize.R |
| 蛋白-疾病网络 | results/screen_<rel>/figures/network | 02_visualize.R |
| 整合靶点网络 | results/network_<rel>/network_integrated | 06_network.R |
| 区域共定位图 | results/hyprcoloc_<rel>/figures/locus_<蛋白> | 13_figure_locus.R |
| PheWAS 多效性负担 | results/phewas/figures/phewas_burden_<rel> | 14_figure_downstream.R |
| PheWAS top 性状 | results/phewas/figures/phewas_top_traits_<rel> | 14_figure_downstream.R |
| LDSC 遗传相关热图 / 遗传力 | results/ldsc<_rel>/figures/ldsc_rg_heatmap、ldsc_h2 | 14_figure_downstream.R |
| 单细胞 UMAP / feature / 富集热图 | results/singlecell/figures/ | 15_figure_singlecell.py |
为什么每张图都出两份
PNG 600 dpi 给你看和投稿初审;PDF 是矢量的,投稿要改字号、改配色、拼版,用 Illustrator 打开 PDF 改,不会糊。 统一由 analysis/_viz_common.R 的 save_both() 落盘,所有图配色一致(风险红 #d73027 / 保护蓝 #4575b4)。
作图规范(字体与语言统一口径)
全课题所有结果图(MR 流水线 / 多组学 / 单细胞 / 靶点验证 / deCODE 平台复制)统一以下口径,保证跨模块一致、达发表标准:
| 维度 | 现行统一口径 | 说明 |
|---|---|---|
| 语言 | 全英文(标题、坐标轴、图例、注释) | 符合高分 SCI;中文只出现在 docs/PPT 的正文与图注文字框,不进图片内部 |
| 字体 | DejaVu Sans | R 的 theme_minimal 默认 sans = DejaVu Sans;matplotlib 默认字体也是它 → R 图与 Python 图像素级统一 |
| 主题 | theme_minimal(base_size=12)(R)/ 等价的白底浅网格(matplotlib) | 中心助手 analysis/_viz_common.R::save_both() |
| 输出 | PNG(≥200 dpi 看/初审)+ 矢量 PDF(投稿改版)双份 | PDF 文字可编辑,Illustrator 拼版不糊 |
| 配色 | 风险红 #d73027 / 保护蓝 #4575b4(语义色) | 全套一致 |
关于 Arial(当前不改,留待终稿)
顶刊作图规范多点名 Arial / Helvetica,但 DejaVu Sans 是完全合规的开源无衬线体、现阶段(汇报/预印本)足够。决定:现在统一保持 DejaVu Sans,不换。 若终稿投稿阶段需要,再做一次专门的字体统一 pass——届时优先用 Arimo(开源、与 Arial 度量/外观几乎一致、嵌 PDF 无授权顾虑),从中心助手 _viz_common.R + matplotlib rcParams 两处统一切换,并只重绘、不重算。
二、火山图:一眼看完整个筛查
volcano_all 按结局分面,横轴 log₂(OR),纵轴 −log₁₀(P)。
怎么读
- 越靠上 = 越显著;越靠两边 = 效应越强
- 红点=风险(OR>1),蓝点=保护(OR<1),灰点=没过 FDR<0.05
- 只有过了 FDR 的点才标基因名(每个结局最多标 8 个)
能下什么结论
- 某个结局整体"有没有信号":AMD 那几个面板点云高高拱起,NeovascGlaucoma 一片扁平(病例才 1576,功效不足)——扁平不等于没关系,可能只是样本不够
- 复合体基因扎堆(CFH/CFB/CFHR2/CFHR5/CFI)同时冒头 = AMD 补体通路的经典信号,说明流水线没跑歪
三、效应热图:跨结局比较同一个蛋白
effect_heatmap,行=蛋白,列=结局,填充 log₂(OR),* 标 FDR<0.05。
怎么读
- 整行都红/都蓝 = 这个蛋白在多个病里方向一致(如 AGER 一片蓝=跨并发症保护)
- 一行里红蓝都有 = 方向不一致,要警惕是不是多效性位点
色标是截断的
色标按 |log₂(OR)| 的 98 分位截断(图注里写了具体数值)。不截断的话少数极端值会把其余格子全压成白色。看颜色深浅只能比大小顺序,不能当精确读数——精确值查 table_S_significant_associations.csv。
四、区域共定位图(最该看的一张)
locus_<蛋白>:上面一条轨道是血浆 pQTL,下面每条是一个疾病,横轴是同一个 ±500 kb 窗口。
怎么读
- 各条轨道的峰对齐在同一个位置 → 支持"同一个因果变异同时影响蛋白和疾病"
- 红色虚线 + 红菱形 = HyPrColoc 判定的候选因果变异,它在每条轨道上的实际取值都被高亮出来
- 峰错开 → 很可能只是 LD 巧合,MR 的关联不可信
实例
locus_APOE(R13):pQTL、AMD、DryAMD、Retinopathy、WetAMD 五条轨道齐刷刷在同一点冒峰,PP=0.956——这是最漂亮的一张locus_TGFB1:pQTL 峰很高(−log₁₀P 到 180),三个 AMD 亚型的峰都在同一位置但矮得多(4–6),PP=0.760——信号真,但疾病侧证据弱
点的颜色 = LD r²(2026-07-20 起)
按 LocusZoom 惯例,点按与候选因果变异的 r² 分档着色(1000 Genomes EUR 面板):
| 颜色 | r² |
|---|---|
| 🔴 红 | 0.8–1.0 |
| 🟠 橙 | 0.6–0.8 |
| 🟢 绿 | 0.4–0.6 |
| 🔵 浅蓝 | 0.2–0.4 |
| 🔷 深蓝 | <0.2 |
| ⬜ 灰 | unknown(面板里没有这个变异) |
红点扎堆在主导变异附近 = 这一簇强连锁的变异共同支撑信号,正常且是好现象。
灰点是"不知道",不是"r² 低"
每张图的 r² 覆盖率不同(本课题实测 34%–46%,个别位点 0%),图注里逐张写明了具体百分比。 覆盖不满的原因:r² 只能对有 rsID 且在 1000G 面板里的变异算,而 UKB-PPP 的区域文件 ID 列是 7:27916:T:C:imp:v1 这种格式、不带 rsID,只能靠 FinnGen 的 rsids 列建 位置→rsID 映射反查;两边都覆盖到的才有颜色。 深蓝(<0.2) 和 灰(unknown) 是完全不同的含义,别混。
面板是 hg19,数据是 hg38 —— 必须按 rsID 匹配
1000G 面板实测是 GRCh37(rs429358 在 EUR.bim 里是 19:45411941,GRCh38 应为 19:44908684)。 本课题的 pQTL/GWAS 数据都是 GRCh38。所以代码里按 rsID 匹配、绝不按位置匹配——r² 是单倍型属性,与坐标系无关,这样做是对的;一旦改成按位置匹配,结果会全错。图注也写明了这一点。 个别位点(如 R9 的 CLPS,主导变异 rs71540127)在面板里不存在,整张图全灰,脚本会自动改写图注说明。
五、PheWAS 两张图:查多效性(安全性)
phewas_burden_<rel>:每个候选蛋白的工具变量,关联了多少个不相干性状(Bonferroni 显著)。数字越大,这个位点越"到处都显著",MR 结论越可能被多效性污染。APOE 是典型反面教材(几百个性状)。phewas_top_traits_<rel>:每个蛋白最强的 8 个关联性状,红=正向、蓝=负向。用来判断"它到底在管什么"。
两个必须注意的点
- P 值有下溢:源数据里很多 P 直接是 0(双精度下溢),图里统一按
1e-320画,图注写明了。别去解读那一档的高低。 - PheWAS 查的是 OpenGWAS 实时库,不可逐位复现。2026-07-16 查得 224 SNP/20688 关联,07-18 再查得 243/22473。投稿必须注明查询日期。
六、LDSC 两张图:疾病之间什么关系
ldsc_rg_heatmap:下三角遗传相关矩阵,格子里直接标数值。糖网↔肾病 rg 极高(同一套糖尿病微血管病变),AMD 与糖尿病并发症基本独立。ldsc_h2:各结局的 SNP 遗传力。
2026-07-20 起改用有效样本量,h² 已可跨结局比较
此前 munge 传的是总人数 ncase+ncontrol,而 LDSC 的 h² 随 N 缩放——本课题各结局 病例占比从 2.2% 到 19.7%,Neff/N 在 0.086–0.633 之间(相差 7.4 倍),等于每个性状 被一个各不相同的因子压低,跨结局比大小是没有意义的。
现已改为二分类的有效样本量 Neff = 4/(1/ncase + 1/ncontrol)。改后数值不再被病例占比牵着走: 病例占比最高的 Retinopathy(19.7%)h² 反而最低(0.051),T1D_wide(2.7%)最高(0.238) ——说明差异开始由性状本身而非抽样结构决定。新图可以跨结局比较(仍是观察尺度; 要与文献中的 liability-scale 数值对比,仍需按人群患病率转换)。
⚠️ 两条使用提醒:① 病例数少的结局(如 Maculopathy 4,766 例)LDSC 估计噪声大, 报告时必须带标准误,不能只给点估计;② rg 只是近似不受该改动影响——实测 AMD–WetAMD 0.925→0.931、WetAMD–DryAMD 0.851→0.865(最大变动 0.014,因为 LDSC 的 回归权重本身依赖 N),定性结论不变,但论文里的 rg 数值要用新表。详见 方法学审计。
rg 高不等于生物学同源——共享对照会把它抬上去
已用官方 FinnGen R13 manifest 核对:Retinopathy 与 Nephropathy 的对照数完全相同(62,519), 它们共用同一批对照;AMD / WetAMD / DryAMD 之间同样大量共用样本。所以这些高 rg 不能当作"疾病之间生物学同源"的独立证据,写作时须限定为"同一生物库、共享对照下的遗传相关"。
这两张图的真正用途:解释"为什么一个蛋白会在好几个病里同时显著"——遗传相关高的病本来就会一起显著。所以跨结局一致性只是支持性观察,不是验证支柱。
七、单细胞三张图:靶点在视网膜哪类细胞里
umap_celltypes:26.6 万细胞 / 18 个细胞类型的全景,图例带各类细胞数umap_features:每个候选基因的表达叠在 UMAP 上,标题给"表达细胞占比"enrichment_heatmap:基因 × 细胞类型,填充 AUC(该类 vs 其余,0.5=无差异),*= Mann-Whitney BH-FDR<0.05 且 AUC>0.5
读出来的结论
| 基因 | 定位 |
|---|---|
| SPRY2 | Müller 细胞 / astrocyte / RPE — 最像"在视网膜内起作用" |
| WARS1、NUDT5 | 神经节细胞(60–76% 细胞表达) |
| TGFB1、PILRA | 小胶质细胞 → 神经炎症线索 |
| CSF2、TNFRSF10A、IL7R、CLPS | 视网膜里几乎不表达 → 机制大概率是系统性/循环免疫,不在视网膜内 |
三条硬限制,写作时必须交代
- HRCA 全是正常视网膜(
disease列只有normal一个水平)→ 做不了 AMD vs 正常的差异表达,只能做表达定位。 - RPE 只有 1619 个细胞(0.6%)。低表达基因在这么少的细胞里本就测不到。"0% 表达"不等于"不表达"——富集热图把细胞数标在横轴上、图注写了"无星≠无表达",就是为了防止误读。
- 26 万细胞下 P 值必然极小,真正有解释力的是 AUC。别去比谁的 P 更小。
和 eQTL 的互相印证
CSF2 / TNFRSF10A 在单细胞里几乎不表达,同时在 Strunz 视网膜 eQTL 里不是 eGene、在公开 eQTL 里连区域数据都没有——两条独立证据指向同一结论。这也正是申请 METR-GT 的 RPE eQTL 的理由:正常视网膜单细胞 + RPE 采样稀少,看不清的部分需要 RPE 分离的深度 bulk eQTL 来补。
八、有意不做的图
| 图 | 为什么不做 |
|---|---|
| 漏斗图 / leave-one-out / MR-Egger | 每个蛋白只有 1 个 cis 工具变量,用的是 Wald ratio。异质性和多效性检验在数学上无从谈起,硬画出来是假图。验证靠共定位 + PheWAS/Steiger 两根支柱。 |
| 研究设计流程图 | 那是排版图不是数据图,用代码画又难看又难改。建议在 Illustrator / PPT 里画。 |
九、重跑与缓存
bash
cd ~/mr-pipeline
./run_pipeline.sh 12 # 只重出筛查层的图
./run_pipeline.sh 13 # 只重出区域共定位图LD 面板:/mnt/d/mrdata/ldpanel/EUR.{bed,bim,fam}(1000G EUR,GRCh37,1.1 G),plink1.9 由 apt 安装。面板缺失时脚本不会崩,会自动退回全灰并在图注说明。
区域共定位图第一次跑很慢(要解 tar + 扫 FinnGen 大文件,约 20 s/基因),之后区域数据缓存在 results/_region_cache/*.rds,再跑是秒出。想强制重新提取就删这个目录。
缓存文件名带版本号,改了读取逻辑必须升版
疾病区域缓存是 dis_<结局>_chr<N>_<pos>_500kb_v3.rds,末尾 _v3 是读取逻辑的版本。 一旦改动 _region_io.R 的提取方式(比如新增一列),必须把版本号 +1,否则会读到按旧格式存的缓存,静默给出错误结果。 旧版本缓存键名对不上、不会被读,确认无误后可以删:
bash
# 只删旧版疾病缓存;prot_*.rds 没有版本后缀、当前仍在用,不要动
find results/_region_cache -name 'dis_*kb.rds' ! -name '*_v3.rds' -delete别在脚本跑着的时候改它
Rscript 是边读边解析的。运行中覆盖 .R 文件会让它中途报 unexpected symbol 崩掉(本项目实际踩过:热替换 13_figure_locus.R 把正在跑的 R9 任务弄崩,只出了 3/5 张图)。改代码前先 pgrep -af Rscript 确认没在跑。