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

如何为ggplot2的facet_wrap添加位置二级列标题?

实现分位置的二级列标题绘图

需求说明

现有包含8个站点(A-H)的数据,站点分属North和South两个区域,已用facet_wrap()生成2行4列的子图,需要为左两列(North站点:A、B、C、D)添加统一的"North"标题,右两列(South站点:E、F、G、H)添加统一的"South"标题,实现跨两行的二级列标题效果。

解决方案1:使用patchwork组合子图

这种方法逻辑清晰,通过拆分数据分别绘图后组合,适合快速实现需求:

library(ggplot2)
library(dplyr)
library(patchwork)

# 生成示例数据
set.seed(123)
df <- data.frame(matrix(ncol = 4, nrow = 24))
colnames(df)[1:4] <- c('location','site','x','y')
df$location <- rep(c('North','North','North','South','South','South'),4)
df$site <- c('A','A','A','E','E','E','B','B','B','F','F','F',
             'C','C','C','G','G','G','D','D','D','H','H','H')
df$x <- rep(seq(0,12,4),6)
df$y <- rnorm(24,50,20)

# 定义通用绘图函数
plot_site <- function(data) {
  ggplot(data, aes(x = x, y = y)) +
    geom_point() +
    geom_line() +
    scale_x_continuous(breaks = seq(0,12,3), limits = c(0,12)) +
    scale_y_continuous(breaks = seq(0, max(df$y),5)) +
    theme_bw() +
    facet_wrap(~site, nrow = 2) +
    theme(strip.background = element_rect(fill = "white"))
}

# 拆分数据并指定站点顺序
north_df <- df %>% 
  filter(location == "North") %>% 
  mutate(site = factor(site, levels = c("A", "B", "C", "D")))
south_df <- df %>% 
  filter(location == "South") %>% 
  mutate(site = factor(site, levels = c("E", "F", "G", "H")))

# 绘制分区域子图并添加标题
p_north <- plot_site(north_df) + 
  ggtitle("North") + 
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))
p_south <- plot_site(south_df) + 
  ggtitle("South") + 
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))

# 组合图表,左右两列宽度一致
p_north + p_south + plot_layout(ncol = 2, widths = c(1,1))

解决方案2:修改ggplot的gtable对象(无需额外安装包)

这种方法直接修改ggplot生成的底层表格对象,适合不想引入新包的场景:

library(ggplot2)
library(dplyr)
library(gtable)
library(grid)

# 生成示例数据
set.seed(123)
df <- data.frame(matrix(ncol = 4, nrow = 24))
colnames(df)[1:4] <- c('location','site','x','y')
df$location <- rep(c('North','North','North','South','South','South'),4)
df$site <- c('A','A','A','E','E','E','B','B','B','F','F','F',
             'C','C','C','G','G','G','D','D','D','H','H','H')
df$x <- rep(seq(0,12,4),6)
df$y <- rnorm(24,50,20)

# 绘制基础facet_wrap图表
p <- df %>%
  mutate(site = factor(site, levels = c('A','B','E','F','C','D','G','H'))) %>%
  ggplot(aes(x = x, y = y)) +
  geom_point() +
  geom_line() +
  scale_x_continuous(breaks = seq(0,12,3), limits = c(0,12)) +
  scale_y_continuous(breaks = seq(0,max(df$y),5)) +
  theme_bw() +
  facet_wrap(~site, nrow = 2)

# 转换为gtable对象
gt <- ggplotGrob(p)

# 找到顶部strip的位置,添加二级标题行
strip_row_pos <- grep("strip-b", gt$layout$name)[1] - 1
gt <- gtable_add_rows(gt, height = unit(1.2, "line"), pos = strip_row_pos)

# 添加North标题(覆盖前两列)
gt <- gtable_add_grob(gt, 
                      textGrob("North", gp = gpar(fontsize = 12, fontface = "bold")),
                      t = strip_row_pos + 1, 
                      l = gt$layout$l[grep("strip-b", gt$layout$name)[1]], 
                      r = gt$layout$l[grep("strip-b", gt$layout$name)[2]])

# 添加South标题(覆盖后两列)
gt <- gtable_add_grob(gt, 
                      textGrob("South", gp = gpar(fontsize = 12, fontface = "bold")),
                      t = strip_row_pos + 1, 
                      l = gt$layout$l[grep("strip-b", gt$layout$name)[3]], 
                      r = gt$layout$l[grep("strip-b", gt$layout$name)[4]])

# 绘制最终图表
grid.newpage()
grid.draw(gt)

两种方案都能实现需求:左两列显示North站点并添加统一标题,右两列显示South站点并添加统一标题,同时保留原有的scale_x_continuous()设置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 23:50:14