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

ggplot2与ggdist多箱线图中跳过单观测值组分布绘制的方法

解决方案

你遇到的问题根源是ggdist::stat_halfeye默认调用的密度估计函数需要至少2个样本自动计算带宽,单样本分组触发的报错会中断所有分组的渲染。以下是两种可用的解决方法:

方法1:自定义安全密度函数(无需提前处理数据)

写一个自带样本量判断的密度估计函数,自动跳过样本量不足2的分组,直接传入stat_halfeye的density参数即可:

library(ggplot2)
library(ggdist)

# 自定义安全密度函数,样本量<2时返回空结果,不触发报错
safe_density <- function(x, ...) {
  if (length(x) < 2) {
    return(data.frame(
      x = numeric(0), y = numeric(0), 
      density = numeric(0), scaled = numeric(0), 
      n = integer(0)
    ))
  }
  # 样本量充足时调用默认的边界密度计算逻辑
  ggdist::density_bounded()(x, ...)
}

# 绘图时仅需修改stat_halfeye的参数,其余代码不变
iris2 <- iris[iris$Species != "setosa",]
iris2 <- rbind(iris2,iris[iris$Species == "setosa",][1,])

p2 <- ggplot(iris2, aes(x = Species, y = Sepal.Length)) + 
  ggdist::stat_halfeye(
    density = safe_density, # 传入自定义安全密度函数
    adjust = 1, 
    width = .4, 
    .width = 0, 
    justification = -.7, 
    point_colour = NA
  )+
  stat_boxplot(geom ='errorbar', width = 0.2) + 
  geom_boxplot(
    width = .4, 
    outlier.shape = NA
  ) +
  geom_point(
    size = 1,
    alpha = .3,
    position = position_jitter(seed = 1, width = .1)
  ) + 
  theme_bw() +
  scale_y_continuous(trans = "log10", labels = prettyNum) + 
  annotation_logticks(short=unit(0.15, "cm"), mid=unit(0.25, "cm"), long=unit(0.35,"cm"), sides="l", outside = TRUE) +
  coord_cartesian(clip="off")+
  theme(axis.text.x=element_text(margin = margin(t = 5)), 
        axis.text.y=element_text(margin = margin(r = 10)))+
  stat_summary(fun=mean, geom="line", aes(group=1), colour = "red")+
  stat_summary(fun=mean, geom="point", aes(group=1), colour = "red")

p2

该方法适配性强,不需要提前对数据集做过滤,适合分组较多、单样本组随机出现的场景。

方法2:提前过滤单样本分组(逻辑更直观)

如果不想自定义函数,可以单独为stat_halfeye过滤掉样本量不足2的分组,其余图层仍然使用全量数据即可:

library(dplyr)

# 提前过滤出样本量>=2的分组,仅供给stat_halfeye使用
halfeye_data <- iris2 %>%
  group_by(Species) %>%
  filter(n() >= 2) %>%
  ungroup()

# 绘图时单独给stat_halfeye传入过滤后的数据
p2 <- ggplot(iris2, aes(x = Species, y = Sepal.Length)) + 
  ggdist::stat_halfeye(
    data = halfeye_data, # 仅传入符合样本量要求的分组
    adjust = 1, 
    width = .4, 
    .width = 0, 
    justification = -.7, 
    point_colour = NA
  )+
  # 其余图层代码完全不变,仍使用全量iris2数据
  stat_boxplot(geom ='errorbar', width = 0.2) + 
  geom_boxplot(
    width = .4, 
    outlier.shape = NA
  ) +
  geom_point(
    size = 1,
    alpha = .3,
    position = position_jitter(seed = 1, width = .1)
  ) + 
  theme_bw() +
  scale_y_continuous(trans = "log10", labels = prettyNum) + 
  annotation_logticks(short=unit(0.15, "cm"), mid=unit(0.25, "cm"), long=unit(0.35,"cm"), sides="l", outside = TRUE) +
  coord_cartesian(clip="off")+
  theme(axis.text.x=element_text(margin = margin(t = 5)), 
        axis.text.y=element_text(margin = margin(r = 10)))+
  stat_summary(fun=mean, geom="line", aes(group=1), colour = "red")+
  stat_summary(fun=mean, geom="point", aes(group=1), colour = "red")

p2

两种方法运行后均不会触发警告,仅样本量充足的分组会渲染半眼图,单样本分组的箱线图、散点等其余元素都可以正常展示。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 22:09:03