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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 04:30:43