You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 08:45:37