如何在ggplot中获取loess拟合线与y=0交点的x值并标记红点?
解决方案
要给每个分面的loess拟合线和y=0的交点加红点,关键是先按id分组算出每个子图的交点x值,再把这些点加到图里。具体步骤如下:
1. 计算每个id对应的交点x值
用dplyr分组处理,给每个id单独拟合loess模型,然后找到y=0对应的x:
library(dplyr) library(ggplot2) # 按id分组计算交点 intersection_points <- SF01_05 %>% group_by(id) %>% summarise( # 拟合当前id的loess模型 loess_fit = loess(Mean.T2 ~ number$x, data = cur_data()), # 生成密集的x序列用于预测,保证交点精度 x_seq = seq(min(number$x), max(number$x), length.out = 1000), # 预测对应x的y值 y_pred = predict(loess_fit, newdata = data.frame(`number$x` = x_seq)) ) %>% # 找到y_pred最接近0的那个x值,作为交点 mutate(threshold = x_seq[which.min(abs(y_pred - 0))]) %>% # 只保留需要的id和threshold列 select(id, threshold)
2. 修改绘图代码,添加红点
把计算好的交点数据用geom_point加到分面图里,注意要匹配每个分面的id:
ggplot(SF01_05, aes(x = number$x, y = Mean.T2, color = Month)) + geom_point() + geom_smooth(method = loess) + # 添加红色交点,指定数据来源是我们计算的intersection_points geom_point(data = intersection_points, aes(x = threshold, y = 0), color = "red", size = 3) + # 保留你原来的辅助线(如果需要的话) geom_segment(data = intersection_points, aes(x = threshold, xend = threshold, y = -Inf, yend = 0), col = 2, linetype = 1) + geom_segment(aes(x = -Inf, xend = Inf, y = 0, yend = 0), col = 2, linetype = 1) + ggtitle("Daily Average Air-temperature (-2cm)") + theme_bw() + xlab("Days") + ylab("Temperature ( ºC )") + theme(legend.position = "none") + scale_y_continuous(breaks = seq(-10, 16, 2), limits = c(-10, 16)) + scale_x_continuous(breaks = seq(0, 200, 50), limits = c(0, 200)) + facet_wrap(. ~ id)
几点说明
- 分组计算是核心,确保每个id用自己的数据拟合模型,得到专属的交点x值
- 生成1000个x值预测y,能保证找到的交点足够接近真实值
- 添加红点时必须指定
data = intersection_points,否则会用主数据框的所有数据重复绘制 - 把原来的x轴辅助线改成
xend = Inf,这样每条子图的y=0线能贯穿整个x轴范围
内容的提问来源于stack exchange,提问作者Stian Andresen
相关产品推荐
相关产品推荐

