如何实现geom_bar按validated_2填充、按count分面并添加计数?
解决方案:同时实现分组填充、计数分面与大数据适配
原始数据
structure(list(validated_1 = c("sombra", "sombra", "sombra", "sombra", "sombra", "sombra", "sombra", "sombra", "sombra", "sombra", "coscinodiscus", "sombra", "coscinodiscus", "coscinodiscus", "sombra", "coscinodiscus", "sombra", "coscinodiscus", "sombra", "coscinodiscus", "coscinodiscus", "detritos", "detritos", "coscinodiscus", "appendicularia", "detritos", "coscinodiscus", "coscinodiscus", "detritos", "coscinodiscus", "langanho", "detritos", "copepodo", "langanho", "copepodo", "langanho", "langanho", "coscinodiscus", "coscinodiscus", "coscinodiscus"), validated_2 = c("sombra", "sombra", "sombra", "sombra", "sombra", "sombra", "sombra", "sombra", "sombra", "sombra", "coscinodiscus", "sombra", "coscinodiscus", "coscinodiscus", "sombra", "coscinodiscus", "sombra", "coscinodiscus", "sombra", "coscinodiscus", "coscinodiscus", "detritos", "detritos", "coscinodiscus", "zooplâncton", "detritos", "coscinodiscus", "coscinodiscus", "detritos", "coscinodiscus", "langanho", "detritos", "zooplâncton", "langanho", "zooplâncton", "langanho", "langanho", "coscinodiscus", "coscinodiscus", "coscinodiscus")), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -40L))
现有处理方式的不足
已尝试两种方式,但均无法满足全部需求:
- 方式1:支持按计数分面并添加总计数标签,但无法用
validated_2变量填充条形
df %>% group_by(validated_1) %>% summarise(count = n()) %>% arrange(desc(count)) %>% mutate(groups = c(rep("high N", 2), rep("lower N", 4))) %>% ggplot(aes(x = reorder(validated_1, -count), y = count)) + geom_bar(stat = 'identity') + facet_wrap(~ groups, nrow = 2, scales = "free") + geom_text(aes(label = count), vjust = -0.5, size = 3)
- 方式2:支持用
validated_2填充条形,但无法按计数分面、添加计数标签,且千万行级大数据集下运行速度极慢
df %>% ggplot(aes(x = fct_infreq(validated_1), fill = validated_2)) + geom_bar()
最终解决方案
核心思路是先对数据进行多层聚合统计,压缩数据量以适配大数据集,再基于聚合后的数据集实现所有需求:
library(tidyverse) # 1. 多层聚合统计:先按两级标签分组计数,再计算每个一级标签的总计数 agg_df <- df %>% group_by(validated_1, validated_2) %>% summarise(sub_count = n(), .groups = "drop_last") %>% mutate(total_count = sum(sub_count)) %>% ungroup() %>% # 2. 按总计数排序,分配分面组并转为有序因子 arrange(desc(total_count)) %>% mutate( validated_1 = fct_inorder(validated_1), # 保留总计数从高到低的顺序 groups = case_when( row_number() %in% 1:2 ~ "high N", # 前2个为高计数组 TRUE ~ "lower N" # 其余为低计数组 ) ) # 3. 绘制堆叠条形图:包含填充、分面、双计数标签 agg_df %>% ggplot(aes(x = validated_1, y = sub_count, fill = validated_2)) + geom_col(position = "stack") + # 添加子类别计数标签(位于堆叠条形中间) geom_text(aes(label = sub_count), position = position_stack(vjust = 0.5), size = 3) + # 添加一级标签总计数标签(位于条形顶部) geom_text( data = . %>% distinct(validated_1, total_count, groups), aes(y = total_count, label = total_count, fill = NULL), vjust = -0.5, size = 3.5 ) + facet_wrap(~ groups, nrow = 2, scales = "free") + labs(x = "Validated 1", y = "Count", fill = "Validated 2") + theme_bw()
方案细节说明
- 大数据适配:通过提前聚合统计,将千万行原始数据压缩为
validated_1与validated_2的组合级别数据,避免ggplot直接处理海量原始数据,大幅提升运行速度。 - 条形填充:使用
fill = validated_2配合geom_col(position = "stack")实现堆叠条形的分组填充效果。 - 按计数分面:先按总计数排序,通过
case_when为每个validated_1分配分面组,再用facet_wrap实现分面展示。 - 计数标签:
- 子类别计数:利用
position_stack将标签精准放在每个堆叠条形的中间位置; - 总计数:提取每个
validated_1的总计数数据,将标签放在条形顶部,避免重复绘制。
- 子类别计数:利用
内容的提问来源于stack exchange,提问作者Wilson Souza
相关产品推荐
相关产品推荐

