如何为ggplot绘制的肿瘤生长曲线添加P值标注括号
问题描述
我用ggplot绘制了肿瘤生长曲线,想要给图添加GraphPad Prism那样的P值标注括号。但目前找到的R函数(比如ggpubr::stat_compare_means、ggpubr::stat_pvalue_manual或ggprism::add_pvalue)都要求对比分组在x轴上,而我的肿瘤生长曲线x轴是时间,对比分组在图例中。希望实现自动添加P值括号的效果,不需要为每张图手动指定坐标。
附示例图:
- GraphPad Prism目标效果:

- 我用ggplot生成的图:

示例代码:
library(tidyverse) library(scales) tumorDataExample <- data.frame( Mouse = rep(1:15, times = 5), Condition = rep(c("A", "B", "C"), each = 5, times = 5), Day = rep(c(0, 8, 10, 11, 14), each = 15), Volume = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55.419392, 63.819999, 9.622816, 43.9999665, 34.792254, 5.470524, 23.516325, 49.9453705, 9.7540625, 16.9136, 13.1383, 36.872528, 18.108342, 48.700748, 13.197388, 86.979584, 76.9613405, 36.452668, 20.9408, 26.978522, 24.628864, 6.397264, 132.420195, 18.3314305, 11.1797745, 5.0688, 29.738592, 17.87125, 32.8653, 19.9408, 135.7811505, 99.900178, 60.76815, 25.6632, 33.519087, 25.1935245, 12.581856, 294.5889, 38.69775, 15.056676, 7.7533775, 21.625065, 19.62, 55.118336, 16.1063615, 200.485611, 162.4776305, 104.56355, 40.106664, 66.2195385, 16.143108, 4.2439, 886.51492, 17.37468, 15.867072, 7.791552, 11.3016465, 37.626644, 74.365425, 4.080501) ) tumorDataExampleSummary <- tumorDataExample %>% group_by(Day, Condition) %>% summarize(meanVolume = mean(Volume, na.rm = TRUE), se = sd(Volume) / sqrt(n())) tumorSizeExample_Summary <- ggplot() + geom_line(data = tumorDataExampleSummary, aes(x = Day, y = meanVolume, color = Condition)) + geom_errorbar(data = tumorDataExampleSummary, aes(x = Day, ymin = meanVolume - se, ymax = meanVolume + se, color = Condition), width = 0.1) + geom_point(data = tumorDataExampleSummary, aes(x = Day, y = meanVolume, color = Condition)) + scale_y_continuous(breaks = pretty_breaks(n=8)) + scale_x_continuous(breaks = pretty_breaks(n=3)) + labs(title = "Tumor Volumes Over Time", x = "Days After Tumor Injection", y = expression("Tumor Volume (mm"^3*")")) + theme_minimal() tumorSizeExample_Summary
解决方案
要实现时间轴上每个时间点的组间P值标注,核心思路是先按时间分组计算组间差异的P值,再把P值和对应位置映射到图上。以下是两种可行的实现方式:
方法1:用ggsignif自动生成标注
ggsignif的geom_signif支持按分组变量指定对比,结合自动计算的位置适配时间点。
library(tidyverse) library(scales) library(ggsignif) library(rstatix) # 1. 计算每个Day的组间两两P值 p_values <- tumorDataExample %>% group_by(Day) %>% pairwise_t_test(Volume ~ Condition, p.adjust.method = "bonferroni") %>% # 整理标注所需的位置信息 rowwise() %>% mutate( x = Day, xend = Day, # 自动计算每个时间点的标注起始y位置:最大均值+标准误的1.1倍 y = tumorDataExampleSummary %>% filter(Day == !!Day) %>% pull(meanVolume + se) %>% max() * 1.1 ) # 2. 绘制带P值标注的图 tumorSizeExample_Summary + geom_signif( data = p_values, aes(x = x, xend = xend, y = y, yend = y + 50, annotations = paste0("p = ", round(p.adj, 4))), manual = TRUE, tip_length = 0.01 )
方法2:用ggprism::add_pvalue结合自定义位置
如果习惯使用ggprism工具链,可以先整理P值表格,再自动适配每个时间点的坐标:
library(tidyverse) library(scales) library(ggprism) library(rstatix) # 1. 整理P值表格,包含位置信息 p_table <- tumorDataExample %>% group_by(Day) %>% pairwise_t_test(Volume ~ Condition, p.adjust.method = "bonferroni") %>% rowwise() %>% mutate( group1 = Condition1, group2 = Condition2, x = Day, # 对应时间点的x坐标 # 自动计算标注的y位置:最大均值+标准误的1.2倍 y = tumorDataExampleSummary %>% filter(Day == !!Day) %>% pull(meanVolume + se) %>% max() * 1.2 ) %>% select(x, y, group1, group2, p.adj) # 2. 添加P值标注 tumorSizeExample_Summary + add_pvalue( p_table, x = "x", y = "y", label = "p = {round(p.adj, 4)}", bracket.size = 0.8, step.increase = 0.1 # 同一时间点多个对比时自动错开标注位置 )
关键说明
- 代码中
y的位置基于每个时间点的最大均值+标准误乘以系数(如1.1、1.2),实现自动适配曲线高度,无需手动指定坐标;可根据图表需求调整系数或偏移量。 - 可根据数据类型替换统计方法(如
t.test换为wilcox.test),或调整P值校正方法。
内容的提问来源于stack exchange,提问作者Kevin Lenzi
相关产品推荐
相关产品推荐

