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

ggplot2:实现箱线图叠加散点居中对齐与线条正确连接

箱线图叠加散点与连线的优化方案

问题背景与示例代码

我正在制作一个叠加散点且用线条连接两组时间点的箱线图,示例数据及代码如下:

examiner <- rep(1:15, 2)
time <- rep(c("before", "after"), each = 15)
result <- c(1,3,2,3,2,1,2,4,3,2,3,2,1,3,3,3,4,4,5,3,4,3,2,2,3,4,3,4,4,3)
data <- data.frame(examiner, time, result)

ggplot(data, aes(time, result, fill=time)) + 
  geom_boxplot() +
  geom_point(aes(group = examiner), 
             position = position_jitter(width = 0.2, height = 0.03)) +
  geom_line(aes(group = examiner), 
             position = position_jitter(width = 0.2, height = 0.03), alpha = 0.3)

我有两个技术需求:

  1. 希望散点仅保留少量纵向抖动,增加横向抖动,且每个y轴刻度对应的散点对称分布在箱线图中心两侧(例如y=4、x="after"的6个点,3个在中心左侧、3个在右侧,距离对称),提升视觉美观度。
  2. 目前线条连接位置错误,已知使用position_dodge()可让点和线对齐,但我还需调整点的纵向位置,同时想了解为何position_dodge()能实现对齐而position_jitter()不行。

解决方案

需求1:实现散点对称分布

position_jitter的随机偏移无法实现对称分布,我们需要手动给每个相同time和result的点分配固定横向偏移。借助dplyr分组处理数据,即可实现对称布局:

library(dplyr)
library(ggplot2)

# 处理数据,添加对称偏移列
data_processed <- data %>%
  group_by(time, result) %>%
  mutate(
    # 给组内每个点编号
    idx = row_number(),
    # 奇数点左移、偶数点右移,偏移量可按需调整
    x_offset = ifelse(idx %% 2 == 1, -0.2, 0.2)
  ) %>%
  ungroup()

# 绘制图形:横向用固定偏移,纵向加少量抖动
ggplot(data_processed, aes(time, result, fill=time)) + 
  geom_boxplot(width = 0.6) +
  geom_point(aes(group = examiner), 
             position = position_nudge(x = data_processed$x_offset),
             position_jitter(height = 0.05)) +
  geom_line(aes(group = examiner), 
             position = position_nudge(x = data_processed$x_offset), alpha = 0.3)

如果某组点数为奇数(比如5个),可以让中间点居中,其余点对称分布:

data_processed <- data %>%
  group_by(time, result) %>%
  mutate(
    n = n(),
    idx = row_number(),
    x_offset = case_when(
      n %% 2 == 1 & idx == (n+1)/2 ~ 0,
      idx <= n/2 ~ -0.2 * ((n/2 - idx) + 1),
      TRUE ~ 0.2 * ((idx - n/2))
    )
  ) %>%
  ungroup()

需求2:连线对齐与原理说明

为什么position_jitter会错位?

position_jitter是对单个点生成独立随机偏移,同一个examiner的before和after点会得到完全不同的偏移值,导致连线无法对应到同一个个体,自然错位。

为什么position_dodge能对齐?

position_dodge是根据group参数(这里是examiner)给同一组的所有点分配固定横向偏移,同一个examiner的前后时间点偏移量完全一致,因此线条能精准连接对应个体的数据。

同时实现对齐与纵向抖动

如果需要兼顾连线对齐和纵向抖动,使用position_jitterdodge即可,它结合了dodge的组偏移逻辑和jitter的纵向随机抖动:

ggplot(data, aes(time, result, fill=time)) + 
  geom_boxplot(width = 0.6) +
  geom_point(aes(group = examiner), 
             position = position_jitterdodge(
               dodge.width = 0.6,  # 与箱线图宽度匹配,控制横向偏移幅度
               jitter.height = 0.05  # 纵向抖动幅度
             )) +
  geom_line(aes(group = examiner), 
             position = position_dodge(width = 0.6), alpha = 0.3)

线条无需抖动,用position_dodge保持和点的偏移一致即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 20:55:20