You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 16:37:53