引言Introduction

差异分析做完了,火山图却画不稳。常见问题有三个。阈值怎么定,显著基因怎么标,颜色和标签怎么处理。如果筛选标准不清晰,后续热图、富集分析和验证都会被带偏。
一张差异表达火山图示意图,标出上调、下调、无显著变化三个区域,并用虚线标注log2FC和p值阈值

1. 火山图是什么,为什么先看它

1.1 火山图的核心信息

火山图本质上是一个二维散点图。横轴通常是 log2 fold change ,表示表达倍数变化。纵轴通常是 -log10(p value) 或 ** -log10(adjusted p value)**,表示统计显著性。

图上的信息很直接。

  • 右侧高点 ,常代表上调且更显著。
  • 左侧高点 ,常代表下调且更显著。
  • 中间低点 ,多为变化不明显的基因。

火山图的价值,不只是“好看”。它是差异分析结果的第一道质量检查。 如果图形分布异常,比如大部分点都挤在一侧,往往提示归一化、分组或阈值设置需要重新检查。

1.2 为什么火山图要和差异分析绑定

火山图不是独立作图。它依赖差异分析结果。常见输入包括 DESeq2 的 log2FoldChangepadj,或 limma 的 logFCadj.P.Val

这意味着,火山图画得是否合理,取决于前面的统计模型是否合适。
比如:

  1. counts 数据优先考虑 DESeq2。
  2. 已标准化表达矩阵常用 limma。
  3. 多重检验校正后再看显著性,更符合科研规范。

如果只看原始 P 值,不做校正,显著基因数可能偏多。尤其在高通量数据里,这个问题很常见。

2. 阈值怎么选,才不会影响后续分析

2.1 常用阈值及其含义

火山图最常见的筛选标准是:

  • log2FC = ±1
  • p < 0.05 或 ** padj < 0.05**

这里的 log2FC = ±1 代表表达变化达到 2 倍。这个标准便于初筛,也便于多数文章统一比较。

阈值越严格,筛到的基因越少。
例如把阈值从 log2FC ≥ 1 提高到 log2FC ≥ 2,等于要求至少 4 倍变化。很多边缘显著基因会被排除。

这不是坏事,但要明确目的。

  • 想做探索性分析,可适当宽松。
  • 想做机制验证,可适当严格。
  • 想提高结果稳定性,建议同时看效应量和校正后 P 值。

2.2 阈值设置会如何影响下游分析

差异基因的选取会影响后续所有下游分析。 这是最容易被忽视的一点。

阈值太宽松时,问题是:

  • 假阳性增加。
  • 富集分析结果更“热闹”,但不一定更可靠。
  • 验证实验成本上升。

阈值太严格时,问题是:

  • 真正有生物学意义的基因可能被漏掉。
  • 热图和通路分析信息量减少。
  • 样本量较小时,结果可能过于稀疏。

因此,建议在文章或报告中明确写出筛选规则。最好同时说明:

  1. 使用的是 padj 还是原始 p value
  2. 设定的 log2FC 阈值是多少。
  3. 是否对低表达基因进行了预过滤。

基础不牢,后续分析徒劳。 这句话对火山图尤其适用。

3. 火山图R代码怎么写,最关键的是数据整理

3.1 DESeq2结果的基础处理

如果你已经得到差异分析结果,最常见的做法是先整理出方向变量,再绘图。下面是一个典型思路。

library(tidyverse)
library(ggplot2)
library(ggrepel)

logFC_cutoff <- 1

DEGs <- as.data.frame(res)
DEGs <- na.omit(DEGs)

DEGs$change <- ifelse(
  abs(DEGs$log2FoldChange) < logFC_cutoff | DEGs$padj >= 0.05,
  "Not",
  ifelse(DEGs$log2FoldChange >= logFC_cutoff, "Up", "Down")
)

DEGs$logP <- -log10(DEGs$padj)

这里有两个重点。

  • change 用来区分 Up、Down 和 Not。
  • logP 用来作为火山图纵轴。

建议先处理缺失值。 padj 中存在 NA 时,直接取对数会出问题。
如果你用的是原始 p value,也要确认是否存在 0 值。严格来说,0 不能直接取 -log10,需要先检查数值来源。

3.2 limma结果的写法

如果是 GEO 或标准化后的表达矩阵,常见是 limma 结果。

logFC_cutoff <- 1

DEGs0 <- as.data.frame(topTable(fit20, coef = contrasts0, n = Inf))
DEGs0 <- na.omit(DEGs0)

DEGs0$change <- ifelse(
  abs(DEGs0$logFC) < logFC_cutoff | DEGs0$adj.P.Val >= 0.05,
  "Not",
  ifelse(DEGs0$logFC >= logFC_cutoff, "Up", "Down")
)

DEGs0$logP <- -log10(DEGs0$adj.P.Val)

这里和 DESeq2 的区别很清楚。

  • DESeq2 常用 log2FoldChangepadj
  • limma 常用 logFCadj.P.Val

