如何在R语言ggplot2中平滑geom_ribbon绘图曲线?
问题描述
制作昆虫丰度图时遇到以下问题:
- 用
geom_line()+geom_ribbon绘制的图存在大量尖锐转折 - 尝试用
geom_smooth(默认loess平滑)调整,效果不理想,添加SE后仍无法满足需求 - 需求:不使用
stat=smooth,仅平滑ribbon曲线,且保留geom_line+geom_ribbon的呈现方式
现有初始代码:
Y2_insect_time%>% ggplot(aes(x = Date.num, y =total, colour = Treatment))+ geom_line(aes(alpha= 1)) + geom_ribbon(aes(ymax = total + seY2t, ymin = total - seY2t,alpha = 0.01 , fill = Treatment)) + guides(alpha="none") + theme_bw() + xlab(NULL) + ylab("macroinvertebrates collected") + ggtitle("Number of Macroinvertebrates Over Time in Year Two")
尝试的geom_smooth代码:
Y2_insect_time%>% ggplot(aes(x = Date.num, y =total, colour = Treatment))+ geom_smooth(data=Y2_insect_time,n=8,span=0.8,se=FALSE, aes(x=Date.num, y=total, alpha=0.1,weight=1,fill = Treatment)) + guides(alpha="none") + theme_bw() + xlab(NULL) + ylab("macroinvertebrates collected") + ggtitle("Number of Macroinvertebrates Over Time in Year Two")
可行解决方案
核心思路是先对原始数据的趋势线(total)和误差范围(seY2t)进行平滑预处理,再用处理后的数据绘制geom_line和geom_ribbon,既能保留你偏好的图结构,又能消除尖锐转折。
方法1:用loess手动平滑分组数据
按Treatment分组,对total、total+seY2t、total-seY2t分别做loess平滑,生成新的平滑后变量:
library(dplyr) library(ggplot2) # 分组平滑数据 smoothed_data <- Y2_insect_time %>% group_by(Treatment) %>% mutate( # 平滑趋势线total smooth_total = predict(loess(total ~ Date.num, span = 0.8), newdata = .), # 平滑上限:total+seY2t smooth_ymax = predict(loess((total + seY2t) ~ Date.num, span = 0.8), newdata = .), # 平滑下限:total-seY2t smooth_ymin = predict(loess((total - seY2t) ~ Date.num, span = 0.8), newdata = .) ) %>% ungroup() # 用平滑后的数据绘图 smoothed_data %>% ggplot(aes(x = Date.num, colour = Treatment, fill = Treatment)) + geom_line(aes(y = smooth_total), alpha = 1) + geom_ribbon(aes(ymax = smooth_ymax, ymin = smooth_ymin), alpha = 0.1) + guides(alpha = "none") + theme_bw() + xlab(NULL) + ylab("采集到的大型无脊椎动物数量") + ggtitle("第二年大型无脊椎动物数量随时间变化")
- 调整
span参数控制平滑程度:值越大曲线越平缓,值越小越贴近原始数据 - 若数据量较大,可改用
gam(广义加性模型)替代loess提升效率:
library(mgcv) smoothed_data <- Y2_insect_time %>% group_by(Treatment) %>% mutate( smooth_total = predict(gam(total ~ s(Date.num, k = 8)), newdata = .), smooth_ymax = predict(gam((total + seY2t) ~ s(Date.num, k = 8)), newdata = .), smooth_ymin = predict(gam((total - seY2t) ~ s(Date.num, k = 8)), newdata = .) ) %>% ungroup()
k参数控制样条曲线自由度,值越大曲线越灵活
方法2:用zoo包的滑动平均平滑
如果偏好简单平滑方式,可使用滑动平均处理变量:
library(zoo) smoothed_data <- Y2_insect_time %>% group_by(Treatment) %>% arrange(Date.num) %>% mutate( smooth_total = rollmean(total, k = 3, fill = "extend"), smooth_ymax = rollmean(total + seY2t, k = 3, fill = "extend"), smooth_ymin = rollmean(total - seY2t, k = 3, fill = "extend") ) %>% ungroup()
k为滑动窗口大小,值越大平滑效果越强;fill = "extend"用于填充首尾缺失值
内容的提问来源于stack exchange,提问作者Colin Cooksey
相关产品推荐
相关产品推荐

