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

如何在存在缺失分类数据时统一ggplot2箱线图宽度?

解决ggplot2箱线图因数据缺失导致宽度不一致的问题

背景与问题

我是R语言新手,这是首次独立完成分析。我的数据集记录了不同时空下各类牙釉质样品的d.13.C和d.18.O值,想用ggplot2展示不同Family在时空上的趋势。

我写出了如下可复现代码:

d %>%
  mutate(across(Member, factor, levels = c("UpperBurgi", "KBS", "Okote"))) %>%
  mutate(across(Dep_context, factor, levels = c("Lacustrine", "Deltaic", "Fluvial "))) %>% 
  ggplot(aes(x = Member, y = d.13.C)) + 
  geom_boxplot(aes(x = Member, y = d.13.C, col = Dep_context, fill = Dep_context), alpha = 0.5, lwd = 1) +
  facet_wrap(~Family) +
  scale_fill_brewer(palette = "Dark2") + 
  scale_color_brewer(palette = "Dark2") + 
  theme_bw() 

生成的图像如下:
生成的箱线图

由于数据分布不均(并非每个Family的每个地质Member都包含所有Dep_context),不同沉积环境的箱线图宽度不一致。我希望所有箱线图宽度统一(比如和Bovidae在KBS Member中的箱线图宽度一致)。

我试过在geom_boxplot中设置width参数、调整theme网格、使用drop=FALSE,但都没效果;也尝试过对Member和Dep_context分面,但视觉效果不佳且操作繁琐。想知道有没有方法实现统一宽度,还是只能选择分面?

数据集子集:

dput(head(d))
structure(list(CA = c("6", "1", "104", "105", "6A", "6A"), Member = c("KBS", 
"Okote", "KBS", "KBS", "KBS", "KBS"), Dep_context = c("Deltaic", 
"Fluvial ", "Fluvial ", "Fluvial ", "Deltaic", "Deltaic"), Family = c("Equidae", 
"Equidae", "Equidae", "Equidae", "Equidae", "Equidae"), Tribe = c("", 
"", "", "", "", ""), Genus = c("Equus", "Equus", "Equus", "Equus", 
"Equus", "Equus"), d.13.C = c(-0.3, -0.7, 0.7, -0.9, -0.1, -0.8
), d.18.O = c(0, 1.6, 4, 2.6, 1.8, 0.2), Age.range = c("1.87-1.56", 
"1.56-1.38", "1.87-1.56", "1.87-1.56", "1.87-1.56", "1.87-1.56"
)), row.names = c(NA, -6L), class = c("tbl_df", "tbl", "data.frame"
))

解决方案

核心是补全所有Family、Member、Dep_context的组合,让ggplot在绘制时保留所有可能的位置,从而实现箱线图宽度统一。用tidyr::complete()函数就能轻松实现:

修改后的完整代码

library(tidyverse)

d %>%
  # 先设置因子水平保证顺序正确
  mutate(across(Member, factor, levels = c("UpperBurgi", "KBS", "Okote"))) %>%
  mutate(across(Dep_context, factor, levels = c("Lacustrine", "Deltaic", "Fluvial "))) %>%
  # 补全三个变量的所有组合,缺失数据自动设为NA
  complete(Family, Member, Dep_context) %>%
  ggplot(aes(x = Member, y = d.13.C)) + 
  geom_boxplot(aes(col = Dep_context, fill = Dep_context), 
               alpha = 0.5, lwd = 1, width = 0.7) + # 可手动设置统一宽度
  facet_wrap(~Family) +
  scale_fill_brewer(palette = "Dark2") + 
  scale_color_brewer(palette = "Dark2") + 
  theme_bw() 

原理说明

complete()函数会生成Family、Member、Dep_context三个变量的所有笛卡尔积组合,没有对应数据的行中d.13.C会被设为NA。ggplot绘制箱线图时,会保留这些空位置,但不会绘制无效的箱线(因为NA无统计意义),同时同一Member下的所有Dep_context位置都被占满,箱线图的宽度就会自动统一,和你想要的Bovidae在KBS中的效果一致。

如果不想让空位置显示(比如完全隐藏没有数据的Dep_context标签),可以不用额外操作——ggplot不会在空位置绘制任何元素,只会保证现有箱线的宽度统一。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 02:35:26