如何在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
相关产品推荐
相关产品推荐

