如何使用grid.arrange实现2x2无图例图表布局并将图例置于右侧居中
解决方案
要实现2×2布局的子图+右侧垂直居中的统一图例,可以按以下步骤操作:
- 移除子图自带图例:给每个ggplot对象添加
theme(legend.position = "none"),避免重复显示图例。 - 提取统一图例:从任意一个保留图例的临时图中提取图例元素。
- 自定义布局:使用
gridExtra的布局矩阵,让图例占据右侧第三列的两行空间,实现垂直居中对齐。
完整代码示例:
library(ggplot2) library(gridExtra) library(grid) library(dplyr) # 创建不带图例的子图 a <- mtcars %>% ggplot(aes(x = disp, y = mpg, colour = hp)) + geom_point(size = 2) + geom_smooth(se = F, colour = "grey") + theme(legend.position = "none") b <- mtcars %>% ggplot(aes(x = disp, y = mpg, colour = hp)) + geom_point(size = 2) + geom_smooth(se = F, colour = "grey") + theme(legend.position = "none") c <- mtcars %>% ggplot(aes(x = disp, y = mpg, colour = hp)) + geom_point(size = 2) + geom_smooth(se = F, colour = "grey") + theme(legend.position = "none") d <- mtcars %>% ggplot(aes(x = disp, y = mpg, colour = hp)) + geom_point(size = 2) + geom_smooth(se = F, colour = "grey") + theme(legend.position = "none") # 自定义函数提取图例(无需额外安装包) extract_legend <- function(plot) { tmp_gtable <- ggplot_gtable(ggplot_build(plot)) legend_index <- which(sapply(tmp_gtable$grobs, function(x) x$name) == "guide-box") legend_grob <- tmp_gtable$grobs[[legend_index]] return(legend_grob) } legend <- extract_legend( mtcars %>% ggplot(aes(x = disp, y = mpg, colour = hp)) + geom_point(size = 2) ) # 定义布局矩阵:图例占第三列两行 layout_matrix <- rbind( c(1, 2, 3), c(4, 5, 3) ) grid.arrange( a, b, legend, c, d, layout_matrix = layout_matrix, widths = c(4, 4, 1), # 调整列宽比例,图例列更紧凑 heights = c(1, 1) # 保持两行高度一致 )
关键说明
layout_matrix中数字3代表图例元素,它在两行的第三列重复出现,直接实现了图例垂直居中对齐两行的效果。widths参数可以灵活调整各列宽度,让整体布局更协调。- 如果习惯使用简化工具,也可以用
cowplot::get_legend()替代自定义的extract_legend函数,代码会更简洁。
内容的提问来源于stack exchange,提问作者Karl Seidl
相关产品推荐
相关产品推荐

