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

如何调整facet_wrap面板内箱线图水平间距及单独偏移均值/中位数标签?

问题:ggplot2分面箱线图标签重叠与自定义位置调整

使用ggplot2绘制带facet_wrap的箱线图时,均值和中位数标签出现重叠,需完成以下调整:

  1. 针对4个场景(Female-No、Female-Yes、Male-No、Male-Yes)单独设置标签位置:
    • Female-No:均值标签4.9上移至均值线上方并右移,中位数标签4.1右移
    • Female-Yes:与Female-No设置相同
    • Male-No:中位数标签8.7右移至箱线图旁的中位数线侧,均值标签8.4下移至均值线下方并右移
    • Male-Yes:均值标签2.5下移至均值线下方并右移,中位数标签2.5水平右移
  2. 调整facet_wrap单个面板内箱线图的水平间距,避免标签重叠

解决方案

核心思路

  1. 增大箱线图水平间距:修改position_dodge的width参数拉开箱线图间距,同时缩小箱线图自身宽度,为标签预留空间。
  2. 自定义标签位置:在统计量数据框中添加水平/垂直偏移列,通过case_when为每个场景单独设置偏移量,实现标签精准定位。

完整代码

library(tidyverse)

datas <- structure(list(Pain = structure(c(2L, 1L, 1L, 1L, 2L, 2L, 1L,
2L, 2L, 2L, 1L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L, 2L, 1L, 2L, 1L,
1L, 1L, 2L, 2L, 1L, 1L, 2L, 1L, 1L, 1L, 2L, 2L, 2L, 1L, 1L, 1L,
1L, 1L, 1L, 2L, 2L, 1L, 1L, 1L, 1L, 2L, 2L, 1L, 2L, 2L, 1L, 1L,
1L, 1L, 2L), levels = c("No", "Yes"), class = "factor"), Sex = structure(c(1L,
1L, 2L, 1L, 1L, 1L, 2L, 1L, 2L, 1L, 1L, 1L, 2L, 2L, 1L, 1L, 2L,
1L, 2L, 1L, 1L, 1L, 1L, 2L, 1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 2L, 2L, 1L, 1L, 2L, 1L, 1L), levels = c("Female", "Male"
), class = "factor"), `23` = c(3.7, 9.9, 18.1, 12.8, 2.3, 0,
8.7, 3.7, 1.5, 8.6, 5.7, 5.8, 2.1, 1.5, 6.1, 1.6, 0.6, 2.9, 9.1,
7.4, 0, 0, 9.5, 8.7, 4.6, 0, 0, 8.6, 1.6, 7.3, 6.3, 3, 7.8, 2.2,
0.7, 3.9, 2.8, 0.4, 6.2, 1.1, 2.3, 4.9, 4.5, 8, 8.6, 3.9, 1.5,
1.6, 0, 1.4, 3.2, 3.6, 3, 5.1, 4.1, 8.8, 9.6, 0.7)), row.names = c(NA,
-58L), class = c("tbl_df", "tbl", "data.frame"))

# 计算中位数并添加自定义位置偏移
medians <- datas %>%
  group_by(Pain, Sex) %>%
  summarise(m = round(median(`23`), 1), .groups = "drop") %>%
  mutate(
    x_offset = case_when(
      Sex == "Female" & Pain == "No" ~ 0.2,
      Sex == "Female" & Pain == "Yes" ~ 0.2,
      Sex == "Male" & Pain == "No" ~ 0.3,
      Sex == "Male" & Pain == "Yes" ~ 0.2,
      TRUE ~ 0
    ),
    y_offset = 0
  )

# 计算均值并添加自定义位置偏移
means <- datas %>%
  group_by(Pain, Sex) %>%
  summarise(m = round(mean(`23`), 1), .groups = "drop") %>%
  mutate(
    x_offset = case_when(
      Sex == "Female" & Pain == "No" ~ 0.2,
      Sex == "Female" & Pain == "Yes" ~ 0.2,
      Sex == "Male" & Pain == "No" ~ 0.3,
      Sex == "Male" & Pain == "Yes" ~ 0.2,
      TRUE ~ 0
    ),
    y_offset = case_when(
      Sex == "Female" & Pain == "No" ~ 0.8,
      Sex == "Female" & Pain == "Yes" ~ 0.8,
      Sex == "Male" & Pain == "No" ~ -1.0,
      Sex == "Male" & Pain == "Yes" ~ -0.6,
      TRUE ~ 0
    )
  )

# 绘制调整后的箱线图
datas %>%
  select(Pain, Sex, `23`) %>%
  ggplot(aes(y = `23`, x = Sex, fill = Pain)) +
  geom_boxplot(fatten = 1, outlier.alpha = 0.50, 
               position = position_dodge(width = 1.8),
               width = 0.7) +
  geom_text(data = medians, 
            aes(x = as.numeric(Sex) + x_offset, y = m + y_offset, label = m), 
            color = 'blue', size = 5) +
  geom_text(data = means, 
            aes(x = as.numeric(Sex) + x_offset, y = m + y_offset, label = m), 
            color = 'red', size = 5) +
  stat_boxplot(geom ='errorbar', position = position_dodge(width = 1.8)) +
  stat_summary(aes(ymax = ..y.., ymin = ..y.., color = 'Mean'),
               fun = mean, geom = 'errorbar', width = .75, linetype = 'solid', 
               position = position_dodge(width = 1.8)) +
  stat_summary(aes(ymax = ..y.., ymin = ..y.., color = 'Median'),
               fun = median, geom = 'errorbar', width = .75, linetype = 'solid', 
               position = position_dodge(width = 1.8)) +
  scale_colour_manual('Values', values = c(Median = 'blue', Mean = 'red')) +
  scale_fill_manual(values = c('lightblue', 'lightgreen')) +
  theme(legend.position = 'top',
        text = element_text(size = 12),
        strip.text = element_text(size = 11, face = "bold"),
        legend.text = element_text(size = 12),
        axis.text.x = element_text(size = 16, vjust = 1),
        panel.spacing.x = unit(2, "lines")) +
  facet_wrap(vars(Sex), scales = 'free')

代码说明

  1. 替换plyr为dplyr:避免包函数冲突,采用tidyverse风格的分组统计。
  2. 自定义偏移量:通过x_offset和y_offset为每个场景的标签设置专属位置,解决重叠问题。
  3. 调整箱线图布局:增大position_dodge(width)到1.8,缩小箱线图宽度到0.7,提升面板内空间利用率。
  4. 标签定位逻辑:将因子型x轴转换为数值后叠加偏移量,实现标签的精准移动。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 14:30:05