如何在ggplot2的facet_wrap分面中添加各分面数据均值线?
在ggplot分面中添加各人员的均值水平线(管道内实现)
问题背景
现有包含各中心人员不同日期销售数据的DataFrame,示例数据生成代码:
library(tidyverse) tibble( centre = rep(c('A', 'B'), 4), person = c('p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8') ) %>% full_join( tibble(date = seq(as.Date('2022-01-01'), as.Date('2022-01-5'), 1)), by = character() ) %>% mutate( num = round(runif(nrow(.), min = 50, max = 100),0) ) -> df
绘制人员销售额随日期变化的趋势图代码:
library(ggplot2) df %>% group_by(centre, person) %>% mutate(mean_num = mean(num, na.rm = TRUE)) %>% ungroup() %>% ggplot(aes(x = date, y = num)) + geom_point() + geom_line() + facet_wrap(~person, scales = 'free') + xlab('Date') + ylab('Sales') + ggtitle('Sales vs Date') -> plt
尝试给每个分面添加对应人员的平均销售额水平线,以下三种方法均失败:
# Method 1 plt + geom_hline(yintercept = mean(num), linetype = 'dotted', colour = 'red') # Method 2 plt + geom_hline(yintercept = mean_num, linetype = 'dotted', colour = 'red') # Method 3 plt + stat_summary(fun = mean, geom = 'line', colour = 'red')
希望在单一数据管道内完成该需求,需明确错误原因及修正方案。
错误原因分析
- 方法1:
mean(num)计算的是整个数据集的全局均值,并非每个分面(人员)的单独均值,导致所有分面显示同一条水平线,不符合需求。 - 方法2:未通过
aes()映射yintercept到mean_num,ggplot无法将分面与对应人员的均值关联,无法正确匹配每个分面的数值。 - 方法3:使用
geom='line'错误,均值是单一数值,应绘制水平线而非折线,且未指定针对分面分组计算。
管道内实现的正确方案
方案一:利用预计算的均值,通过geom_hline映射匹配
提前计算每个人员的均值后,在geom_hline中通过data参数筛选出每个人员唯一的均值,确保分面与均值正确对应:
df %>% group_by(centre, person) %>% mutate(mean_num = mean(num, na.rm = TRUE)) %>% ungroup() %>% ggplot(aes(x = date, y = num)) + geom_point() + geom_line() + # 筛选每个person的唯一均值,映射到yintercept geom_hline(aes(yintercept = mean_num), data = ~distinct(.x, person, mean_num), linetype = 'dotted', colour = 'red') + facet_wrap(~person, scales = 'free') + xlab('Date') + ylab('Sales') + ggtitle('Sales vs Date')
方案二:用stat_summary直接在分面内计算并绘制均值线
无需提前计算均值,通过stat_summary自动在每个分面内计算销售额均值,并绘制水平线:
df %>% ggplot(aes(x = date, y = num)) + geom_point() + geom_line() + # 在每个分面内计算y的均值,绘制水平线 stat_summary(fun = mean, geom = 'hline', aes(yintercept = after_stat(y)), linetype = 'dotted', colour = 'red') + facet_wrap(~person, scales = 'free') + xlab('Date') + ylab('Sales') + ggtitle('Sales vs Date')
内容的提问来源于stack exchange,提问作者Sarthak Nigam
相关产品推荐
相关产品推荐

