geom_ribbon绘制年龄占比:空白区域与额外凸起修复
问题描述
初始问题
我想要展示不同年龄组的占比随时间的变化趋势。目前已获取各年龄组的个体占比(pAGE),以及用于geom_ribbon绘图的各年龄组累积占比区间值(cpAgeMin和cpAgeMax)。尽管所有年龄组占比总和为1,但绘图中部分年份存在无数据的空白区域,这并非数据问题,而是ggplot的绘图问题。需要修复此问题,确保每年0-1区间都被某一年龄组完全覆盖。
示例数据及绘图代码
# 数据子集 df <- structure(list(site = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), levels = "G", class = "factor"), year = c(1988, 1988, 1989, 1989, 1989, 1990, 1990, 1991, 1991, 1991, 1992, 1992, 1992, 1993, 1993, 1993, 1998, 1998, 1998, 1999, 1999, 1999, 2000, 2000, 2000, 2001, 2001, 2001, 2002, 2002, 2003, 2003, 2003), age = c(`9104` = 1, `9341` = 2, `9292` = 1, `9632` = 2, `9960` = 4, `9543` = 1, `9857` = 3, `9685` = 1, `9968` = 2, `10169` = 3, `9858` = 1, `10127` = 2, `10212` = 3, `10009` = 1, `10284` = 2, `10522` = 6, `10464` = 1, `10605` = 2, `10830` = 3, `10556` = 1, `10744` = 2, `11056` = 3, `10687` = 1, `11061` = 2, `11279` = 5, `10912` = 1, `11109` = 2, `11197` = 3, `11065` = 1, `11194` = 2, `11154` = 1, `11255` = 2, `11324` = 3), pAGE = c(0.972, 0.028, 0.964, 0.005, 0.031, 0.823, 0.177, 0.921, 0.074, 0.004, 0.846, 0.045, 0.109, 0.833, 0.155, 0.012, 0.927, 0.054, 0.019, 0.784, 0.21, 0.005, 0.958, 0.017, 0.025, 0.852, 0.124, 0.024, 0.913, 0.087, 0.909, 0.073, 0.019), cpAgeMin = c(0, 0.972, 0, 0.964, 0.969, 0, 0.823, 0, 0.921, 0.996, 0, 0.846, 0.891, 0, 0.833, 0.988, 0, 0.927, 0.981, 0, 0.784, 0.995, 0, 0.958, 0.975, 0, 0.852, 0.976, 0, 0.913, 0, 0.909, 0.981), cpAgeMax = c(0.972, 1, 0.964, 0.969, 1, 0.823, 1, 0.921, 0.996, 1, 0.846, 0.891, 1, 0.833, 0.988, 1, 0.927, 0.981, 1, 0.784, 0.995, 1, 0.958, 0.975, 1, 0.852, 0.976, 1, 0.913, 1, 0.909, 0.981, 1), seg = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2)), row.names = c(NA, -33L), class = c("tbl_df", "tbl", "data.frame")) # 绘图代码 ggplot(data = df) + geom_ribbon(aes(x = year, ymin = cpAgeMin, ymax = cpAgeMax, group = interaction(seg, factor(age)), fill = factor(age), col = factor(age))) + theme_bw()
初始绘图效果

更新问题
在为第二个站点应用@Andy Baxter的解决方案后,绘图中数据范围外出现了额外的“凸起”,如何消除这些凸起?
更新后绘图问题

解决方案
解决初始空白问题
空白区域出现的原因是geom_ribbon按seg+age分组时,会将不连续年份的同分组数据连接,导致跨年份填充断裂。正确做法是按年份+seg+年龄组分组,确保每个年份内的年龄组区间独立连续:
修改绘图代码的group参数:
ggplot(data = df) + geom_ribbon(aes(x = year, ymin = cpAgeMin, ymax = cpAgeMax, group = interaction(year, seg, factor(age)), fill = factor(age), col = factor(age))) + theme_bw()
这样每个年份的每个年龄组区间都会被单独处理,确保0-1区间完全覆盖,不会出现空白。
解决额外凸起问题
数据范围外的凸起是因为geom_ribbon默认会延伸连接分组的首尾点,导致超出数据年份的区域出现异常填充。推荐以下两种解决方式:
方法1:限制x轴范围到数据实际年份
使用coord_cartesian()裁剪显示范围,仅展示数据存在的年份区间,不会过滤原始数据:
ggplot(data = df) + geom_ribbon(aes(x = year, ymin = cpAgeMin, ymax = cpAgeMax, group = interaction(year, seg, factor(age)), fill = factor(age), col = factor(age))) + coord_cartesian(xlim = range(df$year)) + theme_bw()
方法2:为分组添加首尾闭合点
若需保留x轴扩展范围,可在数据中为每个seg+age分组添加首尾年份的边界点(将cpAgeMin和cpAgeMax设为与相邻年份一致或NA),但此方法操作繁琐,优先推荐方法1。
内容的提问来源于stack exchange,提问作者tnt
相关产品推荐
相关产品推荐

