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
相关产品推荐
相关产品推荐

