geom_density_ridges脊线图高度未匹配数据:如何实现面板相对缩放?
问题解决:geom_density_ridges实现相对缩放而非独立面板缩放
问题描述
我有两个随时间反向变化的分布:foo1呈上升趋势,foo2呈下降趋势。但foo1的最大值仅为foo2最小值的一半。当前使用geom_density_ridges()的面板独立缩放效果极具误导性,会让人误以为两类foo的最大值相同。尝试使用geom_density_ridges(panel_scaling = FALSE)未触发报错但无效果,需要实现面板相对缩放以体现数据差异。
示例代码
fy_list = c(1986,1987,1988,1989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017) yrs1 = rep(fy_list, times=c(6,7,10,7,4,7,11,18,19,16,13,13,15,17,15,17,17,15,16,15,15,15,16,20,18,16,19,16,17,15,16,16)) foo1 = rep("foo1", times=457) df1 = data.frame(yrs1, foo1) yrs2 = rep(fy_list, times=c(67,62,58,63,64,57,54,49,44,46,49,48,45,47,45,43,41,40,37,38,36,35,33,32,33,32,30,32,30,34,33,33)) foo2 = rep("foo2", times=1390) df2 = data.frame(yrs2, foo2) df1 <- rename(df1, bin = foo1, yrs = yrs1) df2 <- rename(df2, bin = foo2, yrs = yrs2) df_test <- rbind(df1, df2) p <- ggplot(df_test, aes(x = yrs, y = bin)) + geom_density_ridges()+ labs(x = "fiscal year", y = "foo(test)")+ theme_minimal()
问题分析与解决方案
panel_scaling = FALSE 本身是控制面板缩放的参数,但它生效的前提是密度计算基于全局统计量。当前问题是因为geom_density_ridges默认按y轴分组(foo1/foo2)分别计算密度,导致各自密度被归一化到相同高度范围,所以该参数无效。
以下是两种可行的解决方法:
方案1:直接修改geom_density_ridges参数
通过指定scale = "count"让密度高度反映实际观测数量,同时保留panel_scaling = FALSE统一标尺:
p <- ggplot(df_test, aes(x = yrs, y = bin)) + geom_density_ridges( scale = "count", # 按实际计数缩放密度高度,而非归一化 panel_scaling = FALSE, rel_min_height = 0.01 ) + labs(x = "财年", y = "类别")+ theme_minimal()
方案2:预计算密度后绘制脊线
手动计算每个分组的计数密度,再用geom_ridgeline绘制,完全控制缩放逻辑:
library(dplyr) # 预计算基于计数的密度 df_density <- df_test %>% group_by(bin) %>% reframe( yrs = density(yrs, n = 100)$x, density = density(yrs, n = 100)$y * n() # 转换为计数密度 ) # 绘制脊线图 p <- ggplot(df_density, aes(x = yrs, y = bin, height = density)) + geom_ridgeline(fill = "#56B4E9", alpha = 0.7) + labs(x = "财年", y = "类别") + theme_minimal()
效果说明
两种方案都能让foo1的密度高度明显低于foo2,贴合“foo1最大值仅为foo2最小值一半”的实际数据,避免独立面板缩放带来的误导性视觉效果。
内容的提问来源于stack exchange,提问作者user237554
相关产品推荐
相关产品推荐

