niuneat的个人博客分享 http://blog.sciencenet.cn/u/niuneat

博文

[转载]如何在一张图里同时说清楚‘时间趋势’和‘组间差异’?

已有 79 次阅读 2026-7-13 14:07 |系统分类:科普集锦|文章来源:转载

0封面.png

科研绘图不仅要展示真实严谨的数据,更要讲究排版的美观与可读性。

今天小编来分享一个兼具美感和实用性的R包——vbracket,它打破常规,将组间差异的统计学显著性括号直接集成到了图例的垂直结构中,助你的文章插图提升到顶刊发表级的水准。

一、 什么是 vbracket?

vbracket 是专门为 ggplot2 开发的一个高度定制化的图例增强包。

它的核心设计理念是:既然图例已经垂直排列了各个分组的名称和颜色,为什么不直接在图例的分组之间拉起垂直括号,来展示它们的两两差异呢?

传统做法 vs vbracket 做法
  • 传统做法在绘图区上方拉横向括号。缺点是横向跨度大、挤占 Y 轴高度、多组比较时线条极易交叉。

  • vbracket 做法在图例文字右侧拉垂直括号(如下图所示)。图面干净,且完美支持多重比较。

1.png

(注:图例右侧的垂直括号展示了 WT/Dox vs CH3+5 等组间的显著性差异)

vbracket 高阶美化调整图例
  • line_length:图例中彩色指示线(Legend Line)或色块的物理长度。

  • line_width:图例彩色指示线或括号线条的粗细。

  • item_spacing:图例中不同组别(即每一行文字)之间的垂直间距。

2.png

vbracket 官方示例效果展示

控制括号与图例标签的水平间距
  • bracket_layer_spacing:可以自由定义紧凑型(Tight Spacing,如 0.04)或宽敞型(Wide Spacing,如 0.12)。这确保了无论有多少层统计 brackets,图例右侧的统计标记都能清晰可读、规整有序,避免了遮挡或过于稀疏导致的视觉松散。

3.png

vbracket 官方示例效果展示

二、 实战演练:从安装到出图

下面我们以代谢物数据差异分析为例,展示如何快速上手 vbracket。

第一步:安装包

目前该包托管在 GitHub,可以通过 devtools 快速安装:

# 如果未安装 devtools,请先执行 install.packages("devtools")devtools::install_github("h20gg702/vbracket")

第二步:准备数据

研究问题:益生菌干预前后,短链脂肪酸(SCFAs)的变化是否不同于安慰剂组?

这里的重点不是简单比较 0d 或 56d 某一个时间点两组有没有差异,而是两组从干预前到干预后的“变化幅度”是否显著不同

每个受试者先计算:Δ = 56d 相对丰度 - 0d 相对丰度然后比较:Probiotic 组 Δ vs Placebo 组 Δ

第三步:读入短链脂肪酸矩阵和配对元数据

suppressPackageStartupMessages({ library(ggplot2) library(vbracket)})metab_file <- file.path(base_dir,"scfa_metabolomics_filtered_by_subject_id_freq_gt1_samples.csv")meta_file <- file.path(base_dir,"filtered_metainfo_subject_id_freq_gt1_rows.csv")metab <- read.csv(metab_file, check.names =FALSE, stringsAsFactors =FALSE)meta <- read.csv(meta_file, check.names =FALSE, stringsAsFactors =FALSE)meta$ghname <- trimws(as.character(meta$ghname))meta$subject_id <- trimws(as.character(meta$subject_id))meta$time_point <- trimws(as.character(meta$time_point))meta$day <- ifelse(meta$time_point =="0d",0, ifelse(meta$time_point =="56d",56,NA_real_))meta$Group <- ifelse(meta$`研究分组` =="安慰剂干预","Placebo", ifelse(meta$`研究分组` =="益生菌干预","Probiotic", as.character(meta$`研究分组`)))meta$Group <- factor(meta$Group, levels = c("Placebo","Probiotic"))sample_cols <- setdiff(colnames(metab),"Metabolite")sample_cols <- sample_cols[sample_cols %in% meta$ghname]long_list <- lapply(seq_len(nrow(metab)),function(i){ data.frame( Metabolite = metab$Metabolite[i], ghname = sample_cols, intensity = as.numeric(metab[i, sample_cols]), stringsAsFactors =FALSE, check.names =FALSE)})long <- do.call(rbind, long_list)plot_df <- merge( long, meta[, c("ghname","subject_id","研究分组","Group","time_point","day")], by ="ghname", all.x =TRUE)

到这里,我们就得到了适合 ggplot2 绘图和统计分析的长格式数据。

第四步:计算“干预前后变化量”并生成显著性标记

一部分人的做法是直接在 0d 和 56d 分别比较两组,这样回答的是:

某个时间点,两组是否不同?

