如何在ggplot中平滑带fill填充的时间序列geom_area图形?
问题说明
当前已绘制9T、9C两类就诊占比的堆叠百分比面积图,原始效果如下:
原始绘图代码:
ggplot(long2, aes(x = DATA, y = value, fill = variable)) + geom_area(position="fill", alpha=0.75) + scale_y_continuous(labels = scales::comma,n.breaks = 5,breaks = waiver()) + scale_fill_viridis_d() + scale_x_date(date_labels = "%b/%Y",date_breaks = "6 months") + ggtitle("Proporcions de les visites, només 9T i 9C") + xlab("Data") + ylab("% visites") + theme_minimal() + theme(legend.position="bottom") + guides(fill=guide_legend(title=NULL)) + annotate("rect", fill = "white", alpha = 0.3, xmin = as.Date.character("2020-03-16"), xmax = as.Date.character("2020-06-22"), ymin = 0, ymax = 1)
当前图形存在明显锯齿状波动,需要做平滑处理。
可用平滑方案
以下三种方案可根据数据粒度和展示需求选择:
- 方案1:ggplot图层内直接平滑(代码改动最小)
直接在现有绘图代码中叠加平滑图层,指定位置参数为position="fill"与原面积图对齐,选择适合时间序列的局部加权回归(loess)方法,关闭置信区间避免干扰视觉。新增代码片段如下:
其中geom_smooth(method = "loess", se = FALSE, position = "fill", span = 0.2, linewidth = 0)span参数控制平滑程度,值越大曲线越平滑;linewidth=0用于关闭平滑线描边,让平滑填充区域和原面积图自然融合。 - 方案2:数据预处理做滚动平均(结果最稳定,适合业务场景)
这类锯齿大多来自单日就诊数据的随机波动,先按类别分组做滚动平均再绘图,不会出现比例失真问题。需要加载dplyr和zoo包做数据处理:
后续绘图只需要将原代码中library(dplyr) library(zoo) # 按类别分组做7天滚动平均,窗口大小k可根据波动幅度调整 long2_smooth <- long2 %>% arrange(DATA) %>% group_by(variable) %>% mutate(smooth_value = rollmean(value, k = 7, fill = NA, align = "center")) %>% ungroup()aes里的y = value替换为y = smooth_value即可,其余代码完全不用改动。 - 方案3:样条插值顺滑边缘(适合展示类可视化)
如果需要完全无锯齿的顺滑曲线,可以对每个分组的时间序列做三次样条插值,生成密度更高的时间点拟合值后再绘图,生成的面积边缘会完全平滑。
注意:所有平滑操作后都需要校验每个时间节点的两类占比之和是否为1,避免平滑算法导致比例失真;原有疫情时段的白色半透明标注矩形放在所有图层最上层即可,不需要调整。
内容的提问来源于stack exchange,提问作者José Ángel Vicente Gómez
相关产品推荐
相关产品推荐

