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

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嵌套图层的语法错误,分离各绘图元素。

内容的提问来源于stack exchange,提问作者nesta1990

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 13:54:58