很多人第一次用 enrichGO(ont = "ALL") 画 barplot 时,会遇到一个小尴尬:你想看 BP/CC/MF 各自最显著的条目,但默认的 “TopN” 往往会被某一个本体占满,另外两个本体几乎看不到。

下面用两个很短的例子,把这个问题一次说清楚:
第一步用 split = "ONTOLOGY" 做到“每个本体各取 TopN”;第二步用 enrichplot::autofacet() 把 BP/CC/MF 自动分面排好。

准备数据:做一个 GO(ALL)富集结果

这里用 DOSE 自带的 geneList 凑一个演示用的基因集合,重点不在生物学含义,而在画图技巧。

library(DOSE)
data(geneList, package = "DOSE")
de <- names(geneList)[1:300]
 
library(clusterProfiler)
library(org.Hs.eg.db)
ego_all <- enrichGO(
  gene = de,
  OrgDb = org.Hs.eg.db,
  keyType = "ENTREZID",
  ont = "ALL",
  readable = TRUE
)

Example 1:不分面,但按本体分别取 TopN

关键点是这一句:split = "ONTOLOGY"
它不是简单的“把条形图按本体上色”,而是会在内部做分组筛选:BP/CC/MF 各自选 showCategory 个条目,避免全局 TopN 把图“挤偏”。

library(enrichplot)
library(ggplot2)
 
p_nofacet <- barplot(
  ego_all,
  x = "Count",
  showCategory = 15,
  split = "ONTOLOGY"
) +
  aes(fill = ONTOLOGY) +
  scale_fill_brewer(palette = "Set2")
 
p_nofacet +
  geom_text(aes(label = Count), nudge_x = 2) +
  scale_y_discrete()

上面还顺手做了两件常见的小优化:

  1. geom_text(aes(label = Count), nudge_x = 2):把 Count 直接标在条形旁边,读图更快。
  2. scale_y_discrete():用于覆盖 barplot() 默认的 y 轴标签格式化行为。

y轴的label,默认是被label_format = 30 是控制的,它主要做的是自动换行:超过一定长度就拆成多行;但其实你也可以传一个函数,想对label干啥的函数传进去是支持的。

如果你希望不换行、或者按你自己的方式控制 y 轴标签,你也可以直接加 + scale_y_discrete() 就能把默认处理覆盖掉。

Example 2:加上 autofacet,让 BP/CC/MF 自动分面

split = "ONTOLOGY" 生成的数据里包含 ONTOLOGY 这一列时,你可以直接加一行:

+ enrichplot::autofacet(by = "row", scales = "free")

它会按 ONTOLOGY 自动把图拆成三块面板(通常是 BP/CC/MF),并且因为 scales = "free",每个面板会按自己的条目数量和标签长度去排版,不会互相“拖累”。

p_facet <- barplot(
  ego_all,
  x = "Count",
  showCategory = 15,
  split = "ONTOLOGY"
) +
  aes(fill = ONTOLOGY) +
  scale_fill_brewer(palette = "Set2") +
  enrichplot::autofacet(by = "row", scales = "free")
 
p_facet + scale_y_discrete()

小结:这套写法什么时候最有用?

如果你的 GO 富集结果来自 ont = "ALL",并且你希望:

  • BP/CC/MF 各自展示一组 Top terms(而不是被全局 TopN “一锅端”)
  • 一张图里看清三个本体,但又不想手动写 facet_grid()/facet_wrap()
  • 长标签如何显示(换行/不换行)想自己掌控

那就记住三件事:

  • split = "ONTOLOGY" 负责“按本体分别取 TopN”;
  • autofacet() 负责“自动分面”;
  • scale_y_discrete() 负责“接管 y 轴标签的格式化”。