ggplot柱状图:将Y轴改为各fill分组内百分比而非总百分比
解决ggplot2柱状图分组百分比与文本标注问题
问题描述
使用以下代码生成柱状图时,Y轴为所有柱子的总百分比(总和约100%),需求改为每个fill分组(不同颜色的柱子组)内各X轴类别的百分比总和为100%,同时需要在每个柱子上方显示对应的百分比文本:
long_ov %>% filter(variable == "overall_mother_protection" | variable == "overall_child_protection" | variable == "overall_child_future") %>% ggplot(aes(factor(value,levels = 1:5, labels = c('Sangat Setuju', 'Agak Setuju', 'Tidak Setuju atau Tidak Setuju', 'Agak Tidak Setuju', 'Sangat Tidak Setuju')), fill = factor(variable, levels = c('overall_mother_protection', 'overall_child_protection', 'overall_child_future'), labels = c('Perlindungan Ibu', 'Perlindungan Anak', 'Masa Depan Bagi Anak-Anak')))) + theme_fivethirtyeight() + scale_fill_manual(values=c("#3C4C56", "#DB5628", "#B79D79")) + geom_bar(aes(y = (..count..)/sum(..count..)), position = "dodge") + scale_x_discrete(labels = function(x) str_wrap(x, width = 15), drop = FALSE, na.translate = FALSE) + scale_y_continuous(labels=percent) + ggtitle("Program Yasera menyebabkan peningkatan...", subtitle = "di antara 386 ibu") + mh_theme
解决方案
1. 调整Y轴为分组内百分比
推荐先用dplyr预处理数据,按每个fill分组(variable)统计各X轴类别(value)的百分比,再用geom_col绘图,这种方式更直观且便于后续扩展:
library(dplyr) library(ggplot2) library(scales) library(stringr) # 预处理数据,计算分组内百分比 plot_data <- long_ov %>% filter(variable %in% c("overall_mother_protection", "overall_child_protection", "overall_child_future")) %>% mutate( value = factor(value, levels = 1:5, labels = c('Sangat Setuju', 'Agak Setuju', 'Tidak Setuju atau Tidak Setuju', 'Agak Tidak Setuju', 'Sangat Tidak Setuju')), variable = factor(variable, levels = c('overall_mother_protection', 'overall_child_protection', 'overall_child_future'), labels = c('Perlindungan Ibu', 'Perlindungan Anak', 'Masa Depan Bagi Anak-Anak')) ) %>% group_by(variable, value) %>% summarise(count = n(), .groups = "drop") %>% group_by(variable) %>% mutate(percent = count / sum(count)) # 绘制柱状图 ggplot(plot_data, aes(x = value, y = percent, fill = variable)) + theme_fivethirtyeight() + scale_fill_manual(values=c("#3C4C56", "#DB5628", "#B79D79")) + geom_col(position = position_dodge(width = 0.9)) + scale_x_discrete(labels = function(x) str_wrap(x, width = 15), drop = FALSE, na.translate = FALSE) + scale_y_continuous(labels=percent, limits = c(0, 1)) + ggtitle("Program Yasera menyebabkan peningkatan...", subtitle = "di antara 386 ibu") + mh_theme
如果坚持直接用geom_bar计算,可修改参数按fill分组统计百分比:
geom_bar(aes(y = after_stat(count / sum(count))), position = position_dodge(width = 0.9), stat = "count") +
2. 添加柱子上方的百分比文本
基于预处理好的数据,添加geom_text实现文本标注,通过position_dodge对齐柱子位置,调整参数避免文本被截断:
ggplot(plot_data, aes(x = value, y = percent, fill = variable)) + theme_fivethirtyeight() + scale_fill_manual(values=c("#3C4C56", "#DB5628", "#B79D79")) + geom_col(position = position_dodge(width = 0.9)) + # 添加百分比文本 geom_text(aes(label = percent(percent, accuracy = 1)), position = position_dodge(width = 0.9), vjust = -0.5, size = 3.5) + scale_x_discrete(labels = function(x) str_wrap(x, width = 15), drop = FALSE, na.translate = FALSE) + scale_y_continuous(labels=percent, limits = c(0, 1.1)) + # 扩展Y轴上限,避免文本被截断 ggtitle("Program Yasera menyebabkan peningkatan...", subtitle = "di antara 386 ibu") + mh_theme
accuracy = 1控制百分比保留整数,可按需改为0.1保留一位小数vjust = -0.5调整文本与柱子的距离,数值越小文本位置越靠上
内容的提问来源于stack exchange,提问作者bricevk
相关产品推荐
相关产品推荐

