如何在ggplot柱状图X轴的特定间隔处添加空白间隙
在ggplot柱状图的不同day组间添加自定义间隙
需求:在ggplot柱状图的X轴特定位置(第2组后、第4组后、第7组后,对应不同day分组的边界)添加更大的空白间隙,明确区分不同的day组。
解决方案
核心思路是手动控制X轴坐标位置,给每个day组分配独立的坐标区间,组间预留固定宽度的空白,替代原代码中interaction(hz, day)生成的连续无间隙X轴。
步骤1:预处理数据,分配自定义X坐标
先对数据按day分组,为每个hz类别分配连续的X位置,同时在不同day组之间设置额外间隙:
library(ggplot2) library(grid) library(dplyr) # 原始数据集 df <- data.frame( day = c(rep(11, 6), rep(12, 6), rep(23, 9), rep(31, 9), rep(47, 9)), hz = c(rep(1, 3), rep(2, 3), rep(1, 3), rep(2, 3), rep(1, 3), rep(2, 3), rep(4, 3) , rep(1, 3), rep(2, 3), rep(4, 3), rep(1, 3), rep(2, 3), rep(4, 3)), ft = c(38,42,45,28,30,45,38,41,45,25,30,45,45,43,50,30,28,48,30,33,40,45,41,47,38,35,43,30,32,50,46,40,50,38,30,40,30,28,40), sp = c(rep(c("Ctrl", "Absrc", "Ab42"), 13)) ) # 计算标准误的函数 se <- function(a) sd(a)/sqrt(length(a)) # 预处理:为每个day组分配独立的X坐标区间,组间留间隙 df_processed <- df %>% mutate(day = factor(day, levels = unique(day))) %>% group_by(day) %>% mutate(hz = factor(hz, levels = unique(hz))) %>% ungroup() %>% # 计算X坐标:组序号*(组内hz数量+2) + 组内hz序号,+2为组间预留的空白宽度 mutate( group_idx = as.integer(day), hz_idx = as.integer(hz), group_hz_count = max(hz_idx) ) %>% group_by(group_idx) %>% mutate(x_pos = (group_idx - 1)*(group_hz_count + 2) + hz_idx) %>% ungroup()
步骤2:绘制带组间间隙的柱状图
用自定义的x_pos作为X轴,设置刻度和标签,同时调整分组内的柱子间距:
g1 <- ggplot(df_processed, aes(x = x_pos, y = ft, group = desc(sp), fill = sp)) + geom_bar(position = position_dodge(width = 0.8), stat = "identity") + geom_errorbar( aes(ymax = ft + se(ft), ymin = ft - se(ft)), position = position_dodge(width = 0.8), width = 0.5 ) + coord_cartesian(ylim = c(0, 60), clip = "off") + # 设置X轴刻度和hz标签 scale_x_continuous( breaks = df_processed %>% distinct(x_pos, hz) %>% pull(x_pos), labels = df_processed %>% distinct(x_pos, hz) %>% pull(hz), expand = expansion(add = c(1, 2)) ) + # 添加day组标签(位于组下方居中位置) annotate( "text", x = df_processed %>% group_by(day) %>% summarise(mid_x = mean(x_pos)) %>% pull(mid_x), y = -6, label = unique(df_processed$day) ) + theme_classic() + theme( plot.margin = unit(c(1,1,4,1), "lines"), axis.title.x = element_blank() ) + scale_fill_grey(breaks = c("Ctrl", "Absrc", "Ab42")) + scale_y_continuous(expand = c(0,0)) # 关闭面板裁剪,显示组下方的标签 g2 <- ggplot_gtable(ggplot_build(g1)) g2$layout$clip[g2$layout$name == "panel"] <- "off" grid.draw(g2) ggsave(file = "graph.svg", plot = g2)
关键说明
- 组间间隙宽度可通过修改
(group_hz_count + 2)中的+2调整,数值越大间隙越宽 position_dodge(width = 0.8)保证同一hz下的不同sp柱子紧密排列,避免重叠- 用
annotate添加的day标签自动对齐每组的中心位置,无需手动计算坐标
内容的提问来源于stack exchange,提问作者dimmerz
相关产品推荐
相关产品推荐

