如何结合geom_vline与facet_wrap使用循环减少重复代码?
解决方案
最推荐的是基于注释数据框的原生ggplot实现,不需要任何循环或重复的sapply语句,完全符合ggplot2的设计逻辑,扩展性最强:
实现步骤
- 提前构造分类与对应高亮日期的匹配表,后续分类数量增减时只需维护这个表即可:
annotate_df <- data.frame( category = unlist(category_name), highlight_date = point_dates )
- 把原来4段重复的sapply代码直接替换为单条
geom_vline语句,利用facet分面自动匹配分类的特性,自动把对应日期的竖线绘制到对应分面中。
修改后完整代码
library(ggplot2) library(dplyr) library(tsibble) library(lubridate) # 原有模拟数据逻辑不变 set.seed(42) dates <- seq.Date(as.Date("2012-08-01"), as.Date("2014-08-30"), "day") n <- length(dates) dat <- data.frame(date = dates, category = rep(LETTERS[1:4], n/2), daily_count = sample(18:100, n, replace=TRUE)) point_dates <- sample(seq.Date(as.Date("2012-08-01"), as.Date("2014-08-30"), "month"),4) category_name <- list("A", "B", "C", "D") # 新增注释匹配表 annotate_df <- data.frame( category = unlist(category_name), highlight_date = point_dates ) # 绘图代码 ggplot(dat) + geom_boxplot(aes(y = daily_count, x = yearmonth(date), group = paste(yearmonth(date), category), fill = category)) + labs(x = 'Month & Year', y = 'Count', fill = "Category") + theme_bw() + theme(axis.text=element_text(size=10), axis.title=element_text(size=10), legend.position="none") + # 全局红色竖线保留 geom_vline(xintercept = ymd("2013-08-23"), linetype=1, colour="red", size = 0.5)+ # 替换原有4段sapply的单条竖线语句 geom_vline(data = annotate_df, aes(xintercept = yearmonth(highlight_date)), linetype = 3, colour = "black", size = 1)+ facet_wrap(~category, nrow = 2)
可选循环实现方案
如果偏好循环写法,也可以用lapply批量生成图层列表,避免重复代码:
# 批量生成所有分类的vline图层列表 vline_layers <- lapply(seq_along(category_name), function(i) { geom_vline(data = filter(dat, category == category_name[[i]]), aes(xintercept = yearmonth(point_dates[[i]])), linetype=3, colour="black", size = 1) }) # 绘图时直接拼接图层列表即可 ggplot(dat) + # 其他原有图层不变 geom_vline(xintercept = ymd("2013-08-23"), linetype=1, colour="red", size = 0.5)+ vline_layers + # 直接添加批量生成的图层列表 facet_wrap(~category, nrow = 2)
内容的提问来源于stack exchange,提问作者AneesBaqir
相关产品推荐
相关产品推荐

