使用for循环创建facet_wrap图,为每个分面标记最大值
解决按ID分图、分面内标记Score最大值的问题
问题描述
需要实现以下需求:
- 按
id生成独立图表,每个图表内以month为分面(facet_wrap)展示time与score的趋势 - 为每个
id下**每个分面(即每个month)**对应的score最大值添加标签 - 保留
ind变量,方便后续扩展标记最大值前后n行的点
现有代码存在的问题:仅能标记每个id的全局score最大值,无法识别分面内的最大值(例如id=a的month=2最大值55、id=b的month=1最大值8均未被标记)
示例数据
qdat = data.frame(id = rep(c(rep("a",5), rep("b",5)),2), month = as.factor(c(rep(1,10), rep(2,10))), time = c(rep(1:5,4)), score = c(12,23,34,45,56, 4,5,6,8,7, 11,22,33,55,44, 7,8,9,10,12))
解决方案
使用tidyverse工具链实现分组计算与批量绘图,核心是按id+month分组识别最大值:
步骤1:加载依赖包并预处理数据
library(tidyverse) # 按id和month分组,识别每个分面内的最大值,生成ind变量(组内行号) qdat_processed <- qdat %>% group_by(id, month) %>% mutate( max_score = max(score), is_max = score == max_score, ind = row_number() # 组内行号,方便后续标记前后n行 ) %>% ungroup()
步骤2:定义绘图函数并批量生成图表
# 定义单ID的绘图函数 plot_single_id <- function(id_data) { ggplot(id_data, aes(x = time, y = score)) + geom_line(color = "#636363") + geom_point(size = 2) + # 突出显示最大值点 geom_point(data = filter(id_data, is_max), aes(color = is_max), size = 4, show.legend = FALSE) + # 添加最大值标签 geom_text( data = filter(id_data, is_max), aes(label = paste("Max:", max_score)), vjust = -1.2, hjust = 0.5, color = "#d62728", size = 4 ) + facet_wrap(~month, ncol = 2) + labs(title = paste("Score Trend - ID:", unique(id_data$id)), x = "Time", y = "Score") + theme_bw() + theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold")) } # 按ID拆分数据并批量生成所有图表 qdat_processed %>% group_split(id) %>% map(plot_single_id)
关键逻辑说明
- 分组计算:通过
group_by(id, month)实现最小粒度的分组,确保每个分面内的最大值被精准识别,解决了原代码仅识别全局最大值的问题 - ind变量扩展:生成的
ind是组内行号,后续若需标记最大值前后n行,只需筛选ind %in% c(which(is_max)-n, which(is_max), which(is_max)+n)即可 - 批量绘图:用
group_split(id)拆分数据,结合map函数批量生成每个ID的独立图表,提升效率
内容的提问来源于stack exchange,提问作者Mark Davies
相关产品推荐
相关产品推荐

