Labels ggplot patchwork

Viewed 478

I am trying to put 9 plots in one with some unique labels and some common labels. In a different post I was told to use patchwork instead of grid.arrange (since I had problems with the legend) but using patch work I am not able to put all the labels.

Here is the code for the plots:

library(ggplot2)

df <- data.frame(
  index = 1:21,
  corr = c(0.10470688, 0.10827255, 0.12322448, 0.11887717, 0.12719741, 0.12635607, 0.13427974,
           0.13539245, 0.13636687, 0.13834174, 0.13864013, 0.13816236, 0.13640052, 0.13775515,
           0.13563827, 0.13968726, 0.12499506, 0.11836173, 0.11097081, 0.09829338, 0.10470688),
  group = c(rep("Group A", 14), rep("Group B", 7))
)

p1 <- ggplot(df) +
  aes(x = index, y = corr, shape = group) +
  geom_point(size = 2) +
  theme_light()
library(patchwork)
p1 + p1 + p1 + p1 + p1 + p1 + p1 + p1 + p1 +
  plot_layout(ncol = 3, nrow = 3, guides = "collect")

But I do not know how to put the specific labels. Here you can see how I did that using grid.arrange:

library(ggplot2)
library(gridExtra)
library(grid)
library(lattice)

t <- textGrob("Proportion of S1>S2 on Variable1")

lay <- rbind(c(1,2,3),
             c(1,2,3),
             c(1,2,3),
             c(1,2,3),
             c(1,2,3),
             c(1,2,3),
             c(1,2,3),
             c(4,4,4),
             c(5,6,7),
             c(5,6,7),
             c(5,6,7),
             c(5,6,7),
             c(5,6,7),
             c(5,6,7),
             c(5,6,7),
             c(8,8,8),
             c(9,10,11),
             c(9,10,11),
             c(9,10,11),
             c(9,10,11),
             c(9,10,11),
             c(9,10,11),
             c(9,10,11),
             c(12,12,12))

grid.arrange (arrangeGrob (p1, top="High w", left="High p correlation")
,arrangeGrob(p1,top="Medium w correlation")
,arrangeGrob(p1,top="Low w correlation")
,arrangeGrob(t)
,arrangeGrob(p1, left="Medium p correlation")
,arrangeGrob(p1)
,arrangeGrob(p1)
,t
,arrangeGrob(p1, left="Low p correlation")
,arrangeGrob(p1)
,arrangeGrob(p1)
,t
, ncol=3,nrow=24,top="Title", layout_matrix=lay)

But I need to do it with pachwork in order to have a shared legend and not 9 legends one for each plot.

Is there any way to add labels in patchwork as I did in grid.arrange?

I have seen this function for grind.arrange to extract the shared legend but I cannot make it work in my example:

grid_arrange_shared_legend <- function(...) {
  plots <- list(...)
  g <- ggplotGrob(plots[[1]] + theme(legend.position="bottom"))$grobs
  legend <- g[[which(sapply(g, function(x) x$name) == "guide-box")]]
  lheight <- sum(legend$height)
  grid.arrange(
    do.call(arrangeGrob, lapply(plots, function(x)
      x + theme(legend.position="none"))),
    legend,
    ncol = 1,
    heights = unit.c(unit(1, "npc") - lheight, lheight))
}

It works here:

grid_arrange_shared_legend(p1, p1, p1, p1)

But I cannot make it work here:

grid.arrange (arrangeGrob (p1, top="High w", left="High p correlation")
,arrangeGrob(p1,top="Medium w correlation")
,arrangeGrob(p1,top="Low w correlation")
,arrangeGrob(t)
,arrangeGrob(p1, left="Medium p correlation")
,arrangeGrob(p1)
,arrangeGrob(p1)
,t
,arrangeGrob(p1, left="Low p correlation")
,arrangeGrob(p1)
,arrangeGrob(p1)
,t
, ncol=3,nrow=24,top="Title", layout_matrix=lay)

Any ideas? Thank you so much in advance and thank you so much for all your help and support in this forum.

With all good wishes,

1 Answers

Here you can find different strategies (different functions) to solve your task: https://github.com/thomasp85/patchwork/issues/43

  • As an example to add a global label to your plots use this provided function:
add_global_label <- function(pwobj, Xlab = NULL, Ylab = NULL, Xgap = 0.03, Ygap = 0.03, ...) {
  ylabgrob <- patchwork::plot_spacer()
  if (!is.null(Ylab)) {
    ylabgrob <- ggplot() +
      geom_text(aes(x = .5, y = .5), label = Ylab, angle = 90, ...) +
      theme_void()
  }
  if (!is.null(Xlab)) {
    xlabgrob <- ggplot() +
      geom_text(aes(x = .5, y = .5), label = Xlab, ...) +
      theme_void()
  }
  if (!is.null(Ylab) & is.null(Xlab)) {
    return((ylabgrob + patchworkGrob(pwobj)) + 
             patchwork::plot_layout(widths = 100 * c(Ygap, 1 - Ygap)))
  }
  if (is.null(Ylab) & !is.null(Xlab)) {
    return((ylabgrob + pwobj) + 
             (xlabgrob) +
             patchwork::plot_layout(heights = 100 * c(1 - Xgap, Xgap),
                                    widths = c(0, 100),
                                    design = "
                                   AB
                                   CC
                                   "
             ))
  }
  if (!is.null(Ylab) & !is.null(Xlab)) {
    return((ylabgrob + pwobj) + 
             (xlabgrob) +
             patchwork::plot_layout(heights = 100 * c(1 - Xgap, Xgap),
                                    widths = 100 * c(Ygap, 1 - Ygap),
                                    design = "
                                   AB
                                   CC
                                   "
             ))
  }
  return(pwobj)
}

and then use:

require(magrittr)
(p1 + p1 + p1 + p1 + p1 + p1 + p1 + p1 + p1) %>%
  add_global_label(Ylab = "Global Y title",
                   #       size = 8,
                   #      Ygap = 0.04
  ) + plot_layout(guides = "collect")

which results in: enter image description here

Related