添加Viridis配色后stat_slab柱状图消失的原因及解决方法
问题:添加fill映射后stat_slab柱状图消失的原因与修复
问题背景
使用ggdist、ggplot2和dplyr可视化有序数据,无配色的stat_slab代码可正常生成柱状图,但添加fill=factor(response)映射并使用Viridis配色后,柱状图消失。
数据结构示例
library(ggdist) library(ggplot2) library(dplyr) data(long_data) srss_question1 <- long_data %>% filter(type == "1") %>% dplyr::select(id, day, response) head(srss_question1) # A tibble: 6 × 3 id day response <dbl> <fct> <dbl> 1 1 day7 5 2 1 day2 4 3 1 day0 3 4 2 day7 5 5 2 day2 5 6 2 day0 6
正常运行的无配色代码
srss_question1 %>% ggplot(aes(y = response, x = day)) + stat_slab( data = filter(srss_question1, day == "day7"), density = "histogram", breaks = breaks_fixed(width = 0.5), align = "center", position = position_nudge(x = 0), side = "right" ) + stat_slab( data = filter(srss_question1, day == "day2"), density = "histogram", breaks = breaks_fixed(width = 0.5), align = "center", position = position_nudge(x = 0), side = "right" ) + stat_slab( data = filter(srss_question1, day == "day0"), density = "histogram", breaks = breaks_fixed(width = 0.5), align = "center", position = position_nudge(x = 0), side = "right", ) + geom_line( aes(group = id), size = 0.25, position = position_jitter(h = 0.05, w = 0.05), alpha = 0.25 ) + scale_y_continuous(limits = c(-0.25, 7.5), breaks = 0:10) + labs(x = "Day", y = "Question 1 Responses") + theme_bw()
添加fill映射后失效的代码
srss_question1 %>% ggplot(aes(x = day, y = response, fill = factor(response))) + stat_slab( data = filter(srss_question1, day == "day7"), density = "histogram", breaks = breaks_fixed(width = 0.5), align = "center", side = "right", position = position_nudge(x = 0) ) + stat_slab( data = filter(srss_question1, day == "day2"), density = "histogram", breaks = breaks_fixed(width = 0.5), align = "center", side = "right", position = position_nudge(x = 0) ) + stat_slab( data = filter(srss_question1, day == "day0"), density = "histogram", breaks = breaks_fixed(width = 0.5), align = "center", side = "right", position = position_nudge(x = 0) ) + geom_line( aes(group = id), linewidth = 0.25, position = position_jitter(h = 0.05, w = 0.05), alpha = 0.25 ) + scale_fill_viridis_d(option = "D", direction = 1) + scale_y_continuous(limits = c(-0.25, 7.5), breaks = 0:10) + labs(x = "Day", y = "Question 1 Responses") + theme_bw()
原因分析
- 分组冲突:全局映射
fill = factor(response)后,ggplot会自动按response对数据分组。而stat_slab在density = "histogram"模式下,会基于分组计算直方图,导致每个分组仅包含单个response值的记录,无法形成有高度的柱状条,最终表现为柱状图消失。 - 冗余代码加剧问题:重复调用三次
stat_slab分别处理不同day的逻辑,未覆盖全局分组映射,进一步导致每个day内的数据被拆分为多个极小分组,无法渲染出可见的柱状图。
修复方案
修复后代码
library(ggdist) library(ggplot2) library(dplyr) srss_question1 <- long_data %>% filter(type == "1") %>% select(id, day, response) srss_question1 %>% ggplot(aes(x = day, y = response)) + # 仅在stat_slab内部指定fill映射,并强制group=1避免按response分组 stat_slab( aes(fill = factor(response), group = 1), density = "histogram", breaks = breaks_fixed(width = 0.5), align = "center", side = "right", position = position_nudge(x = 0) ) + geom_line( aes(group = id), linewidth = 0.25, position = position_jitter(h = 0.05, w = 0.05), alpha = 0.25 ) + scale_fill_viridis_d(option = "D", direction = 1) + scale_y_continuous(limits = c(-0.25, 7.5), breaks = 0:10) + labs(x = "Day", y = "Question 1 Responses", fill = "Response") + theme_bw()
关键修复点
- 将fill映射移至stat_slab内部:避免全局fill映射影响其他图层(如
geom_line不需要fill),同时仅让直方图图层使用fill配色。 - 添加
group = 1:强制stat_slab按每个day的整体数据统计直方图,而非按response拆分分组,确保每个响应值的柱状条能显示对应的计数高度。 - 简化代码:移除重复的三次
stat_slab调用,利用ggplot的自动分组逻辑,基于x=day自动为每个day绘制直方图,代码更简洁易维护。
内容的提问来源于stack exchange,提问作者AKing
相关产品推荐
相关产品推荐

