气泡图的数据结构:三个核心指标

讲气泡图,很多人上来就看图。但我建议你先搞清楚图背后的数据长啥样。

说白了,气泡图上每一个泡泡背后都对应一行表格数据。这行数据至少有四个字段:基因数、P值、富集因子,还有通路名字。我刚开始做富集分析时,只看颜色和大小,结果有一次把富集因子算反了,画出来的图完全反直觉。嗯,从那以后我每次都先检查数据框的列名。

下面我拆开一个个讲。

基因数(Count)—— 泡泡的大小

基因数就是这个通路上真正匹配到你基因列表里的基因个数。比如你的输入基因有200个,KEGG的「细胞周期」通路里背景基因是300个,其中你输入列表里有25个,那Count就是25。

Count值越大,气泡直径越大。这里有个坑:

注意: 不同工具对气泡大小的映射方式不同。clusterProfiler 默认用 Count 映射 size,而某些在线工具会用 GeneRatio。碰上气泡图显得特别小,先看看纵坐标是不是比率。

P值(或调整后P值)—— 泡泡的颜色

P值代表富集结果的统计学显著性。你想想看,一个通路里偶然出现几个基因很正常,但出现太多就不太可能是巧合了。P值越小,颜色通常越红或越深。

我个人习惯用 调整后P值(p.adjust) 来做颜色映射。因为KEGG通路数不多(几百条),但如果你用ORA(Over-Representation Analysis),不做多重假设校正,P值很容易虚低。

小技巧: 如果你的气泡图颜色几乎全红或全蓝,差异不明显,试试把 p.adjust 取负对数(-log10),这样小P值会拉开差距,颜色渐变更清晰。

富集因子(Rich Factor)—— 泡泡的X/Y位置

富集因子定义多样,但最常见的一种是:
富集因子 = (输入基因中属于该通路的基因数)/ (该通路总背景基因数)
这个值范围在0到1之间,越接近1说明你输入基因对该通路的覆盖度越高。

注意:有些工具把 GeneRatio 当纵坐标,它和富集因子有点像,但分母不同:
GeneRatio = 输入基因中属于该通路的基因数 / 你的总输入基因数。

我曾经在对比几个工具结果时发现,同一个通路在clusterProfiler里Rich Factor=0.3,在DAVID里却显示0.15,差点以为算错了。后来才发现分母定义不一样。所以看气泡图前,一定先确认X轴/Y轴标签是什么。

一张表说清楚

字段 常用别名 取值范围 气泡图映射 典型问题
Count 基因数、GeneCount 正整数(通常≥2) 气泡大小 若通路Count=0会被过滤
Pvalue / p.adjust 显著性、FDR [0,1] 气泡颜色 未校正时易出现假阳
Rich Factor Enrichment Ratio [0,1] X或Y轴 定义需统一
GeneRatio 比例 [0,1] 常替代Rich Factor 分母不同,数值不同

从R数据框看数据结构

我们用clusterProfiler跑出来的结果,直接 head() 就能看到这些列。

# 假设你已经做了 enrichKEGG
library(clusterProfiler)
data(geneList, package="DOSE")
kegg_res <- enrichKEGG(gene = names(geneList)[1:100],
                       organism = 'hsa',
                       pvalueCutoff = 0.05)
head(kegg_res[, c("ID", "Description", "GeneRatio", "BgRatio", "pvalue", "p.adjust", "qvalue", "Count")])

输出大概长这样:

            ID        Description GeneRatio  BgRatio    pvalue  p.adjust  qvalue Count
hsa04110 hsa04110        Cell cycle    25/200 300/8000 3.45e-08 1.23e-05 1.01e-05    25
hsa03030 hsa03030 DNA replication    12/200 150/8000 1.22e-04 2.56e-03 2.34e-03    12
...

这里 GeneRatio 是"25/200"这样的字符串,表示25个输入基因中属于该通路;BgRatio 是背景比例。你画图时如果要计算Rich Factor,可以把两个Ratio相除,但更常见的做法是直接用 Count 和 p.adjust 加 GeneRatio。

我画气泡图时用到的R代码

下面是我常用的一个代码片段,直接基于clusterProfiler的结果画图,并手动调整映射变量。

library(ggplot2)
library(DOSE)

# 转换数据为数据框
df <- as.data.frame(kegg_res)
# 计算 GeneRatio 数值 (分子/分母)
df$GeneRatio_num <- sapply(strsplit(df$GeneRatio, "/"), function(x) as.numeric(x[1])/as.numeric(x[2]))
# 画气泡
ggplot(df, aes(x = GeneRatio_num, y = Description)) +
  geom_point(aes(size = Count, color = p.adjust)) +
  scale_color_gradient(low = "red", high = "blue") +
  theme_bw()

注意:我没有用 scale_size_continuous 限制大小范围,有时几个极端大通路会撑爆版面。你可以加 scale_size_area(max_size = 10) 让气泡面积与Count成正比。

避坑:富集因子到底怎么算

我曾经踩过的坑: 使用不同的KEGG富集工具(如clusterProfiler vs. WebGestalt vs. DAVID),它们给出的富集因子列名不同。clusterProfiler 不直接输出Rich Factor,它输出 GeneRatio 和 BgRatio。你需要用 RichFactor = (GeneRatio分子/BgRatio分子) 自己算,或者干脆用 GeneRatio 作为横轴。而WebGestalt会直接给出 Enrichment Ratio。所以当你看到别人文献里的气泡图横轴标着“Rich Factor”,一定要看方法部分他们用的哪个工具,不然你照着参数画会完全不一样。

气泡图数据结构总览

下面这张SVG图把整个映射关系串起来。你可以把它当成一个“数据结构→气泡图元素”的快速参考。

气泡图数据映射关系 气泡图数据映射关系 输入基因列表 (N个基因) + KEGG背景注释 富集分析计算 超几何检验 → Count → Pvalue → 校正 → p.adjust 富集结果表 Count, p.adjust, GeneRatio, BgRatio 可计算 Rich Factor 气泡大小 ← Count (越大基因越多) 气泡颜色 ← p.adjust (越红显著越强) 气泡位置 X: Rich Factor Y: 通路名 说明: 图中展示了从输入基因到KEGG通路富集,再到气泡图三个视觉元素的映射链条。 实际使用时,p.adjust 常取 -log10 变换后映射颜色,以使色差更明显。

常见错误与调优建议

  • 气泡过小或过大: 如果Count范围很大(比如从2到200),默认的scale_size可能会让最小的泡泡几乎看不见。可以设置 scale_size_area(max_size = 12) 或手动指定 limits。
  • 颜色映射失真: p.adjust 值通常集中在0.01~0.05之间,直接用连续色标可能会让大部分点颜色接近。我一般先取 -log10(p.adjust) 再映射,色带用 scale_color_gradientn(colors = c("blue", "yellow", "red")) 拉开中部。
  • X轴混淆: 一定确认横轴标签是 Rich Factor 还是 GeneRatio。如果横轴值都小于0.1但纵轴通路很多,很可能是用了 GeneRatio(因为分母是总输入基因数,而KEGG通路本身基因数都在几十到几百,比率会小)。

核心思路: 气泡图本质上是三维数据(大小、颜色、位置)映射到二维平面。你只要确保数据框里有 Count、p.adjust 和 RichFactor 这三列,就能随心所欲调整图形。不要被工具默认的美观参数带偏,先检查原始数据。