如何在ggplot箱线图误差棒上限精准添加显著性字母
箱线图误差棒上限精准添加显著性字母问题
我尝试为箱线图的误差棒上限添加显著性字母,但字母位置无法精准对应上限。希望将字母精准放置在每个箱线图的误差棒上限处,同时保留图表其他元素不变。
原使用代码
#ANOVA提取显著性字母 mod <- aov(gas ~ Genotype, data = data) tu <- TukeyHSD(mod) group <- multcompLetters4(mod, tu) group_letter <- data.frame(group$`Genotype`$Letters) # 数据汇总并添加字母列 df = data %>% group_by(Genotype, Species) %>% summarize(MaxVal = max(gas), sd=sd(gas),mean=mean(gas), median= median(gas),se = sd(gas/sqrt(gas)), Q50 = quantile(gas, probs = 0.50), Q25 = quantile(gas, probs = 0.25), Q75 = quantile(gas, probs = 0.75), WhiskUp = (Q75 * (Q75 - Q25)),.groups = "keep") df$label <- group_letter$group.Genotype.Letters bp <- boxplot(gas ~ Genotype, data = data, plot = FALSE) bp data %>% transform(Genotype = factor(Genotype, levels = bp$names[order(-bp$stats[4,])])) %>% ggplot(aes(x=Genotype, y=Pn, fill=Species)) + stat_boxplot(geom = "errorbar") + scale_fill_manual(values=c('#e9002d', '#ffaa00', '#00b000')) + geom_boxplot(linetype = 3) + theme(axis.text.x = element_text(size = 10, colour = "black",vjust = 0.5, angle = 90))+ geom_text(data = df, aes(y = MaxVal-WhiskUp, label = label), fontface="italic", size=3.5, position = position_dodge(width = .75), angle=90, hjust=0.4, vjust=0.3)
数据集
Genotype Species gas BGB001 sp1 0.214 BGB001 sp1 0.216 BGB001 sp1 0.109 BGB001 sp1 0.097 BGB003 sp1 0.182 BGB003 sp1 0.270 BGB003 sp1 0.181 BGB003 sp1 0.282 BGB008 sp1 0.349 BGB008 sp1 0.206 BGB008 sp1 0.388 BGB008 sp1 0.157 BGB009 sp1 0.170 BGB009 sp1 0.179 BGB009 sp1 0.197 BGB009 sp1 0.164 BGB011 sp1 0.266 BGB011 sp1 0.198 BGB011 sp1 0.410 BGB011 sp1 0.352 BGB027 sp1 0.348 BGB027 sp1 0.344 BGB027 sp1 0.353 BGB027 sp1 0.350 BGB045 sp1 0.311 BGB045 sp1 0.211 BGB045 sp1 0.277 BGB045 sp1 0.340 BGB048 sp2 0.486 BGB048 sp2 0.504 BGB048 sp2 0.187 BGB048 sp2 0.205 BGB055 sp2 0.257 BGB055 sp2 0.273 BGB055 sp2 0.328 BGB055 sp2 0.342 BGB068 sp2 0.238 BGB068 sp2 0.121 BGB068 sp2 0.260 BGB068 sp2 0.133 BGB077 sp2 0.261 BGB077 sp2 0.203 BGB077 sp2 0.275 BGB077 sp2 0.219 BGB083 sp2 0.498 BGB083 sp2 0.485 BGB083 sp2 0.515 BGB083 sp2 0.499 BGB086 sp2 0.471 BGB086 sp2 0.183 BGB086 sp2 0.441 BGB086 sp2 0.134 BGB088 sp3 0.196 BGB088 sp3 0.178 BGB088 sp3 0.174 BGB088 sp3 0.229 BGB089 sp3 0.196 BGB089 sp3 0.448 BGB089 sp3 0.213 BGB089 sp3 0.484 BGB091 sp3 0.143 BGB091 sp3 0.187 BGB091 sp3 0.192 BGB091 sp3 0.155 BGB093 sp3 0.297 BGB093 sp3 0.314 BGB093 sp3 0.497 BGB093 sp3 0.519 BGB094 sp2 0.426 BGB094 sp2 0.335 BGB094 sp2 0.307 BGB094 sp2 0.221 BGB095 sp2 0.128 BGB095 sp2 0.099 BGB095 sp2 0.190 BGB095 sp2 0.186 BGB096 sp2 0.357 BGB096 sp2 0.274 BGB096 sp2 0.350 BGB096 sp2 0.539 BGB097 sp2 0.172 BGB097 sp2 0.174 BGB097 sp2 0.208 BGB097 sp2 0.459 BGB098 sp2 0.379 BGB098 sp2 0.380 BGB098 sp2 0.543 BGB098 sp2 0.557 BGB099 sp2 0.361 BGB099 sp2 0.354 BGB099 sp2 0.296 BGB099 sp2 0.289 BGB100 sp2 0.357 BGB100 sp2 0.529 BGB100 sp2 0.323 BGB100 sp2 0.503 BGB101 sp2 0.231 BGB101 sp2 0.235 BGB101 sp2 0.233 BGB101 sp2 0.236 BGB102 sp2 0.323 BGB102 sp2 0.402 BGB102 sp2 0.389 BGB102 sp2 0.501 BGB103 sp2 0.315 BGB103 sp2 0.314 BGB103 sp2 0.312 BGB103 sp2 0.311 BGB104 sp2 0.423 BGB104 sp2 0.323 BGB104 sp2 0.280 BGB104 sp2 0.160 BGB105 sp2 0.151 BGB105 sp2 0.137 BGB105 sp2 0.170 BGB105 sp2 0.092 BGB106 sp2 0.274 BGB106 sp2 0.279 BGB106 sp2 0.241 BGB106 sp2 0.246 BGB107 sp2 0.137 BGB107 sp2 0.145 BGB107 sp2 0.148 BGB107 sp2 0.133 BGB108 sp2 0.505 BGB108 sp2 0.526 BGB108 sp2 0.351 BGB108 sp2 0.380 BGB109 sp2 0.307 BGB109 sp2 0.283 BGB109 sp2 0.306 BGB109 sp2 0.283 BGB110 sp2 0.148 BGB110 sp2 0.186 BGB110 sp2 0.089 BGB110 sp2 0.318 BGB111 sp2 0.162 BGB111 sp2 0.185 BGB111 sp2 0.125 BGB111 sp2 0.138 BGB113 sp2 0.673 BGB113 sp2 0.780 BGB113 sp2 0.482 BGB113 sp2 0.666 BGB444 sp2 0.384 BGB444 sp2 0.222 BGB444 sp2 0.374 BGB444 sp2 0.190 BGB451 sp2 0.569 BGB451 sp2 0.562 BGB451 sp2 0.641 BGB451 sp2 0.635 BGB453 sp2 0.136 BGB453 sp2 0.159 BGB453 sp2 0.173 BGB453 sp2 0.194 BGB460 sp1 0.127 BGB460 sp1 0.246 BGB460 sp1 0.189 BGB460 sp1 0.314 BGB467 sp2 0.270 BGB467 sp2 0.274 BGB467 sp2 0.273 BGB467 sp2 0.270 BGB472 sp2 0.451 BGB472 sp2 0.634 BGB472 sp2 0.445 BGB472 sp2 0.600
解决方案
核心问题分析
- 上须计算错误:原代码中
WhiskUp = Q75*(Q75-Q25)不符合箱线图上须的定义(正确为Q75 + 1.5*(Q75-Q25)),导致字母位置偏离实际误差棒。 - 变量映射错误:ggplot中
aes(y=Pn)是笔误,应改为y=gas才能正确关联数据。 - 手动计算偏差:用
max(gas)和手动计算的上须值无法和ggplot自动生成的箱线图误差棒完全匹配。
修正后代码
library(tidyverse) library(multcompView) # 1. 提取显著性字母 mod <- aov(gas ~ Genotype, data = data) tu <- TukeyHSD(mod) group <- multcompLetters4(mod, tu) group_letter <- data.frame( Genotype = rownames(group$Genotype), label = group$Genotype$Letters ) # 2. 获取箱线图的精确上须值 bp <- boxplot(gas ~ Genotype, data = data, plot = FALSE) whisk_up_df <- data.frame( Genotype = bp$names, whisk_up = bp$stats[5,] # 直接取boxplot返回的上须值 ) # 3. 合并数据:基因型、物种、字母、上须值 df <- data %>% group_by(Genotype, Species) %>% summarize(.groups = "keep") %>% left_join(group_letter, by = "Genotype") %>% left_join(whisk_up_df, by = "Genotype") # 4. 绘制图表并添加字母 data %>% transform(Genotype = factor(Genotype, levels = bp$names[order(-bp$stats[4,])])) %>% ggplot(aes(x=Genotype, y=gas, fill=Species)) + stat_boxplot(geom = "errorbar") + scale_fill_manual(values=c('#e9002d', '#ffaa00', '#00b000')) + geom_boxplot(linetype = 3) + theme(axis.text.x = element_text(size = 10, colour = "black", vjust = 0.5, angle = 90)) + geom_text(data = df, aes(y = whisk_up, label = label), fontface="italic", size=3.5, position = position_dodge(width = .75), hjust = -0.1) # 调整hjust让字母位于误差棒外侧
关键改进点
- 直接使用
boxplot()返回的stats[5,]作为上须值,确保和ggplot绘制的误差棒完全对齐; - 通过
left_join整合所有必要数据,避免手动匹配出错; - 调整
geom_text的hjust参数,让字母刚好落在误差棒外侧,不遮挡图表元素; - 修正了原代码中的变量笔误和统计量计算错误。
内容的提问来源于stack exchange,提问作者Ikram Bashir
相关产品推荐
相关产品推荐

