如何在ggplot中平滑折线?附代码与数据求助
问题描述
我想重现一张折线图,但需要让折线更平滑,目标是做出接近平滑曲线的效果。目前我写了代码,但只得到了趋势线,没能把两个数据系列都做平滑处理。
我的现有代码:
plot_fig4 <- ggplot(fig4, aes(x=dias))+ geom_line(aes(y=complete_preds_means), color="#9a6584", size=0.5)+ geom_line(aes(y=contrafact), colour="#000000", size=0.5) + geom_line(aes(y=complete_preds_means), method = "lm", formula=y~spline(x,21))+ geom_ribbon(aes(ymin=complete_preds_lower, ymax=complete_preds_upper), fill="#9a6584", alpha=0.2)
我的数据:
structure(list(dias = structure(c(19052, 19053, 19054, 19055, 19056, 19057, 19058, 19059, 19060, 19061, 19062, 19063, 19064, 19065, 19066, 19067, 19068, 19069, 19070, 19071), class = "Date"), complete_preds_means = c(341.07434, 381.59167, 455.47815, 485.05597, 527.60876, 562.63965, 602.48975, 624.663, 626.5637, 527.2239, 420.71643, 389.30804, 378.74396, 366.61548, 361.36566, 363.37253, 319.31824, 314.39688, 303.60342, 294.8934), contrafact = c(364.5, 358.89, 466.64, 470.11, 464.25, 487.27, 591.2, 715.33, 628.02, 505.98, 402.9, 316.81, 323.35, 358.61, 354.26, 369.5, 317.01, 336.5, 285.33, 270.91), complete_preds_lower = c(320.6368042, 361.7870895, 432.4487762, 461.2275833, 503.2255051, 535.7108551, 576.3850006, 597.9762146, 601.4407013, 504.0448837, 398.7777023, 368.0046799, 356.3603165, 345.5847885, 339.9679932, 342.7514801, 298.3247482, 293.4419693, 282.5286865, 275.4635284), complete_preds_upper = c(359.9897186, 402.5708664, 477.4746765, 508.7775711, 550.3326447, 587.6521027, 628.5320251, 649.9691833, 649.4831665, 547.9886108, 442.046402, 410.8121475, 399.0208908, 389.8615128, 387.4929993, 386.2935928, 340.140834, 336.3622116, 324.793483, 315.4606934)), row.names = c(NA, -20L), class = c("tbl_df", "tbl", "data.frame"))
解决方案
你之前的代码里用geom_line加method参数是无效的,geom_line不支持拟合方法。要实现平滑曲线,有两种常用方法:
方法1:用geom_smooth直接拟合
geom_smooth可以指定拟合方法,比如用广义可加模型(GAM)配合立方样条,能直接对两个数据系列做平滑处理:
library(ggplot2) library(mgcv) # 依赖包,用于GAM拟合 plot_fig4 <- ggplot(fig4, aes(x = dias)) + # 平滑complete_preds_means系列 geom_smooth(aes(y = complete_preds_means), color = "#9a6584", size = 0.5, method = "gam", formula = y ~ s(x, bs = "cs"), se = FALSE) + # 平滑contrafact系列 geom_smooth(aes(y = contrafact), color = "#000000", size = 0.5, method = "gam", formula = y ~ s(x, bs = "cs"), se = FALSE) + # 保留原有的置信区间 geom_ribbon(aes(ymin = complete_preds_lower, ymax = complete_preds_upper), fill = "#9a6584", alpha = 0.2) plot(plot_fig4)
方法2:手动用样条函数拟合后绘制
如果想更灵活控制平滑程度,可以先用smooth.spline手动拟合每个系列,再绘制拟合后的曲线:
# 拟合complete_preds_means的平滑曲线,df控制平滑度(值越小越平滑) smooth_means <- smooth.spline(fig4$dias, fig4$complete_preds_means, df = 10) smooth_means_df <- data.frame(dias = smooth_means$x, y_smooth = smooth_means$y) # 拟合contrafact的平滑曲线 smooth_contra <- smooth.spline(fig4$dias, fig4$contrafact, df = 10) smooth_contra_df <- data.frame(dias = smooth_contra$x, y_smooth = smooth_contra$y) # 绘制图表 plot_fig4 <- ggplot() + geom_line(data = smooth_means_df, aes(x = dias, y = y_smooth), color = "#9a6584", size = 0.5) + geom_line(data = smooth_contra_df, aes(x = dias, y = y_smooth), color = "#000000", size = 0.5) + geom_ribbon(data = fig4, aes(x = dias, ymin = complete_preds_lower, ymax = complete_preds_upper), fill = "#9a6584", alpha = 0.2) plot(plot_fig4)
说明:
- 方法1中的
bs = "cs"是立方样条,能保证曲线连续平滑,适合时间序列数据。 - 方法2中的
df参数可调整平滑度:df越大,曲线越贴近原始数据;df越小,曲线越平滑。
内容的提问来源于stack exchange,提问作者Maria
相关产品推荐
相关产品推荐

