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
相关产品推荐
相关产品推荐

