如何在ggplot2分组多值柱状图中添加累积百分比
为ggplot2分组柱状图添加每组累积百分比的实现方案
需求说明
现有按Taxa分组、每组包含两个Method观测值的分组柱状图,需要为每个Taxa组添加累积百分比相关可视化(组内占比或组间累积折线),尝试通过过滤数据集并使用geom_line实现但未成功,需明确正确实现方式,包括geom_line中使用filter的方法。
原始代码与数据集
原始绘图代码
df %>% mutate(Taxa = fct_relevel(Taxa, "Cnidaria ", "Echinodermata", "Mollusca", "Bryozoa", "Porifera", "Annelida", "Foraminifera", "Platyhelminthes", "Brachiopoda")) %>% ggplot(aes(x=Taxa,y=Observations,fill = Method)) + geom_bar(stat = "identity", width = 0.8 ,size = 1, position=position_dodge(), alpha = 0.9) + geom_text(aes(label=Observations), vjust=1.6, color="white", size=4, position=position_dodge(0.9)) + theme_bw() + theme(legend.background = element_rect(fill="grey95", size=0.5, linetype="solid", colour ="black"), axis.text.x = element_text(angle = 45, hjust=1, size = 10, face="bold"), axis.text.y = element_text(size = 10, face="bold"), axis.title = element_text(size = 12, face="bold"), panel.grid.minor = element_blank())
数据集
df <- structure(list(Taxa = c("Cnidaria ", "Cnidaria ", "Echinodermata", "Echinodermata", "Mollusca", "Mollusca", "Bryozoa", "Bryozoa", "Porifera", "Porifera", "Annelida", "Annelida", "Foraminifera", "Foraminifera", "Platyhelminthes", "Platyhelminthes", "Brachiopoda", "Brachiopoda"), sum = c(26L, 26L, 19L, 19L, 17L, 17L, 15L, 15L, 14L, 14L, 11L, 11L, 9L, 9L, 7L, 7L, 2L, 2L), Method = structure(c(2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L), .Label = c("BGR", "GSR"), class = "factor"), Observations = c(16L, 10L, 10L, 9L, 11L, 6L, 12L, 3L, 11L, 3L, 8L, 3L, 4L, 5L, 6L, 1L, 2L, 0L)), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -18L))
解决方案
方法1:添加组内占比文本
在每个柱状图上方显示该Method对应Taxa组的百分比占比:
library(tidyverse) df %>% mutate(Taxa = fct_relevel(Taxa, "Cnidaria ", "Echinodermata", "Mollusca", "Bryozoa", "Porifera", "Annelida", "Foraminifera", "Platyhelminthes", "Brachiopoda"), # 计算组内百分比,保留1位小数 group_pct = round(Observations / sum * 100, 1)) %>% ggplot(aes(x=Taxa,y=Observations,fill = Method)) + geom_bar(stat = "identity", width = 0.8 ,size = 1, position=position_dodge(), alpha = 0.9) + # 原始观测值文本 geom_text(aes(label=Observations), vjust=1.6, color="white", size=4, position=position_dodge(0.9)) + # 组内占比文本 geom_text(aes(label=paste0(group_pct, "%")), vjust=-0.5, size=3.5, position=position_dodge(0.9)) + theme_bw() + theme(legend.background = element_rect(fill="grey95", size=0.5, linetype="solid", colour ="black"), axis.text.x = element_text(angle = 45, hjust=1, size = 10, face="bold"), axis.text.y = element_text(size = 10, face="bold"), axis.title = element_text(size = 12, face="bold"), panel.grid.minor = element_blank())
方法2:添加全局累积百分比折线(双Y轴)
绘制所有Taxa组总和的累积占比折线,使用双Y轴适配数值范围:
# 预计算累积百分比数据 cumul_data <- df %>% distinct(Taxa, sum) %>% mutate(Taxa = fct_relevel(Taxa, "Cnidaria ", "Echinodermata", "Mollusca", "Bryozoa", "Porifera", "Annelida", "Foraminifera", "Platyhelminthes", "Brachiopoda")) %>% arrange(Taxa) %>% mutate(global_total = sum(sum), cumulative_sum = cumsum(sum), cumulative_pct = round(cumulative_sum / global_total * 100, 1)) # 绘图 df %>% mutate(Taxa = fct_relevel(Taxa, "Cnidaria ", "Echinodermata", "Mollusca", "Bryozoa", "Porifera", "Annelida", "Foraminifera", "Platyhelminthes", "Brachiopoda")) %>% ggplot() + # 分组柱状图 geom_bar(aes(x=Taxa,y=Observations,fill = Method), stat = "identity", width = 0.8 ,size = 1, position=position_dodge(), alpha = 0.9) + geom_text(aes(x=Taxa,y=Observations,label=Observations, group=Method), vjust=1.6, color="white", size=4, position=position_dodge(0.9)) + # 累积百分比折线(适配Y轴范围) geom_line(data = cumul_data, aes(x=Taxa, y=cumulative_pct * max(df$Observations)/100, group=1), color="darkred", size=1.2) + geom_text(data = cumul_data, aes(x=Taxa, y=cumulative_pct * max(df$Observations)/100, label=paste0(cumulative_pct, "%")), vjust=-0.5, color="darkred", size=3.5) + # 设置双Y轴 scale_y_continuous( name = "Observations", sec.axis = sec_axis(~ . * 100 / max(df$Observations), name = "Cumulative Percentage (%)") ) + theme_bw() + theme(legend.background = element_rect(fill="grey95", size=0.5, linetype="solid", colour ="black"), axis.text.x = element_text(angle = 45, hjust=1, size = 10, face="bold"), axis.text.y = element_text(size = 10, face="bold"), axis.text.y.right = element_text(color="darkred", size=10, face="bold"), axis.title = element_text(size = 12, face="bold"), axis.title.y.right = element_text(color="darkred", size=12, face="bold"), panel.grid.minor = element_blank())
方法3:在geom_line中使用filter筛选特定Method
仅为指定Method绘制其观测值的累积折线:
df %>% mutate(Taxa = fct_relevel(Taxa, "Cnidaria ", "Echinodermata", "Mollusca", "Bryozoa", "Porifera", "Annelida", "Foraminifera", "Platyhelminthes", "Brachiopoda")) %>% ggplot(aes(x=Taxa,y=Observations,fill = Method)) + geom_bar(stat = "identity", width = 0.8 ,size = 1, position=position_dodge(), alpha = 0.9) + geom_text(aes(label=Observations), vjust=1.6, color="white", size=4, position=position_dodge(0.9)) + # 筛选GSR方法,计算累积值并绘制折线 geom_line(data = . %>% filter(Method == "GSR") %>% arrange(Taxa) %>% mutate(cumulative = cumsum(Observations)), aes(x=Taxa, y=cumulative, group=1), color="darkblue", size=1) + geom_text(data = . %>% filter(Method == "GSR") %>% arrange(Taxa) %>% mutate(cumulative = cumsum(Observations)), aes(x=Taxa, y=cumulative, label=cumulative), vjust=-0.5, color="darkblue", size=3.5) + theme_bw() + theme(legend.background = element_rect(fill="grey95", size=0.5, linetype="solid", colour ="black"), axis.text.x = element_text(angle = 45, hjust=1, size = 10, face="bold"), axis.text.y = element_text(size = 10, face="bold"), axis.title = element_text(size = 12, face="bold"), panel.grid.minor = element_blank())
注:geom_line的data参数中,用.指代上游数据集,链式调用filter筛选目标Method后计算累积值即可。
内容的提问来源于stack exchange,提问作者C. Guff
相关产品推荐
相关产品推荐