变量名不同,但逻辑完全一致。

4. 火山图R代码实战,如何标注重点基因

4.1 先筛 top 基因再标注

火山图上不建议标注所有显著基因。这样会非常拥挤。更稳妥的做法是挑选上下调各前几个基因。

DEGs_sig <- filter(DEGs, change != "Not")

DEGs_sig <- DEGs_sig[order(DEGs_sig$log2FoldChange, decreasing = TRUE), ]
DEGs_sig <- rbind(head(DEGs_sig, 5), tail(DEGs_sig, 5))

如果你用的是 limma,就把 log2FoldChange 换成 logFC

标注时,建议只保留最有代表性的基因。这样读者更容易抓住重点,也更符合论文图注的阅读习惯。

4.2 典型火山图绘制代码

下面是一个较完整的 ggplot2 示例。

ggplot(data = DEGs, aes(x = log2FoldChange, y = logP)) +
  geom_point(alpha = 0.4, size = 2.5, aes(color = change)) +
  scale_color_manual(values = c("Down" = "#4DBBD5", "Not" = "grey", "Up" = "#E64B35")) +
  geom_vline(xintercept = c(-logFC_cutoff, logFC_cutoff), linetype = 4, color = "black", linewidth = 0.6) +
  geom_hline(yintercept = -log10(0.05), linetype = 4, color = "black", linewidth = 0.6) +
  theme_bw() +
  ylab("-log10(padj)") +
  xlab("log2FoldChange") +
  geom_point(data = DEGs_sig, size = 3, shape = 1) +
  ggrepel::geom_label_repel(
    data = DEGs_sig,
    aes(label = rownames(DEGs_sig)),
    color = "black",
    size = 3
  )

这段代码里,最重要的是四件事。

  1. 颜色区分三类基因。
  2. 用竖线标出 fold change 阈值。
  3. 用横线标出显著性阈值。
  4. 用标签突出关键基因。

如果你想让图更适合投稿,可以进一步统一字体、调整图例位置、限制坐标范围。
如果点数很多,alpha = 0.3~0.5 会更清晰。

5. 火山图常见错误与修正思路

5.1 只看 p 值,不看 fold change

这是最常见的问题之一。某些基因因为样本量大,P 值很小,但表达变化很小。
如果只按显著性筛选,结果可能在统计上成立,但生物学意义有限。

更合理的方式是同时设置:

  • 显著性阈值。
  • 倍数变化阈值。

这也是火山图被广泛使用的原因。它能把“统计显著”和“变化幅度”放在同一张图里比较。

5.2 阈值过严导致点太少

如果图上几乎没有红点和蓝点,可能有三种情况:

  • 生物学差异确实不强。
  • 样本量不足。
  • 阈值设得过严。

这时不要急着“调图”。应该先回到差异分析本身,检查:

  1. 分组是否正确。
  2. 数据是否做过合理归一化。
  3. 是否对低表达基因做了过滤。
  4. padj 是否过于保守。

5.3 标签太多导致图面混乱

火山图不是“标得越多越好”。
标注的目标,是帮助读者快速识别核心基因,而不是把所有信息堆在一张图里。

建议优先标注:

  • 文献中已有报道的基因。
  • 变化幅度最大的基因。
  • 和课题机制直接相关的基因。

6. 从结果到应用,火山图真正解决什么问题

6.1 火山图适合哪些场景

火山图常用于以下场景:

  • 肿瘤组与正常组比较。
  • 干预前后表达变化比较。
  • 高低表达分组比较。
  • 药物处理前后筛选候选基因。

它的优势是直观。审稿人和读者通常能在几秒内判断结果是否合理。
但前提是阈值清晰,分组明确,数据处理规范。

6.2 结果展示之外,更重要的是后续验证

火山图只是起点。真正的工作还包括:

  1. 差异基因列表整理。
  2. GO、KEGG 或 GSEA 富集分析。
  3. 热图展示表达模式。
  4. qPCR、IHC 或功能实验验证。

如果火山图筛选逻辑不稳,后续验证会更难成立。
因此,绘图不是最后一步,而是分析链条中的关键一环。

最后,如果你希望把火山图、热图、差异分析和结果展示做得更规范,可以直接借助 解螺旋 的科研实操资源和数据分析支持,减少重复试错,把时间集中在真正有价值的机制验证上。

总结Conclusion

火山图看似简单,实则高度依赖前期差异分析质量。阈值选择、显著性校正、基因标注策略,都会直接影响结论。 规范做法是先确定分析方法,再统一阈值,再用简洁的 R 代码完成可视化。

如果你正在写论文、做汇报,或者想把差异分析结果整理得更专业,建议按照本文的逻辑重新检查一遍流程。也欢迎结合 解螺旋 的工具与课程,把火山图绘制、阈值选择和后续分析一次性做规范。

解螺旋科研助手企业微信二维码,扫码添加免费领取科研资料礼包,包含AI科研提效、SCI投稿技巧、国自然基金、医学科研绘图、科研软件工具等实用资料