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

如何在ggplot2箱线图中用不同形状区分数据点且避免重叠

问题描述

我有一个存储为prescriptivism_scores.csv的数据集,结构如下:

Usage_GuideUsage_ProblemPrescriptivism_Index
Book 1who/whom2
Book 2who/whom2
Book 3who/whom2.5
Book 4who/whom4
Book 5who/whom2
Book 6who/whom1.5
Book 7who/whom3
Book 8who/whom2
Book 9who/whom4
Book 10who/whom4
Book 11who/whom2

我使用以下代码生成了一个无数据点重叠的箱线图:

library(ggplot2)

df <- read.csv(file = 'prescriptivism_scores.csv')
ggplot(df, aes(y = Prescriptivism_Index, x = Usage_Problem)) +
  geom_boxplot(color = "#838383") +
  
  geom_dotplot(binaxis = "y", stackdir = "center", dotsize = 0.5, color = "#00853E", fill = "#C4D600", stackratio = 1.5) +
 
  scale_x_discrete(name = "Usage Problem", 
                   breaks = c("different_to_than_from", "I_for_me", "lay_lie", "less_fewer", "none", "singular_they", "split_infinitive", "who_whom"),
                   labels = c("DIFF TO/THAN/FROM", "I FOR ME", "LAY/LIE", "LESS/FEWER", "NONE", "SG THEY", "SPLIT INF", "WHO/WHOM")) +
  
  ylab("Prescriptivism Index") +
  
  stat_summary(fun.y = mean, geom="point", shape=3, size=3, color="#EF4B81") +
 
  theme(panel.background = element_blank()) +
  
  geom_hline(yintercept = 1, linetype = "dashed", linewidth = 0.25, color = "darkgray") +
  geom_hline(yintercept = 2, linetype = "dashed", linewidth = 0.25, color = "darkgray") +
  geom_hline(yintercept = 3, linetype = "dashed", linewidth = 0.25, color = "darkgray") +
  geom_hline(yintercept = 4, linetype = "dashed", linewidth = 0.25, color = "darkgray")

我对该箱线图的整体效果满意,但希望每个数据点以不同形状对应数据集中Usage_Guide列的不同书籍,以便明确各数据点所属书籍。我尝试在ggplot的aes()中添加shape = Usage_Guide,但数据点未改变形状,且出现重叠,箱线图也显示异常;尝试颜色映射时,要么数据点重叠,要么箱线图消失。请问如何在保持原箱线图样式的前提下,实现用不同形状区分对应不同书籍的数据点?


解决方案

核心问题在于geom_dotplot本身不支持按分组(如Usage_Guide)设置不同形状,且直接在全局aes中添加shape=Usage_Guide会让箱线图也按书籍分组,导致样式异常。我们可以改用geom_jitter配合位置调整来替代geom_dotplot,既保留无重叠的布局,又能实现形状映射:

修改后的代码

library(ggplot2)

df <- read.csv(file = 'prescriptivism_scores.csv')
ggplot(df, aes(y = Prescriptivism_Index, x = Usage_Problem)) +
  # 保留原箱线图样式,避免分组影响
  geom_boxplot(color = "#838383", width = 0.6) +
  
  # 用geom_jitter替代dotplot,添加形状映射,控制位置避免重叠
  geom_jitter(aes(shape = Usage_Guide), 
              width = 0.2,  # 控制x方向分散程度,避免重叠
              size = 2,     # 点大小
              color = "#00853E", 
              fill = "#C4D600") +
  
  # 自定义形状映射,解决默认形状数量不足的问题
  scale_shape_manual(values = c(1,2,3,4,5,6,7,8,9,10,11)) +
  
  scale_x_discrete(name = "Usage Problem", 
                   breaks = c("different_to_than_from", "I_for_me", "lay_lie", "less_fewer", "none", "singular_they", "split_infinitive", "who_whom"),
                   labels = c("DIFF TO/THAN/FROM", "I FOR ME", "LAY/LIE", "LESS/FEWER", "NONE", "SG THEY", "SPLIT INF", "WHO/WHOM")) +
  
  ylab("Prescriptivism Index") +
  
  stat_summary(fun.y = mean, geom="point", shape=3, size=3, color="#EF4B81") +
 
  theme(panel.background = element_blank(),
        # 调整图例位置避免遮挡,可选
        legend.position = "right") +
  
  geom_hline(yintercept = 1, linetype = "dashed", linewidth = 0.25, color = "darkgray") +
  geom_hline(yintercept = 2, linetype = "dashed", linewidth = 0.25, color = "darkgray") +
  geom_hline(yintercept = 3, linetype = "dashed", linewidth = 0.25, color = "darkgray") +
  geom_hline(yintercept = 4, linetype = "dashed", linewidth = 0.25, color = "darkgray")

关键说明

  1. 替换geom_dotplot为geom_jitter:geom_dotplot基于分箱堆叠展示点,不支持分组形状映射;geom_jitter通过x轴方向的随机偏移避免点重叠,同时支持形状映射。
  2. 局部aes添加形状映射:在geom_jitter的aes中单独设置shape=Usage_Guide,不会影响箱线图的分组逻辑,保证原箱线图样式不变。
  3. 自定义形状值:由于书籍数量(11本)超过ggplot默认提供的形状数量(8个),用scale_shape_manual手动指定足够的形状值,避免重复。
  4. 调整width参数:控制x方向的偏移范围,确保同y值的点分散开不重叠,同时不会偏离对应箱线图的位置太远。

如果仍想保留类似geom_dotplot的堆叠效果,可以使用geom_point配合position_dodge或position_stack,但geom_jitter是实现无重叠+形状区分的最简便方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 15:55:20