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

如何调整分组geom_bar条形图中零计数对应的geom_text位置?

解决分组条形图零计数导致文本偏移的问题

问题根源

当分组条形图中存在零计数的类别时,geom_text依赖stat="count"动态计算数值会因为缺失数据行,导致position_dodge无法正确分配每个文本的位置,进而出现非零数值偏移到分组中间的情况。

解决方案:提前预处理数据,补全零计数组合

通过提前计算每个分组的百分比,并补全所有feed1与study的组合(包括零计数的情况),让每个x轴类别下的两个分组都有对应数据点,确保position_dodge能精准对齐文本与柱子。

步骤1:加载依赖包并预处理数据

library(ggplot2)
library(dplyr)
library(tidyr)

# 原数据集代码
vec.feed1.sorted <- c(rep(2,1), rep(3,2), rep(4,7), rep(5,15), rep(6,30), rep(7,40))
set.seed(001)
vec.feed1 <- sample(vec.feed1.sorted)

df.feedback <- data.frame(
    study = factor(c(rep(1,62),rep(2,33)), levels=c("1","2")),
    feed1 = factor(vec.feed1, levels=as.character(c(1:7)))
  )

# 预处理:计算百分比并补全零计数
df_summary <- df.feedback %>%
  # 统计每个study和feed1的计数
  count(study, feed1) %>%
  # 补全所有feed1和study的组合,缺失的计数设为0
  complete(feed1, study, fill = list(n = 0)) %>%
  # 计算每个study内的百分比
  group_by(study) %>%
  mutate(percent = n / sum(n)) %>%
  ungroup() %>%
  # 匹配原代码的x轴标签(若有自定义标签可替换这里的labels参数)
  mutate(feed1_label = factor(feed1, levels = 1:7, labels = 1:7))

步骤2:修改绘图代码

使用预处理后的df_summary绘图,直接调用计算好的percent字段,无需依赖after_stat:

ggplot(data = df_summary, 
       aes(x = feed1_label, fill = study)) +
  geom_bar(aes(y = percent), stat = "identity", position = position_dodge(width = 0.9)) +
  scale_fill_manual(
    values = c("grey40", "grey60"),
    name = "event location",
    labels = c("university", "cinema")) +
  # 直接使用计算好的percent设置文本位置和内容,零计数时显示空文本
  geom_text(aes(y = percent, 
                label = ifelse(percent > 0, scales::percent(percent, accuracy = 1), "")),
            position = position_dodge(width = 0.9), vjust = -0.5) +
  ylab("percent of audience relative to location") +
  xlab("How did you like this event?") +
  theme(axis.text.x = element_text(angle = 45, hjust = .9)) +
  scale_y_continuous(labels = scales::percent, limits = c(0, 0.51)) +
  scale_x_discrete(drop = FALSE) +
  theme(
    panel.border = element_rect(linetype = "solid", colour = "black", linewidth = .5, fill = NA),
    panel.grid.minor = element_line(colour = "grey93", linewidth = .3),
    panel.grid.major.y = element_line(colour = "grey93", linewidth = .3),
    panel.background = element_rect(fill = "grey97")
  ) +
  theme(axis.title.x.bottom = element_text(margin = margin(t = .15, unit = "in")))

效果说明

预处理后的数据包含了所有feed1和study的组合,每个x轴类别下的两个分组都有对应的数值(零或非零),position_dodge(width=0.9)能精准将文本定位到对应柱子的正上方,解决了零计数导致的偏移问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 13:32:04