ggdist stat_slab使用coord_cartesian设置x轴上限时填充丢失问题求助
我尝试使用ggdist的stat_slab绘制brms模型的预测抽样结果,使用coord_cartesian放大坐标轴时遇到异常:调整x轴下限裁剪完全正常,比如把xlim下限从0调整到50时ggdist对象显示正常;但设置x轴上限时(例如从2000调整为1000),尾部超出x轴上限的stat_slab填充色会消失,看起来coord_cartesian对分布上侧的裁剪逻辑存在异常。
可复现问题的代码如下:
theme_set(theme_tidybayes() + panel_border()) set.seed(1) vars = data.frame(year = rep(c("before","after"), each = 1100), treatment = rep(c("low","high","low","high"), each = 550)) dat = data.frame(vars, .value = rgamma(nrow(vars), scale = 100, shape = 4)) ggplot(dat, aes(x = .value, y = treatment, group= year, fill=year, color = year)) + stat_slab(alpha=0.6, slab_color = "black") + #coord_cartesian(xlim = c(0, 2000)) + # 完整数据显示正常 #coord_cartesian(xlim = c(300, 2000)) + # 裁剪下限正常 #coord_cartesian(xlim = c(0, 1000)) + # 此时已有1个slab填充消失 coord_cartesian(xlim = c(0, 900)) -> reprex1 # 此时3个slab填充消失
我实际绘图时需要设置slab_color=NA,仅使用填充色结合自定义填充色阶展示结果,因此填充丢失的问题对我影响很大,目前没有找到解决方案。
补充说明
该问题还和R图形系统的绘图窗口大小有关,窗口或绘图区域越小,slab中保留填充的部分越多,不同尺寸的导出示例如下:
- 大尺寸导出代码:
reprex1 tiff(paste0(getwd(),"/reprex1.tiff"), res=600, compression="lzw", height = 9, width = 13, units = "in") print(reprex1) dev.off()
大尺寸导出时所有slab的填充都会消失。
- 小尺寸导出代码:
reprex1 tiff(paste0(getwd(),"/reprex1.tiff"), res=600, compression="lzw", height = 3, width = 5, units = "in") print(reprex1) dev.off()
小尺寸导出时已有2个slab可以保留填充。
环境信息
使用的环境为R 4.1.0 (2021-05-18)、ggdist 2.4.1、ggplot2 3.3.5,所有包均已更新到对应版本的最新版,在base R和RStudio中均能复现该问题。
需求说明
原始数据方差较大,slab的尾部非常长,直接展示很难观察年份和处理组的均值差异,因此必须对绘图进行放大以聚焦高密度区域。
原因
这个是ggdist 2.x版本的已知兼容性问题:stat_slab默认的密度估算和多边形绘制逻辑和ggplot2的坐标裁剪规则适配存在缺陷。当密度多边形的大部分顶点落在coord_cartesian设置的显示范围外时,R底层图形设备会判定填充区域无效,绘图尺寸越大,密度采样的顶点数量越多,越容易触发这个判定,因此大尺寸导出时填充会完全消失。
解决方案
优先方案:升级ggdist到3.0及以上版本
该版本已经官方修复了裁剪适配问题,升级后直接运行原有代码即可正常显示裁剪后的slab填充。无法升级包的临时修复方案
可以手动调整stat_slab的参数避免触发异常,两种可选参数设置:
- 关闭自动截断,指定密度绘制范围:
ggplot(dat, aes(x = .value, y = treatment, group= year, fill=year, color = year)) + stat_slab(alpha=0.6, slab_color = "black", trim = FALSE, cut = 0) + coord_cartesian(xlim = c(0, 900))
- 提前过滤超出显示范围的极端值,再绘图:
# 过滤掉不需要展示的上侧尾部数据 dat_filtered <- dat[dat$.value <= 900, ] ggplot(dat_filtered, aes(x = .value, y = treatment, group= year, fill=year, color = year)) + stat_slab(alpha=0.6, slab_color = "black") + coord_cartesian(xlim = c(0, 900))
内容的提问来源于stack exchange,提问作者MariaW

