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

ggplot2中geom_col对应geom_text百分比标签对齐调整求助

问题解决:分组柱状图百分比标签对齐调整

问题说明

基于年龄组、健康状态(very good、good、bad)绘制分组柱状图,展示性状态为"yes"时的性活动率百分比,但当前百分比标签按年龄组垂直堆叠,无法对应到对应柱子的末端位置。

原代码

library(tidyverse)
library(scales)

ageC <- c("18-34","35+", "35+", "35+","35+","18-34","18-34","35+","18-34","35+")
health <- c("very good","very good", "bad", "bad", "good", "good", "bad", "very good", "good", "bad")
sexuality <- c("yes", "yes", "no", "yes", "yes", "no", "yes", "no", "yes", "no")

df <- data.frame(ageC,health,sexuality)

df2 <- df %>%
  select(ageC, health, sexuality)

dff2 <- 
  df2 %>%
  group_by(ageC, health, sexuality) %>%
  summarise(n = n()) %>%
  mutate(pct = n / sum(n), sexuality = str_squish(sexuality)) %>%
  ungroup() |>
  filter(sexuality == "yes") %>%
  mutate(health = fct_relevel(health, "very good", "good", "bad"))


ggplot(data = dff2) +
  geom_col(aes(fill = health, y = pct, x = ageC),
           width = 0.75, position = position_dodge(preserve = "single")
  ) +
  scale_y_continuous(label = percent) +
  scale_fill_manual(values = c("very good" = "#cbd5e8", "good" = "#fdcdac", 
                               "bad" = "#b3e2cd" )) +
  facet_wrap(~sexuality) +
  labs(
    x = "Age class", y = "Percentage"
  ) +
  expand_limits(y = 1) +
  theme(text = element_text(family = "Times New Roman", size = 18)) +
  geom_text(aes(y = pct, x = ageC, group = pct, label = percent(pct, accuracy = .1), family = "Times New Roman"),  
            vjust = 1.2, size = 2)

调整方案

问题核心是geom_text的分组逻辑和位置设置错误,修改后即可让标签与柱子一一对应:

修改后的完整代码

library(tidyverse)
library(scales)

ageC <- c("18-34","35+", "35+", "35+","35+","18-34","18-34","35+","18-34","35+")
health <- c("very good","very good", "bad", "bad", "good", "good", "bad", "very good", "good", "bad")
sexuality <- c("yes", "yes", "no", "yes", "yes", "no", "yes", "no", "yes", "no")

df <- data.frame(ageC,health,sexuality)

df2 <- df %>%
  select(ageC, health, sexuality)

dff2 <- 
  df2 %>%
  group_by(ageC, health, sexuality) %>%
  summarise(n = n()) %>%
  mutate(pct = n / sum(n), sexuality = str_squish(sexuality)) %>%
  ungroup() |>
  filter(sexuality == "yes") %>%
  mutate(health = fct_relevel(health, "very good", "good", "bad"))


ggplot(data = dff2) +
  geom_col(aes(fill = health, y = pct, x = ageC),
           width = 0.75, position = position_dodge(preserve = "single")
  ) +
  scale_y_continuous(label = percent) +
  scale_fill_manual(values = c("very good" = "#cbd5e8", "good" = "#fdcdac", 
                               "bad" = "#b3e2cd" )) +
  facet_wrap(~sexuality) +
  labs(
    x = "年龄组", y = "百分比"
  ) +
  expand_limits(y = 1) +
  theme(text = element_text(family = "Times New Roman", size = 18)) +
  geom_text(aes(y = pct, x = ageC, group = health, label = percent(pct, accuracy = .1), family = "Times New Roman"),  
            vjust = 1.2, size = 2, position = position_dodge(preserve = "single"))

关键修改点

  • 将geom_text中的group = pct改为group = health:让标签按健康状态分组,匹配柱子的分组逻辑
  • 给geom_text添加position = position_dodge(preserve = "single"):与柱子的位置偏移设置保持一致,确保标签和对应柱子对齐
  • 可选优化:将坐标轴标签改为中文,适配中文使用场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 16:27:24