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

ggplot中多尺度/图例的网格布局排列及垂直空间不足的解决方法

ggplot中多尺度/图例的网格布局排列及垂直空间不足的解决方法

我之前也碰到过这个头疼的问题——用ggpubr::get_legend()提取多个图例后,总是没法整齐对齐,尤其是垂直空间不够想排成网格的时候。不过结合patchwork和cowplot的一些小技巧,完全能实现规整的n行m列网格布局,还能让每个图例的标题精准对齐。

先给你补全你提到的mock示例代码(基于ggnewscale的多尺度图),方便后续操作:

library(ggplot2)
library(ggnewscale)
library(ggpubr) 
library(patchwork)
library(cowplot)

# 构造地形数据
topography <- expand.grid(x = 1:nrow(volcano), y = 1:ncol(volcano))
topography$z <- volcano[as.matrix(topography)]

# 构造多尺度点数据
set.seed(42)
points <- data.frame(
  x = runif(20, 1, 80),
  y = runif(20, 1, 60),
  size = runif(20, 1, 10),
  color = sample(letters[1:5], 20, replace = TRUE),
  fill = sample(LETTERS[1:3], 20, replace = TRUE)
)

# 生成带多个尺度的主图
p <- ggplot(topography, aes(x, y)) +
  geom_tile(aes(fill = z)) +
  scale_fill_viridis_c(option = "A", name = "Topography") +
  new_scale_fill() +
  geom_point(data = points, aes(fill = fill, size = size), shape = 21) +
  scale_fill_brewer(palette = "Set1", name = "Point Fill") +
  new_scale_color() +
  geom_point(data = points, aes(color = color), size = 3) +
  scale_color_brewer(palette = "Set2", name = "Point Color") +
  theme(legend.position = "right")

解决步骤:

1. 单独提取每个图例(关键:统一标题位置)

直接从主图提取所有图例容易混在一起,最好为每个尺度单独生成小图,提取对应图例,同时把图例标题设置为顶部居中——这是后续对齐的关键:

# 提取地形填充图例
p_topography <- ggplot(topography, aes(x, y)) +
  geom_tile(aes(fill = z)) +
  scale_fill_viridis_c(option = "A", name = "Topography") +
  guides(fill = guide_colorbar(title.position = "top", title.hjust = 0.5)) +
  theme(legend.position = "right")
legend_topography <- get_legend(p_topography)

# 提取点填充图例
p_fill <- ggplot(points, aes(x, y)) +
  geom_point(aes(fill = fill), shape = 21) +
  scale_fill_brewer(palette = "Set1", name = "Point Fill") +
  guides(fill = guide_legend(title.position = "top", title.hjust = 0.5)) +
  theme(legend.position = "right")
legend_fill <- get_legend(p_fill)

# 提取点颜色图例
p_color <- ggplot(points, aes(x, y)) +
  geom_point(aes(color = color), size = 3) +
  scale_color_brewer(palette = "Set2", name = "Point Color") +
  guides(color = guide_legend(title.position = "top", title.hjust = 0.5)) +
  theme(legend.position = "right")
legend_color <- get_legend(p_color)

# 提取点大小图例
p_size <- ggplot(points, aes(x, y)) +
  geom_point(aes(size = size)) +
  scale_size_continuous(name = "Point Size") +
  guides(size = guide_legend(title.position = "top", title.hjust = 0.5)) +
  theme(legend.position = "right")
legend_size <- get_legend(p_size)

2. 用patchwork或cowplot排列图例网格

现在用patchwork::wrap_plots把图例排成2行2列的网格,开启对齐参数就能让标题和图例框完美对齐:

# 排列图例为2行2列网格
legend_grid <- wrap_plots(
  legend_topography, legend_fill,
  legend_color, legend_size,
  nrow = 2, ncol = 2,
  align = "hv",  # 同时开启水平和垂直对齐
  axis = "lrtb"  # 对齐所有边距
)

# 组合主图(去掉原图例)和图例网格
final_plot <- p + theme(legend.position = "none") +
  plot_spacer() +  # 填充空白避免布局偏移
  legend_grid +
  plot_layout(ncol = 2, widths = c(4, 1))  # 调整主图和图例的宽度比例

如果偏好cowplot,可以用plot_grid实现同样效果:

# 主图去掉原图例
p_no_legend <- p + theme(legend.position = "none")

# 排列图例网格
legend_grid <- plot_grid(
  legend_topography, legend_fill,
  legend_color, legend_size,
  nrow = 2, ncol = 2,
  align = "hv",
  axis = "tb"  # 垂直对齐顶部和底部
)

# 组合主图和图例
final_plot <- plot_grid(
  p_no_legend, legend_grid,
  ncol = 2,
  rel_widths = c(4, 1)
)

额外技巧:

  • 如果图例数量不是刚好填满网格,可以用plot_spacer()填充空白位置,保持网格规整。
  • 可以统一设置所有图例的主题(比如标题字体大小、图例框样式),让整体视觉更协调:
    # 统一图例主题
    legend_theme <- theme(
      legend.title = element_text(size = 10, face = "bold"),
      legend.text = element_text(size = 9),
      legend.box.background = element_rect(color = "gray80")
    )
    # 提取图例时加上这个主题
    legend_topography <- get_legend(p_topography + legend_theme)
    
  • 通过调整plot_layout的widths或heights参数,可以灵活控制主图和图例区域的占比。

这样处理后,你就能得到标题对齐、布局规整的图例网格,完美解决垂直空间不足的问题啦!

备注:内容来源于stack exchange,提问作者Daniel Zuluaga

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.16 07:04:41