ggplot柱状图:实现分组绝对值与子组占比显示的问题
用ggplot实现带占比分布和顶部绝对值的堆叠柱状图
需求
- 每个柱状顶部显示对应分组的绝对值总计数
- 每个柱状内按子组展示占比分布,并在子组区域内显示占比数值
现有尝试与问题
1. 数据处理代码
df <- df %>% group_by(directed_to_whom, treatment_details) %>% mutate(direct_period_count=n()) %>% # 按treatment_details分组下各directed_to_whom的计数 group_by(treatment_details) %>% mutate(period_count=n()) %>% # 每个treatment_details分组的总计数 mutate(directed_to_whom_percentage = direct_period_count/period_count*100) # 计算占比
该代码无报错,但生成的数据存在重复行,导致绘图逻辑混乱。
2. 初始绘图代码
ggplot(experimentgraph_directed_to_whom, aes(x = treatment_details, y = period_count, fill = directed_to_whom, label=directed_to_whom_percentage))+ geom_bar(position = "fill", stat = "identity") + scale_y_continuous(labels = scales::label_percent(accuracy = 1) + geom_text(position = position_stack(vjust = 0.5), size = 4)) + theme(plot.title = element_text(size = 18, face = "bold")) + theme_bw()+ theme(plot.title = element_text(size = 5, face = "bold"), axis.text.x = element_text(angle =90, vjust = 0.5))
存在语法错误(scale_y_continuous内嵌套geom_text),且未正确绑定占比数据,导致无法显示子组占比和顶部绝对值。
3. 修改后的尝试
数据处理:
df <- experimentgraph_directed_to_whom %>% distinct()
绘图代码:
ggplot(df, aes(x = treatment_details, y = period_count, fill = directed_to_whom, label=directed_to_whom_percentage))+ geom_bar(position = "fill", stat = "identity") + geom_text(aes(y = 1,label = sum(direct_period_count)), vjust = 0) + geom_text(aes(label = scales::label_percent(0.1, scale = 1) (directed_to_whom_percentage)), position = position_fill(.5)) + scale_y_continuous(labels = scales::label_percent(accuracy = 1) + geom_text(position = position_stack(vjust = 0.5), size = 4)) + theme(plot.title = element_text(size = 18, face = "bold")) + theme_bw()+ theme(plot.title = element_text(size = 5, face = "bold"), axis.text.x = element_text(angle =90, vjust = 0.5))
仍未解决数据重复、语法错误及文本定位问题,无法实现预期效果。
正确解决方案
步骤1:准确聚合数据
先通过聚合得到每个分组-子组的计数及总计数,避免重复行:
library(dplyr) library(ggplot2) library(scales) df_summary <- experimentgraph_directed_to_whom %>% # 统计每个treatment_details下各directed_to_whom的数量 count(treatment_details, directed_to_whom, name = "direct_period_count") %>% # 按treatment_details分组,计算总计数和占比(小数形式) group_by(treatment_details) %>% mutate(period_count = sum(direct_period_count), percentage = direct_period_count / period_count)
步骤2:绘制目标柱状图
ggplot(df_summary, aes(x = treatment_details, y = percentage, fill = directed_to_whom)) + # 堆叠占比柱状图 geom_bar(stat = "identity", position = "fill") + # 子组内显示占比文本,居中对齐 geom_text(aes(label = percent(percentage, accuracy = 1)), position = position_fill(vjust = 0.5), size = 4) + # 柱子顶部显示总计数绝对值,偏移至柱子上方 geom_text(data = df_summary %>% distinct(treatment_details, period_count), aes(x = treatment_details, y = 1.02, label = period_count), vjust = 0, size = 4.5, fontface = "bold") + # y轴设置为百分比格式 scale_y_continuous(labels = percent_format(accuracy = 1)) + # 主题调整 theme_bw() + theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1), plot.title = element_text(size = 14, face = "bold")) + # 自定义标签 labs(title = "分组占比与总计数分布", x = "分组", y = "占比", fill = "子组")
关键修正说明
- 数据层面:用
count()直接聚合,避免原代码中重复行导致的绘图错误;占比用小数计算,适配ggplot的百分比格式化。 - 绘图逻辑:
- y轴绑定
percentage,配合position="fill"实现占比堆叠,确保所有柱子高度统一为100%。 - 顶部绝对值文本单独提取每个分组的唯一总计数,设置
y=1.02避免与柱子重叠。 - 修正原代码中
scale_y_continuous嵌套图层的语法错误,分离各绘图元素。
- y轴绑定
内容的提问来源于stack exchange,提问作者nesta1990
相关产品推荐
相关产品推荐

