告别单调气泡图!用R语言ggplot2手把手绘制桑吉气泡图(附clusterProfiler数据处理代码)
用R语言打造高阶桑吉气泡图:从clusterProfiler数据到科研级可视化
在生物信息学分析中,KEGG和GO富集结果的可视化一直是展示研究发现的窗口。传统气泡图虽然能同时展示通路名称、富集倍数、p值和基因数四个维度,但关键的基因列表信息往往被压缩在表格中。桑吉气泡图(Sankey Dot Plot)的创新之处在于,它通过桑吉图的连线美学,将第五个维度——差异基因列表直观地整合到可视化中,形成信息密度与美学表现双赢的科研图表。
对于使用R语言的研究者而言,掌握这种复合图表的自定义绘制能力意味着:1) 摆脱在线工具的限制,实现完全可控的细节调整;2) 建立可重复的分析流程;3) 满足期刊对图表分辨率和格式的严苛要求。下面我们将从数据准备到图形美化,完整解析如何用ggplot2构建这种高级可视化方案。
1. 数据准备与清洗
1.1 从clusterProfiler提取五维数据
clusterProfiler的富集分析结果通常存储在enrichResult对象中,我们需要从中提取五个关键维度:
library(clusterProfiler) library(tidyverse) # 假设enrich_res是clusterProfiler的富集结果 enrich_data <- enrich_res@result %>% select(Description, GeneRatio, pvalue, geneID, Count) %>% mutate( GeneRatio = sapply(strsplit(GeneRatio, "/"), function(x) as.numeric(x[1])/as.numeric(x[2])), pvalue = -log10(pvalue), geneID = strsplit(geneID, "/") )关键处理步骤:
- GeneRatio转换:将"5/100"格式转换为数值0.05
- p值对数化:-log10转换使颜色梯度更具生物学意义
- 基因列表拆分:将geneID列转换为列表格式,便于后续展开
1.2 数据展开与桑吉图结构构建
桑吉图需要明确"源-目标"关系,这里源是基因,目标是通路:
sankey_data <- enrich_data %>% unnest(geneID) %>% select(source = geneID, target = Description, value = Count) %>% distinct()注意:实际绘制时需确保基因名称唯一性,对于多通路共享的基因,建议添加通路前缀或使用其他标识方法
2. 复合图表核心绘制技术
2.1 基础气泡图构建
使用ggplot2的图层叠加原理,先绘制标准气泡图:
base_plot <- ggplot(enrich_data, aes(x = GeneRatio, y = reorder(Description, GeneRatio))) + geom_point(aes(size = Count, color = pvalue), alpha = 0.8) + scale_size_continuous(range = c(3, 8), breaks = seq(5, 30, by = 5)) + scale_color_gradientn( colours = c("#4575b4", "#74add1", "#abd9e9", "#e0f3f8", "#fee090", "#fdae61", "#f46d43", "#d73027"), limits = c(1, 4), breaks = seq(1, 4, by = 0.5) ) + theme_minimal(base_size = 12) + labs(x = "Gene Ratio", y = "", color = "-log10(p-value)", size = "Gene Count")2.2 桑吉连线集成技术
通过geom_segment实现基因-通路的流向连接:
# 计算连线位置参数 link_data <- sankey_data %>% group_by(target) %>% mutate( yend = as.numeric(factor(target, levels = levels(factor(enrich_data$Description)))), xstart = 0, xend = min(enrich_data$GeneRatio) * 0.7 ) %>% ungroup() %>% mutate( y = as.numeric(factor(source, levels = unique(source))), group = paste0(source, "_", target) ) # 添加桑吉连线层 sankey_layer <- geom_segment( data = link_data, aes(x = xstart, xend = xend, y = y, yend = yend, group = group), color = "grey70", alpha = 0.4, linewidth = 0.3 )2.3 双坐标轴同步控制
通过coord_cartesian实现左右区域的完美拼接:
final_plot <- base_plot + sankey_layer + coord_cartesian(xlim = c(-max(enrich_data$GeneRatio)*0.5, max(enrich_data$GeneRatio)*1.1)) + theme( plot.margin = unit(c(1,1,1,3), "cm"), axis.text.y = element_text(hjust = 0.5) )3. 高级定制技巧
3.1 动态颜色映射策略
对于大型数据集,建议采用分位数离散化颜色标尺:
library(scales) color_breaks <- quantile(enrich_data$pvalue, probs = seq(0, 1, 0.1)) final_plot <- final_plot + scale_color_gradientn( colours = viridis_pal(option = "D")(10), values = rescale(color_breaks), breaks = color_breaks[c(2,4,6,8,10)] )3.2 智能避标签重叠算法
使用ggrepel自动处理密集标签:
library(ggrepel) final_plot <- final_plot + geom_text_repel( data = link_data %>% distinct(source, y), aes(x = -0.05, y = y, label = source), size = 2.5, direction = "y", hjust = 1, segment.size = 0.2, box.padding = 0.1, max.overlaps = 20 )3.3 响应式布局参数
根据数据特征动态调整图形比例:
dynamic_aspect <- length(unique(enrich_data$Description)) / 15 final_plot <- final_plot + theme(aspect.ratio = ifelse(dynamic_aspect > 1, 1, dynamic_aspect))4. 实战案例:阿尔茨海默症数据集应用
4.1 数据加载与预处理
以GSE1297数据集为例展示完整流程:
library(GEOquery) library(clusterProfiler) # 获取差异基因 gse <- getGEO("GSE1297", GSEMatrix = TRUE) exprs <- exprs(gse[[1]]) de_genes <- rownames(exprs)[which(exprs[, "AD"] > exprs[, "Control"])] # KEGG富集分析 kegg_res <- enrichKEGG( gene = de_genes, organism = "hsa", pvalueCutoff = 0.05, qvalueCutoff = 0.1 )4.2 关键参数调试经验
根据实际绘制效果调整的核心参数:
| 参数类别 | 推荐值范围 | 调整策略 |
|---|---|---|
| 点大小范围 | 3-10 | 根据通路数量线性调整 |
| 颜色渐变 | viridis/plasma | 色盲友好优先 |
| 连线透明度 | 0.3-0.6 | 基因密度越高值越小 |
| 标签字号 | 2.5-3.5 | 与输出分辨率匹配 |
4.3 期刊出版级输出设置
满足Cell Press等顶级期刊的要求:
ggsave( "sankey_dotplot.pdf", plot = final_plot, width = 12, height = 8, units = "in", dpi = 600, device = cairo_pdf )在绘制复杂生物通路时,建议先用小样本测试布局参数。例如神经退行性疾病相关通路往往基因数量多,需要特别调整连线透明度和标签间距。一个实用的技巧是先用geom_density_2d检查基因-通路的分布热点,再针对性优化可视化参数。
