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

如何在R的ggplot2图表中为差异显著的点添加*标记

高效添加多分组时间点vs基线的显著性标记方案

针对你40组(8种MIC×5种eGFR)的时间序列数据,手动加列的方式虽然可行,但用批量统计+ggplot映射的方式能大幅提升效率,以下是具体实现思路和代码:

核心思路

  1. 批量统计检验:用dplyr分组处理每个MIC-eGFR组合,完成ANOVA+Tukey事后检验,提取各时间点与基线对比的p值并转换为显著性标记(、、)。
  2. 自动映射标记:将统计结果与绘图数据合并后,用geom_text批量添加标记;或直接用ggsignif包的geom_signif在图中生成对比线和标记。

方案一:批量统计+geom_text映射(推荐)

1. 数据准备(模拟你的数据结构,替换为实际数据即可)

library(dplyr)
library(ggplot2)
library(emmeans)

# 模拟原始重复数据(ANOVA需要重复样本,你的实际数据应该包含这类原始值)
set.seed(123)
raw_df <- expand.grid(
  MIC = paste0("MIC", 1:8),
  eGFR = paste0("eGFR", 1:5),
  Time = c("Baseline", "Week2", "Week4", "Week8"),
  Rep = 1:5  # 每个时间点的重复样本
) %>%
  mutate(Value = rnorm(nrow(.), 50, 10))

# 计算各分组的中位数(用于绘图)
plot_df <- raw_df %>%
  group_by(MIC, eGFR, Time) %>%
  summarize(Median = median(Value), .groups = "drop")

2. 批量生成显著性结果

# 对每个MIC-eGFR组合做ANOVA+Tukey检验,提取基线对比的显著性标记
stat_results <- raw_df %>%
  group_by(MIC, eGFR) %>%
  do({
    # 拟合ANOVA模型
    aov_mod <- aov(Value ~ Time, data = .)
    # Tukey事后检验,对比所有时间点
    tukey_res <- emmeans(aov_mod, pairwise ~ Time, adjust = "tukey")
    # 筛选仅与Baseline对比的结果,转换为显著性标记
    baseline_comp <- tukey_res$contrasts %>%
      as.data.frame() %>%
      filter(grepl("Baseline", contrast)) %>%
      mutate(
        Time = gsub("-Baseline", "", contrast),
        sig = case_when(
          p.value < 0.001 ~ "***",
          p.value < 0.01 ~ "**",
          p.value < 0.05 ~ "*",
          TRUE ~ ""
        )
      ) %>%
      select(Time, sig)
    baseline_comp
  }) %>%
  ungroup()

# 合并绘图数据与显著性结果
plot_df <- plot_df %>%
  left_join(stat_results, by = c("MIC", "eGFR", "Time"))

3. 绘制带显著性标记的折线散点图

ggplot(plot_df, aes(x = Time, y = Median, group = interaction(MIC, eGFR))) +
  geom_line(color = "#2c3e50") +
  geom_point(size = 2, color = "#e74c3c") +
  # 分面展示40组数据,更清晰
  facet_grid(eGFR ~ MIC) +
  # 批量添加显著性标记,位置在中位数上方
  geom_text(aes(label = sig), vjust = -1.2, size = 4, na.rm = TRUE) +
  labs(x = "时间点", y = "中位数") +
  theme_bw() +
  theme(strip.text = element_text(size = 8))

方案二:用ggsignif直接添加对比标记

如果不想提前处理统计结果,可以用ggsignif包直接在图中生成时间点与基线的对比线和标记:

library(ggsignif)

ggplot(raw_df, aes(x = Time, y = Value)) +
  geom_line(aes(group = interaction(MIC, eGFR)), color = "#2c3e50") +
  geom_point(size = 2, color = "#e74c3c") +
  facet_grid(eGFR ~ MIC) +
  # 针对每个分面,添加所有时间点与Baseline的对比
  geom_signif(
    comparisons = lapply(setdiff(unique(raw_df$Time), "Baseline"), function(t) c("Baseline", t)),
    test = "anova",  # 指定用ANOVA+Tukey检验
    adjust = "tukey",
    map_signif_level = TRUE,
    y_position = max(raw_df$Value) + 6,  # 调整标记的垂直位置
    tip_length = 0.01
  ) +
  labs(x = "时间点", y = "数值") +
  theme_bw()

为什么stat_compare_means()会失败?

stat_compare_means()默认是对整个绘图数据的分组做检验,无法自动识别你需要的「每个MIC-eGFR组合下,各时间点与基线单独对比」的需求,必须先按分组批量处理统计结果,再映射到图中。

内容的提问来源于stack exchange,提问作者Carla

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 05:22:49