R语言ggplot2 按type分类绘制n1/n2的100%堆叠比例条形图
100%占比堆叠条形图实现方案
之前使用position = fill无法得到预期图形的核心原因,是未将当前宽表结构转换为ggplot适配的长格式 tidy 数据,且未匹配正确的统计参数配置,具体可复现流程如下:
依赖准备
需要用到三个基础包,直接通过代码加载即可:
ggplot2:核心绘图工具tidyr:完成宽表到长表的格式转换scales:实现y轴的百分比标签格式化
复现你提供的示例数据:
library(ggplot2) library(tidyr) library(scales) demo_df <- data.frame( type = c("a", "b", "c", "d", "e", "f"), n1 = c(4278, 4004, 4268, 4645, 5068, 4338), n2 = c(903, 286, 304, 105, 148, 9), total = c(5181, 4290, 4572, 4750, 5216, 4347) )
关键步骤:格式转换
ggplot绘制堆叠条形图要求输入为「一行对应一个最小绘图单元」的长格式数据。当前表格中n1、n2是两个独立的数值列,需要合并为“分组类别”和“对应计数”两个字段,系统会自动按type分组完成后续的堆叠计算:
long_df <- demo_df |> pivot_longer( cols = c(n1, n2), # 指定需要合并的两个数值列 names_to = "group", # 原列名映射为分组字段 values_to = "count" # 原列数值映射为计数字段 )
转换后的数据结构会从6行扩展为12行,每一行对应某个type下的n1或n2分组的计数值,符合ggplot的输入要求。
绘图实现
绘图时需要注意两个之前容易遗漏的参数配置,避免图形偏差:
- 因为已经有预先统计好的计数值,需要在
geom_bar()中设置stat = "identity",否则ggplot会默认按原始数据的行数做计数统计,和我们的实际计数值不匹配 - 位置参数设置为
position = "fill",系统会自动按每个type下的总计数做归一化,把每根条形的总高度拉满为100%,按n1、n2的计数拆分堆叠段
ggplot(long_df, aes(x = type, y = count, fill = group)) + geom_bar(stat = "identity", position = "fill") + # 将y轴默认的0-1小数刻度转换为百分比格式 scale_y_continuous(labels = percent_format()) + labs(x = "类型", y = "组内占比", fill = "数据分组")
踩坑提示
- 无需手动计算n1、n2的占比再映射y轴,
position = "fill"会自动完成组内比例归一化,避免手动计算的误差 - 如果使用
geom_col()替代geom_bar(),不需要手动设置stat = "identity",因为geom_col()默认使用映射的y值作为条形高度,最终渲染效果和上述代码完全一致 - 跳过宽表转长表的步骤、直接叠加两层几何对象分别映射n1和n2,不仅代码冗余,还容易因为位置参数不统一导致堆叠错位
内容的提问来源于stack exchange,提问作者BOB123
相关产品推荐
相关产品推荐

