如何强制ggplot2中geom_smooth曲线起始点保持一致?
问题描述
请问能否强制ggplot2的geom_smooth曲线起始点相同?我有如下数据集:
Year_start avg_start_salary adjusted_wage 1979 7.000000 8.000 1980 7.000000 9.080 1981 8.000000 9.080 1982 8.500000 9.080 1984 8.900000 11.000 1985 9.000000 11.288 1986 9.100000 11.440 1987 9.000000 11.728 1988 8.800000 12.056 1989 11.000000 12.440
我尝试修改下面的ggplot代码,让两条曲线起始点一致,但geom_smooth函数自动调整了它们:
ggplot(plot_data, aes(x = Year_start)) + # Smoothed trend line for avg_start_salary geom_smooth(aes(y = avg_start_salary, color = "Start Salary"), method = "loess", se = FALSE, size = 1.2) + # Smoothed trend line for adjusted_wage geom_smooth(aes(y = adjusted_wage, color = "Adjusted Salary"), method = "loess", se = FALSE, size = 1.2) + labs(title = "Average Starting Salary and Adjusted Salary Over Time", x = "Year", y = "Salary") + scale_color_manual(name = "Caption", values = c("Adjusted Salary" = "blue", "Start Salary" = "red")) + theme_minimal()
解决方法
问题核心是geom_smooth默认会针对每条曲线的拟合数据自动生成x轴预测范围,导致两条曲线的起始/结束点错位。要强制起始点一致,最可靠的方式是手动拟合loess模型,用统一的x序列生成预测值,再用geom_line绘制曲线,具体步骤如下:
1. 生成统一的x预测序列
先提取数据的时间范围,生成连续的年份序列,确保两条曲线用完全相同的x值做预测:
# 生成从最早到最晚年份的连续序列(1979到1989) pred_x <- seq(min(plot_data$Year_start), max(plot_data$Year_start), by = 1)
2. 分别拟合模型并生成预测值
对两个薪资变量各自拟合loess模型,用统一的x序列生成预测结果:
# 拟合起始薪资的loess模型 model_start <- loess(avg_start_salary ~ Year_start, data = plot_data) pred_start <- predict(model_start, newdata = data.frame(Year_start = pred_x)) # 拟合调整后薪资的loess模型 model_adjusted <- loess(adjusted_wage ~ Year_start, data = plot_data) pred_adjusted <- predict(model_adjusted, newdata = data.frame(Year_start = pred_x)) # 合并成绘图用的数据框 plot_pred <- data.frame( Year_start = pred_x, Start_Salary = pred_start, Adjusted_Salary = pred_adjusted )
3. 绘制对齐后的曲线
用预测数据框绘图,两条曲线的x轴范围完全一致,起始点自然对齐:
ggplot() + # 绘制起始薪资平滑曲线 geom_line(data = plot_pred, aes(x = Year_start, y = Start_Salary, color = "Start Salary"), size = 1.2) + # 绘制调整后薪资平滑曲线 geom_line(data = plot_pred, aes(x = Year_start, y = Adjusted_Salary, color = "Adjusted Salary"), size = 1.2) + # 可选:添加原始数据点用于对比 geom_point(data = plot_data, aes(x = Year_start, y = avg_start_salary), color = "red", size = 2) + geom_point(data = plot_data, aes(x = Year_start, y = adjusted_wage), color = "blue", size = 2) + labs(title = "Average Starting Salary and Adjusted Salary Over Time", x = "Year", y = "Salary") + scale_color_manual(name = "Caption", values = c("Adjusted Salary" = "blue", "Start Salary" = "red")) + theme_minimal()
额外说明
- 如果想简化操作,也可以给
geom_smooth加上xlim = c(1979, 1989)固定x轴范围,但这只是视觉截断,曲线的拟合逻辑还是各自独立,可靠性不如手动拟合。 - loess默认
span = 0.75,手动拟合时保持这个参数,就能和原geom_smooth的平滑程度一致。
内容的提问来源于stack exchange,提问作者Abner Mácola
相关产品推荐
相关产品推荐