但如果你的问题是“干预前后变化是否不同”,更合适的做法是先在每个受试者内部计算变化量:

Δ56d-0d = intensity_56d - intensity_0d

脚本中使用 reshape() 将同一个 subject_id 的 0d 和 56d 拉成一行,然后计算 Δ:

wide <- reshape( sub[, c("Metabolite","subject_id","Group","day","intensity")], idvar = c("Metabolite","subject_id","Group"), timevar ="day", direction ="wide")wide$delta_56d_minus_0d <- wide$intensity.56- wide$intensity.0wide <- wide[!is.na(wide$delta_56d_minus_0d),]

随后,对每个代谢物分别比较两组的变化量:

delta_placebo <- wide$delta_56d_minus_0d[wide$Group =="Placebo"]delta_probiotic <- wide$delta_56d_minus_0d[wide$Group =="Probiotic"]pval <- t.test(delta_placebo, delta_probiotic)$p.value

也就是说,这里的统计检验是:

Placebo 组的 Δ56d-0d vs Probiotic 组的 Δ56d-0d

将 p 值转换成常见的显著性标记:

p_to_star <-function(p){if(is.na(p)) return("NA")if(p <0.001) return("***")if(p <0.01) return("**")if(p <0.05) return("*")"ns"}

最终,每个短链脂肪酸都会得到一个变化量比较结果,例如:

Δ56d-0d: nsΔ56d-0d: *

这个标签不是某个时间点的横向差异,而是干预前后变化幅度的组间差异

第五步:绘制均值折线图,并用vbracket展示显著性结果

绘图部分保持经典的论文风格:

  • 横轴:0d 和 56d

  • 纵轴:Relative Abundance

  • 两条线:Placebo 与 Probiotic

  • 点:组均值

  • 误差线:Mean ± SEM

  • 主题:theme_classic()

  • 显著性:不再堆在图上,而是放进 vbracket 图例里

首先定义颜色:

colors <- c("Placebo"="#00AA00","Probiotic"="#FF4400")groups <- c("Placebo","Probiotic")

然后把变化量检验得到的显著性结果写进 vbracket 的比较结构中:

vb_label <- paste0("Δ56d-0d: ", stat_m$significance)comparisons <- add_bracket_comparisons( groups1 ="Placebo", groups2 ="Probiotic", labels = vb_label)

最后绘图:

p <- ggplot(sum_m, aes(x = day, y = mean, color = Group, group = Group))+ geom_line(linewidth =1.2)+ geom_point(size =3)+ geom_errorbar(aes(ymin = mean - sem, ymax = mean + sem), width =4, linewidth =0.8)+ scale_color_manual(values = colors)+ scale_x_continuous( breaks = c(0,56), limits = c(-3,59), labels = c("0d","56d"))+ labs( title = met, x ="Time point", y ="Relative Abundance")+ theme_classic(base_size =14)+ theme( plot.title = element_text(hjust =0.5, size =16, face ="bold"), legend.position ="none")+ legend_bracket( labels = groups, colors = colors, comparisons = comparisons, position ="topleft", output_width =6, output_height =4, width =0.36, text_size =9, sig_size =8)ggsave(file_png, p, width =6, height =4, dpi =300)

4.png

从图中可以直观看出,尽管起点不同,但益生菌干预显著促进了丙酸的产生

三、 贴心避坑指南

为了让大家在排版时少走弯路,在使用 vbracket 时有以下两点需要特别注意:

  • 绝对尺寸对齐

由于图例中文字宽度、括号间距的计算是基于物理绝对单位(如毫米或英寸)进行的,因此在 legend_bracket() 中设置的 output_width 和 output_height,必须与你最终用 ggsave() 保存时的宽高完全一致!否则,导出的 PDF 或 PNG 中括号和文字可能会发生错位。

  • 图例顺序对齐

在编写 legend_bracket(labels = ...) 时,填写的组名顺序要与你在 add_bracket_comparisons() 里使用的组名完全一致,且顺序应符合逻辑(通常是从上到下对应的实验组顺序)。

四、 总结

vbracket 包非常适合处理多时间点折线图+显著性标记。如果你也有类似的场景,一起用起来吧!

  • 项目开源地址:https://github.com/h20gg702/vbracket

  • 推荐指数:⭐⭐⭐⭐⭐

本文转自:谷禾健康



https://blog.sciencenet.cn/blog-2040048-1543421.html

上一篇:[转载]川崎病:肠道菌群扰动下,被点燃的儿童免疫性血管炎
下一篇:[转载]儿童发育迟缓,不只是“吃得少”:营养、肠道菌群与生长的复杂关系



    
收藏 IP: 125.120.149.*| 热度|

0

该博文允许注册用户评论 请点击登录 评论 (0 个评论)

数据加载中...

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2026-7-15 07:55

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部