使用stat_pvalue_manual给ggplot2手动加p值出错的技术问询
问题:在ggplot2双向交互图中添加emmeans显著性标记时出错
模拟数据集与模型拟合
set.seed(123) id <- rep(1:50, each = 3) condition <- rep(c("a", "b"), each = 1, times = 75) trial <- rep(c("1", "2", "3"), each = 1, times = 50) outcome <- rnorm(150, mean = 15, sd = 2.4) df <- data.frame(id, condition, trial, outcome) model <- aov(outcome ~ condition*trial, data = df) summary(model)
emmeans事后检验
emm_model <- emmeans(model, pairwise ~ trial | condition) summary(emm_model)
ggplot2交互图绘制
model_means <- df %>% dplyr::group_by(condition,trial) %>% get_summary_stats(outcome) gg_model <- ggplot(model_means, aes(x = condition, y = mean, fill = trial, color = trial)) + geom_bar(stat = "identity", position = "dodge", alpha = 0.5, size = 0.8) + scale_fill_manual(values = c("#190C3EFF","#9C2964FF", "#F8870EFF")) + scale_color_manual(values = c("#190C3EFF","#9C2964FF", "#F8870EFF")) + geom_errorbar(aes(ymin = mean - se, ymax = mean + se), width = 0.2, position = position_dodge(width = 0.9), size = 0.8) gg_model
尝试的两种显著性标记添加方法
方法一
model_posthoc <- df %>% dplyr::group_by(condition) %>% t_test(outcome ~ trial, p.adjust.method = "holm") model_posthoc <- model_posthoc %>% add_xy_position(x = "condition", dodge = 0.8) gg_model + stat_pvalue_manual(model_posthoc, label = "p.adj", tip.length = 0.01)
方法二
gg_model + stat_pvalue_manual(compare_means(data = df %>% dplyr::group_by(condition), outcome ~ trial, method = "t.test"), label = "p.adj", y.position = 15)
错误信息
Adding missing grouping variables: `condition`Error: ! Problem while computing aesthetics. ℹ Error occurred in the 3rd layer. Caused by error in `check_aesthetics()`: ! Aesthetics must be either length 1 or the same as the data (3) ✖ Fix the following mappings: `fill` Backtrace: 1. base (local) `<fn>`(x) 2. ggplot2:::print.ggplot(x) 4. ggplot2:::ggplot_build.ggplot(x) 5. ggplot2:::by_layer(...) 12. ggplot2 (local) f(l = layers[[i]], d = data[[i]]) 13. l$compute_aesthetics(d, plot) 14. ggplot2 (local) compute_aesthetics(..., self = self) 15. ggplot2:::check_aesthetics(evaled, n)
提问
请问在添加显著性值的过程中我遗漏了什么?
解决方案
错误原因
你遇到的核心问题是全局美学映射冲突:原ggplot的全局aes()中包含fill = trial和color = trial,但stat_pvalue_manual使用的数据集(不管是t_test结果还是emmeans结果)并没有trial列。ggplot会自动继承全局美学映射,尝试给显著性标记的每一行数据分配fill值,但数据集行数与trial的水平数不匹配,最终触发报错。
另外,你原本想使用emmeans的p值,但尝试的两种方法都用了t.test,这也不符合需求,需要先把emmeans的事后检验结果整理成适配stat_pvalue_manual的格式。
具体解决步骤
1. 整理emmeans的事后检验结果
从emmeans输出中提取比较组、校正p值等信息,并添加坐标位置(注意dodge值要和geom_bar的position_dodge保持一致):
library(emmeans) library(dplyr) library(stringr) library(ggpubr) # 提取emmeans两两比较结果,整理为ggpubr适配格式 emm_posthoc <- emm_model$contrasts %>% as.data.frame() %>% mutate( # 从contrast列拆分出对比的两个trial组 group1 = str_extract(contrast, "^\\w+"), group2 = str_extract(contrast, "\\w+$"), # 保留condition分组信息 group = condition, # 使用emmeans输出的校正p值 p.adj = p.value ) %>% # 添加坐标位置,dodge值与geom_bar的position_dodge一致(此处为0.9) add_xy_position(x = "condition", dodge = 0.9)
2. 修正ggplot美学映射(二选一即可)
方案A:移除全局fill/color映射,仅在目标图层设置
把fill和color的映射从全局ggplot()中移到geom_bar和geom_errorbar里,避免stat_pvalue_manual继承这些映射:
gg_model <- ggplot(model_means, aes(x = condition, y = mean)) + geom_bar(aes(fill = trial, color = trial), stat = "identity", position = "dodge", alpha = 0.5, size = 0.8) + scale_fill_manual(values = c("#190C3EFF","#9C2964FF", "#F8870EFF")) + scale_color_manual(values = c("#190C3EFF","#9C2964FF", "#F8870EFF")) + geom_errorbar(aes(ymin = mean - se, ymax = mean + se, color = trial), width = 0.2, position = position_dodge(width = 0.9), size = 0.8) # 添加显著性标记 gg_model + stat_pvalue_manual(emm_posthoc, label = "p.adj", tip.length = 0.01)
方案B:保留全局映射,禁用stat_pvalue_manual的继承
如果不想修改原ggplot代码,直接在stat_pvalue_manual中禁用全局美学映射继承:
gg_model + stat_pvalue_manual(emm_posthoc, label = "p.adj", tip.length = 0.01, inherit.aes = FALSE)
补充说明
- 若需要用
holm校正p值,调用emmeans时指定adjust = "holm":emm_model <- emmeans(model, pairwise ~ trial | condition, adjust = "holm") - 若要显示显著性星号(、、)而非原始p值,修改
label参数为"p.adj.signif":stat_pvalue_manual(emm_posthoc, label = "p.adj.signif", tip.length = 0.01, inherit.aes = FALSE)
内容的提问来源于stack exchange,提问作者becbot
相关产品推荐
相关产品推荐

