1

I am trying to compose a figure with multiple panels. I have a lot of empty space and I am trying to overlap some of the rectangular panels, so I can make some of them larger. However, setting in theme() either plot.background or plot.background to element_rect(fill = "transparent") worked.

Here an example of what I am working with:

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))
    )

This code generates this figure:

composite figure with opaque panels

As you can see, despite using plot.background = element_rect(fill = "transparent", color="#808080"), panel D has an opaque background that blocks the text on the y axis of panel B.

It seems that the issue lies in having the transparency in separate patchworkGrob.

If I draw both plots in the same grob, the transparency works fine:

pC+plot_spacer()+pD+plot_layout(widths=c(1,-0.35,1)) + 
+     plot_annotation(tag_levels = list(c('C', 'D')) )

plots in same grob

However, if the overlap is between plots in separate grobs, the transparency no longer works:

grid.arrange(
  patchworkGrob(pA + 
        plot_annotation(tag_levels = list(c('A')) )
  ),
  patchworkGrob( plot_spacer() + pD +
                   plot_layout(widths=c(-0.35, 1)) + 
        plot_annotation(tag_levels = list(c('D')) )
        ),
  nrow=1
  )

separate grobs

Is there any way to be able to build the composite figure using several patchworkGrob calls and still have the transparency working between panels??

This is just a mock-up, but the original figure I am trying to build is more complex and I haven't been able to build its layout without using separate calls.

2 Answers 2

4

It works when you specify plot.background in the theme inside patchworkGrob():

grid.arrange(
  patchworkGrob(pA + 
                  plot_annotation(tag_levels = list(c('A')) )
  ),
  patchworkGrob( plot_spacer() + pD +
                   plot_layout(widths=c(-0.35, 1)) + 
                   plot_annotation(tag_levels = list(c('D'))) & 
                   theme(plot.background = element_rect(fill = "transparent", color="#808080"))
  ),
  nrow=1
)

transparent grobs

My package versions:
ggplot2_3.5.2
gridExtra_2.3
patchwork_1.3.0
ggpubr_0.6.0

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, I just arrived at the same conclusion a few minutes ago after a fighting with the grob structure. The spacers are given a Z-position of -100, but are set to have a white background by default. I assume that, when drawing the 3 separate grobs in grid.arrange, the Z-positions are not checked between separate grobs, so, the white spacers are drawn on top of the (previously drawn) B panel.
Also, this behavior goes against the documentation of ?plot_spacer: "This simple wrapper creates an empty transparent patch that can be added to push your other plots apart. The patch responds to adding theme() specifications, but only plot.background will have an effect."
1

After fighting with the gtable grob structure I found that patchworkGrob makes the background of plot_spacer filled with white:

gg <- 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"))
  )

> gtable_filter(gg, "background")
TableGrob (20 x 62) "layout": 5 grobs
     z         cells         name                              grob
1    0 ( 2-19, 2-16) background-1 rect[plot.background..rect.26667]
2 -100 ( 2-19,17-31) background-2 rect[plot.background..rect.26679]
3    0 ( 2-19,32-46) background-3 rect[plot.background..rect.26719]
4 -100 ( 2-19,47-61) background-4 rect[plot.background..rect.26731]
5 -101 ( 1-20, 1-62)   background rect[plot.background..rect.26743]


> gtable_filter(gg, "background")$grobs[[1]]$gp$fill
[1] "transparent"
> gtable_filter(gg, "background-1")$grobs[[1]]$gp$fill
[1] "transparent"
> gtable_filter(gg, "background-2")$grobs[[1]]$gp$fill
[1] "white"
> gtable_filter(gg, "background-3")$grobs[[1]]$gp$fill
[1] "transparent"
> gtable_filter(gg, "background-4")$grobs[[1]]$gp$fill
[1] "white"

This goes against the documentation of ?plot_spacer:

This simple wrapper creates an empty transparent patch that can be added to push your other plots apart. The patch responds to adding theme() specifications, but only plot.background will have an effect.

Explicitly giving a transparent background to the spacers fixes the issue (plot_spacer() & theme(plot.background = element_rect(fill = "transparent")) )

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.