如何结合facet_wrap与geom_smooth正确使用geom_label_repel?
解决分面后geom_smooth曲线末端标签异常问题
问题核心是直接用stat="smooth"的after_stat获取范围时,未考虑分面的分组逻辑,导致标签匹配错误。解决思路是提前计算每个分面+曲线分组的平滑末端点,再用该数据绘制标签。
修正后的代码
library(ggrepel) library(tidyverse) df<-structure(list(month_day = structure(c(19124, 19124, 19132, 19132,19145, 19146, 19171, 19172, 19160, 19185, 19201, 19214, 19229,19244, 19110, 19259, 19273, 19104, 19116, 19130, 19131, 19144, 19166, 19179, 19193, 19208, 19229, 19243, 19256, 19271, 19131, 19145, 19145, 19171, 19171, 19157, 19160, 19185, 19185, 19201, 19201, 19214, 19214, 19229, 19229, 19244, 19244, 19110, 19110, 19259, 19259, 19273, 19273, 19104, 19104, 19116, 19144, 19130, 19166, 19179, 19208, 19229, 19243, 19256, 19256, 19271, 19271,19131, 19145, 19145, 19171, 19171, 19157, 19185, 19185, 19201, 19201, 19214, 19214, 19214, 19229, 19229, 19244, 19244, 19110, 19110, 19259, 19259, 19273, 19273, 19104, 19104, 19116, 19116,19130, 19144, 19166, 19179, 19179, 19193), class = "Date"), Sensibilite = c(4,1, 0, 1, 0, 2, 3, 3, 2, 3, 4, 5, 5, 2, 0, 4, 4, 0, 1, 2, 3, 1,2, 2, 3, 3, 2, 2, 5, 4, 0, 2, 1, 3, 0, 2, 1, 5, 4, 5, 5, 5, 1, 4, 1, 3, 0, 0, 0, 5, 4, 5, 5, 0, 1, 1, 1, 1, 2, 1, 2, 2, 0, 4,3, 5, 4, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 1, 0, 0,0, 1, 0, 1, 1, 1, 0, 1, 0, 2, 0, 0, 0, 1, 1), Nom = c("Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom1","Nom1", "Nom1", "Nom1", "Nom1", "Nom1", "Nom2", "Nom2", "Nom2", "Nom2", "Nom2", "Nom2", "Nom2", "Nom2", "Nom2", "Nom2", "Nom2","Nom2", "Nom2", "Nom2", "Nom2", "Nom2", "Nom2", "Nom2", "Nom2","Nom2", "Nom2", "Nom2", "Nom2","Nom2", "Nom2", "Nom2", "Nom2","Nom2", "Nom2", "Nom2", "Nom2", "Nom2", "Nom2", "Nom2", "Nom2", "Nom2", "Nom2", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3", "Nom3","Nom3", "Nom3"), Annee = c("2021","2021","2021", "2021", "2021","2021","2021","2021","2021","2021","2021","2021","2021","2021","2021","2021","2021","2022", "2022", "2022","2022", "2022","2022", "2022", "2022", "2022", "2022","2022", "2022","2022","2021","2021","2021","2021","2021","2021","2021","2021","2021","2021","2021","2021","2021","2021", "2021","2021","2021","2021","2021", "2021","2021","2021","2021","2022","2022","2022","2022","2022","2022","2022","2022","2022","2022","2022","2022", "2022","2022","2021","2021","2021","2021","2021","2021", "2021","2021","2021","2021","2021","2021","2021","2021","2021","2021", "2021","2021","2021","2021","2021","2021", "2021","2022","2022","2022", "2022","2022", "2022","2022","2022","2022", "2022"), Lieu = c("Lieu1","Lieu1","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu1","Lieu1","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu1","Lieu1","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2","Lieu2" )), row.names = c(NA, -100L), class = c("tbl_df", "tbl", "data.frame")) # 计算每个分面+Nom对应的平滑曲线末端点 smooth_endpoints <- df %>% group_by(Lieu, Annee, Nom) %>% nest() %>% mutate(smooth_data = map(data, ~{ # 用loess拟合,和geom_smooth默认方法一致 fit <- loess(Sensibilite ~ as.numeric(month_day), data = .x) # 获取该分组下最大的日期(曲线末端) max_date <- max(.x$month_day) # 预测该日期对应的平滑值 pred_y <- predict(fit, newdata = data.frame(month_day = as.numeric(max_date))) tibble(month_day = max_date, Sensibilite = pred_y) })) %>% unnest(smooth_data) %>% ungroup() # 绘图 ggplot(df, aes(month_day, Sensibilite, color = Nom)) + geom_smooth(se = FALSE) + # 使用预计算的末端点添加标签 geom_label_repel(data = smooth_endpoints, aes(label = Nom), max.overlaps = Inf, size = 2) + facet_wrap(Lieu~Annee, ncol = 2) + scale_y_continuous(limits = c(0,5)) + scale_x_date(expand = expansion(mult = 0.25), name = "Mois", date_breaks = "1 month", date_labels = "%b")
关键说明
- 原代码中
after_stat(ifelse(x %in% range(x), color, NA_character_))基于全局x范围判断,分面后每个子图的独立范围被忽略,导致标签位置混乱。 - 提前按
Lieu、Annee、Nom分组拟合平滑曲线,提取每个分组的末端点,确保标签精准对应每个分面内的曲线末端。 - 如果你的
geom_smooth使用了其他拟合方法(如method = "lm"),只需修改loess为对应函数即可。
内容的提问来源于stack exchange,提问作者Mmerose
相关产品推荐
相关产品推荐

