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

如何调整ggplot2堆叠柱状图单柱宽度并保持柱间间距相等

问题原因

你直接给geom_bar传入宽度向量后间距不一致,是因为ggplot默认离散x轴的每个类别中心是等距分布的,柱子宽度变化后,相邻两个柱子的边缘间距就会出现差异。比如宽度为1的柱子中心在3的位置,左右会各占0.5的长度,会挤占和前一个柱子的空间。

解决方法

手动计算每个类别的x轴位置,严格控制相邻柱子的边缘间距相等,不需要安装额外扩展包,修改后的代码如下:

library(ggplot2)
library(dplyr)

# 原始数据处理逻辑不变
df <- data.frame(var = c("var1", "var1", "var1", "var2", "var2", "var2", "var3", "var3", "var3"),
                 change = c("better", "same", "worse","better", "same", "worse","better", "same", "worse"),
                 freq = sample(100:500, 9, replace = T))

df <- df %>% group_by(change) %>%
  mutate(per= prop.table(freq) * 100) %>%
  mutate(across(per, ~ round(., 1)))

# ===== 新增位置、宽度计算逻辑 =====
# 自定义参数:窄柱宽度、宽柱宽度、柱子之间的统一间距
w_narrow <- 0.3
w_wide <- 1
unified_gap <- 0.4

# 获取change的因子水平,默认顺序better、same、worse,coord_flip后worse在顶部
change_levels <- levels(as.factor(df$change))
# 给每个水平指定宽度,这里设置最后一个水平(worse)为宽柱,对应顶部位置
width_vec <- setNames(c(w_narrow, w_narrow, w_wide), change_levels)

# 计算每个水平的x轴中心位置,保证相邻间距相等
x_pos <- c()
current_end <- 0
for (level in change_levels) {
  w <- width_vec[[level]]
  x_pos[[level]] <- current_end + w/2
  current_end <- current_end + w + unified_gap
}

# 把位置和宽度映射到原数据
df$x_pos <- x_pos[as.character(df$change)]
df$bar_width <- width_vec[as.character(df$change)]

# ===== 绘图逻辑修改 =====
fig3 <- ggplot(df, aes(x=x_pos, y=freq, fill=var)) + 
  # 把width映射到数据中对应的宽度
  geom_bar(position="fill", stat="identity", alpha = 0.8, aes(width = bar_width)) + 
  scale_y_continuous(labels = scales::percent) +
  # x轴刻度替换为原change的类别标签
  scale_x_continuous(breaks = unname(x_pos), labels = names(x_pos), name = "change") +
  theme_classic() + 
  theme(legend.position = "right") + 
  guides(fill = guide_legend(reverse = TRUE)) +
  coord_flip()

fig3

效果说明

运行代码后三个柱子的边缘间距完全相等,顶部的宽柱会自然成为视觉焦点,你可以根据需要调整w_narrow、w_wide、unified_gap三个参数适配你的排版需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 23:18:02