使用ggplot2+patchwork组合多图:跨patchworkGrob背景透明失效问题
解决多面板ggplot图形跨patchworkGrob时的透明背景失效问题
问题描述
制作多面板图形时,为节省空间需要重叠部分面板,已在theme()中设置plot.background和panel.background为透明,但当重叠的绘图分属不同patchworkGrob时,透明效果失效——比如示例中面板D的不透明背景会遮挡面板B的Y轴文本。
示例代码
library(ggplot2) library(gridExtra) library(patchwork) library(ggpubr) d1 <- data.frame( val1=rnorm(500,1,1), val2=rnorm(500,1,2), val3=rnorm(500,1,3) ) pA <- ggplot(d1) + geom_density(aes(x=val1)) + theme(aspect.ratio = 1, plot.background = element_rect(fill = "transparent", color="#808080")) pC <- ggplot(d1) + geom_density(aes(x=val2)) + theme_pubr() + theme( plot.background = element_rect(fill = "transparent", color="#808080")) pD <- ggplot(d1) + geom_density(aes(x=val3)) + theme_pubr() + theme( plot.background = element_rect(fill = "transparent", color="#808080"), panel.background = element_rect(fill = "transparent", color="#808080") ) df_mtcars <- as.data.frame(mtcars) df_mtcars$name <- rownames(df_mtcars) df_mtcars$cyl <- as.factor(df_mtcars$cyl) pB <- ggplot(df_mtcars) + geom_col(aes(x=hp, y=name, fill=cyl)) + theme_minimal() + scale_x_continuous(position="top") + scale_y_discrete(limits=rev) + theme(legend.position = "bottom", plot.background = element_rect(fill = "transparent", color="#808080")) + labs(y=NULL, x="HP") + guides(fill=guide_legend( title.position="top", byrow=TRUE, nrow=3 )) grid.arrange( patchworkGrob(pA + plot_layout(widths=1) + plot_annotation(tag_levels = list(c('A')) ) & theme(plot.tag = element_text(size = 15, face = "bold")) ), patchworkGrob(pB + plot_annotation(tag_levels = list(c('B')) ) & theme(plot.tag = element_text(size = 15, face = "bold")) ), patchworkGrob( pC + plot_spacer() + pD + plot_spacer() + plot_layout(widths = c(1, 0.01, 1, -0.65)) + plot_annotation(tag_levels = list(c('C', 'D')) ) & theme(plot.tag = element_text(size = 15, face = "bold")) ), widths=c(1, 0.75), heights=c(1, 0.65), layout_matrix=rbind(c(1,2),c(3,2)) )
解决方案
问题根源在于每个patchworkGrob会生成一个顶层容器grob,默认带有不透明白色背景,即使子图设置了透明,这个顶层背景依然会遮挡下方图形。以下两种方法可解决该问题:
方法1:手动修改patchworkGrob的顶层背景为透明
通过grid包工具定位并修改每个patchworkGrob的顶层背景元素,将其填充色设为透明:
# 先定义所有patchworkGrob对象 gA <- patchworkGrob(pA + plot_layout(widths=1) + plot_annotation(tag_levels = list(c('A')) ) & theme(plot.tag = element_text(size = 15, face = "bold"))) gB <- patchworkGrob(pB + plot_annotation(tag_levels = list(c('B')) ) & theme(plot.tag = element_text(size = 15, face = "bold"))) gCD <- patchworkGrob( pC + plot_spacer() + pD + plot_spacer() + plot_layout(widths = c(1, 0.01, 1, -0.65)) + plot_annotation(tag_levels = list(c('C', 'D')) ) & theme(plot.tag = element_text(size = 15, face = "bold")) ) # 定义修改grob背景的函数 modify_grob_background <- function(grob_obj) { bg_idx <- which(sapply(grob_obj$children, function(x) inherits(x, "rect"))) for (idx in bg_idx) { grob_obj$children[[idx]]$gp$fill <- "transparent" } return(grob_obj) } # 应用修改 gA <- modify_grob_background(gA) gB <- modify_grob_background(gB) gCD <- modify_grob_background(gCD) # 重新组合布局 grid.arrange( gA, gB, gCD, widths=c(1, 0.75), heights=c(1, 0.65), layout_matrix=rbind(c(1,2),c(3,2)) )
方法2:使用patchwork原生inset_element实现重叠布局
如果场景允许,直接用patchwork的inset_element功能嵌入需要重叠的子图,避免拆分多个patchworkGrob:
# 构建主布局 main_layout <- pA + pB + plot_layout(widths = c(1, 0.75), heights = c(1)) + plot_annotation(tag_levels = c('A', 'B')) & theme(plot.tag = element_text(size = 15, face = "bold")) # 插入CD组合图到指定位置 final_plot <- main_layout + inset_element( pC + pD + plot_layout(widths = c(1, 0.01, 1, -0.65)) + plot_annotation(tag_levels = list(c('C', 'D'))) & theme(plot.tag = element_text(size = 15, face = "bold")), left = 0, bottom = 0, right = 1, top = 0.65, # 匹配原布局位置 on_top = FALSE # 根据需求设置图层顺序 ) # 输出图形 final_plot
说明
- 方法1适合保留原有
grid.arrange布局逻辑的场景,直接修改grob属性,兼容性强。 - 方法2更贴合patchwork原生布局逻辑,减少多grob组合的兼容性问题,推荐优先尝试。
内容的提问来源于stack exchange,提问作者dkysh
相关产品推荐
相关产品推荐

