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

如何在R ggplot2中设置多幅柱状图统一宽度及相关问题

解决方法

1. 统一子图宽度

使用ggarrange的align="h"参数实现水平对齐,同时指定widths=c(1,1,1)强制三个子图宽度完全一致。

2. 统一y轴与柱状图的间距

给三个子图设置相同的plot.margin,对B_bar和C_bar隐藏y轴标签/刻度但保留边距,确保所有子图的内部间距一致。

3. 调整柱状图顺序为A~E

通过fct_rev()反转group的显示顺序,配合coord_flip()实现从上到下为A到E的柱状图排列。


修改后的完整代码

library(ggplot2)
library(ggpubr)
library(forcats) # 用于fct_rev

df <- data.frame(group=c('A', 'B', 'C', 'D', 'E'),
                 valueA=c(0.1, 0.06, 0.02, 0.09, 0.12),
                 valueB=c(0.4, 0.6, 0.55, 0.45, 0.52),
                 valueC=c(0.76, 0.79, 0.85, 0.94, 0.89))

# 第一幅图:调整x轴顺序,实现coord_flip后从上到下A~E
A_bar <- ggplot(df, aes(x=fct_rev(group), y=valueA, fill=group))+
  geom_bar(stat='identity')+
  theme_bw()+
  labs(x = "Group", y = "ValueA", fill = "Group") +
  scale_y_continuous(limits=c(0,0.2),oob = rescale_none)+
  coord_flip()+
  theme(legend.position="none", 
        axis.text=element_text(size=12), 
        axis.title=element_text(size=14),
        # 设置统一边距
        plot.margin = margin(l=10, r=10, t=5, b=5))

# 第二幅图:隐藏y轴标签/刻度,保留统一边距
B_bar <- ggplot(df, aes(x=fct_rev(group), y=valueB, fill=group))+
  geom_bar(stat='identity')+
  theme_bw()+
  labs(x = "Group", y = "ValueB", fill = "Group") +
  scale_y_continuous(limits=c(0.4,0.65),oob = rescale_none)+
  coord_flip()+
  theme(legend.position="none", 
        axis.text=element_text(size=12), 
        axis.title=element_text(size=14),
        axis.title.y = element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),
        # 与A_bar相同的边距
        plot.margin = margin(l=10, r=10, t=5, b=5))

# 第三幅图:同第二幅图设置
C_bar <- ggplot(df, aes(x=fct_rev(group), y=valueC, fill=group))+
  geom_bar(stat='identity')+
  theme_bw()+
  labs(x = "Group", y = "ValueC", fill = "Group") +
  scale_y_continuous(limits=c(0.7,1),oob = rescale_none)+
  coord_flip()+
  theme(legend.position="none", 
        axis.text=element_text(size=12), 
        axis.title=element_text(size=14),
        axis.title.y = element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),
        # 统一边距
        plot.margin = margin(l=10, r=10, t=5, b=5))

# 拼接时强制水平对齐+等宽度
ggarrange(A_bar, B_bar, C_bar, ncol=3, nrow=1, align="h", widths=c(1,1,1))

更优雅的分面实现方案

如果想避免重复代码,可将数据转为长格式后用facet_wrap实现,自动保证子图宽度一致:

library(tidyverse)

df_long <- df %>%
  pivot_longer(cols = starts_with("value"), 
               names_to = "Metric", 
               values_to = "Value") %>%
  mutate(Metric = factor(Metric, levels = c("valueA", "valueB", "valueC"),
                         labels = c("ValueA", "ValueB", "ValueC")),
         group = fct_rev(group))

# 自定义每个分面的y轴范围
y_limits <- list(
  ValueA = c(0, 0.2),
  ValueB = c(0.4, 0.65),
  ValueC = c(0.7, 1)
)

ggplot(df_long, aes(x=group, y=Value, fill=group)) +
  geom_col() +
  theme_bw() +
  scale_y_continuous(oob = rescale_none) +
  facet_wrap(~Metric, ncol=3, scales = "free_y") +
  coord_flip() +
  theme(legend.position = "none",
        axis.text = element_text(size=12),
        axis.title = element_text(size=14),
        # 只让第一个分面显示y轴标签和刻度
        axis.text.y = element_text(color = ifelse(df_long$Metric == "ValueA", "black", "white")),
        axis.ticks.y = element_line(color = ifelse(df_long$Metric == "ValueA", "black", "white"))) +
  # 为每个分面设置y轴范围
  geom_blank(aes(y = y_limits[[Metric]][1])) +
  geom_blank(aes(y = y_limits[[Metric]][2]))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 00:23:10