如何在ggplot2的geom_bar中移除条形间多余空白(不增宽条形)
移除ggplot2条形图的多余空白
问题描述
我需要移除ggplot2生成的条形图中多余的空白(如图中标记区域),要求不合并所有条形、不增加条形宽度。
原始图表:
需要移除的空白区域:
数据结构:
structure(list(hypoxic2 = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), levels = c("No", "Yes"), class = "factor"), Season = structure(c(3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), levels = c("Pre", "Peak", "Post"), class = "factor")), row.names = c(NA, -185L), class = "data.frame")
原始绘图代码:
ggplot(df, aes(x = Season, ..count..)) + geom_bar(aes(fill = hypoxic2), position = position_dodge2(width = 1, preserve = "single")) + ggtitle("TITLE") + labs(x="Season", fill = "Hypoxic (DO < 2 mg/L)", y = "Frequency") + ggsci::scale_fill_igv(palette = "default") + scale_x_discrete(labels = c("Pre-Hypoxic", "Peak-Hypoxic", "Post-Hypoxic")) + scale_y_continuous(limits = c(0,100), expand = expand_scale(mult = c(0, 0.01), add = c(0, 0))) + theme_bw() + theme(legend.position = c(0.85,0.9), plot.title = element_text(hjust=0.5, face = "bold", family = "Arial", size=15), legend.background = element_rect(fill = "white", color = 1), axis.ticks.x = element_blank(), axis.title = element_text(size=15), legend.title.align = 0.5, legend.title = element_text(face = "bold"), axis.title.y = element_text(size = 15, margin = margin(t = 0, r = 10, b = 0, l = 0), color = "black"), axis.title.x.top = element_text(size = 14, margin = margin(t = 0, r = 0, b = 10, l = 0), color = "black"), text = element_text(family = "Times New Roman"), axis.text.y = element_text(color = "black", size = 10, angle = 0, vjust = 0.5, hjust = 1, margin = margin(t = 0, r = 5, b = 0, l = 0)), axis.text.x = element_text(color = "black", size = 12, angle = 0, vjust = 0, hjust = 0.5, margin = margin(t = 0, r = 5, b = 0, l = 0)), strip.text.y = element_text(size=18), panel.grid.major = element_blank(), panel.grid.minor = element_blank())
解决方案
问题出在两个参数:position_dodge2()的width值,以及x轴的默认留白。修改这两处即可移除目标空白:
修改后的代码
ggplot(df, aes(x = Season, ..count..)) + geom_bar(aes(fill = hypoxic2), # 缩小组内条形的间距,避免过宽留白 position = position_dodge2(width = 0.6, preserve = "single"), # 固定条形宽度,满足不增宽的要求 width = 0.5) + ggtitle("TITLE") + labs(x="Season", fill = "Hypoxic (DO < 2 mg/L)", y = "Frequency") + ggsci::scale_fill_igv(palette = "default") + scale_x_discrete(labels = c("Pre-Hypoxic", "Peak-Hypoxic", "Post-Hypoxic"), # 移除x轴两侧的多余留白,0.2为标签预留少量空间 expand = c(0, 0.2)) + scale_y_continuous(limits = c(0,100), expand = expand_scale(mult = c(0, 0.01), add = c(0, 0))) + theme_bw() + theme(legend.position = c(0.85,0.9), plot.title = element_text(hjust=0.5, face = "bold", family = "Arial", size=15), legend.background = element_rect(fill = "white", color = 1), axis.ticks.x = element_blank(), axis.title = element_text(size=15), legend.title.align = 0.5, legend.title = element_text(face = "bold"), axis.title.y = element_text(size = 15, margin = margin(t = 0, r = 10, b = 0, l = 0), color = "black"), axis.title.x.top = element_text(size = 14, margin = margin(t = 0, r = 0, b = 10, l = 0), color = "black"), text = element_text(family = "Times New Roman"), axis.text.y = element_text(color = "black", size = 10, angle = 0, vjust = 0.5, hjust = 1, margin = margin(t = 0, r = 5, b = 0, l = 0)), axis.text.x = element_text(color = "black", size = 12, angle = 0, vjust = 0, hjust = 0.5, margin = margin(t = 0, r = 5, b = 0, l = 0)), strip.text.y = element_text(size=18), panel.grid.major = element_blank(), panel.grid.minor = element_blank())
关键修改点
position_dodge2(width = 0.6):将原width=1缩小,减少同一Season组内两个条形的间距,同时保持条形独立不合并。geom_bar(width = 0.5):固定条形宽度,避免调整dodge参数后条形自动变宽。scale_x_discrete(expand = c(0, 0.2)):移除x轴两侧的默认留白,0表示完全移除外侧空白,0.2为x轴标签预留少量空间防止截断,可根据实际显示效果微调。
这样修改后,就能移除你标记的空白区域,同时满足条形独立、宽度不变的要求。
内容的提问来源于stack exchange,提问作者FishyFishies
相关产品推荐
相关产品推荐

