7

I have a list of ggplots that may be too complex to arrange using facet_wrap. All plots must share the same legend and should be arranged in a grid. Each column of the grid needs a different title, also each row of the grid needs a differen title.
An absurdly simple example:

library(ggplot2)
library(ggpubr)

plot1<- ggplot() + geom_point(aes(x=1, y=1, col="a"))
plot2<- ggplot() + geom_point(aes(x=1, y=1, col="a"))
plot3<- ggplot() + geom_point(aes(x=1, y=1, col="a"))
plot4<- ggplot() + geom_point(aes(x=1, y=1, col="a"))

plotlist<- list(plot1, plot2, plot3, plot4)

ggarrange(plotlist = plotlist, ncol = 2, nrow = 2, common.legend = TRUE, legend="bottom")

This produces everything needed except the column and row titles, and annotate_figure only adds a global title to the figure. The desired output should look like:

ggarrange with row and column titles

tjebo
  • 21,977
  • 7
  • 58
  • 94
Darío Rocha
  • 140
  • 1
  • 5
  • small tip: you can also use `plot1<-plot2<-plot3<-plot4<-` when all objects are the same – tjebo Feb 22 '20 at 17:03

2 Answers2

4

I prefer the patchwork package. Controlling layout is easy. The titles are a bit tricky. Patchwork uses the labs from each plot - so you could add plot titles to the upper plots and maybe add a row to the y label in the left hand side plots.

Arguably easier is to create the titles as plot and add them to your patchwork. You can easily customise your layout like explained in the patchwork vignette

library(ggplot2)
library(patchwork)

plot1<-plot2<-plot3<-plot4<- ggplot() + geom_point(aes(x=1, y=1, col="a"))

row1 <- ggplot() + annotate(geom = 'text', x=1, y=1, label="row 1 title", angle = 90) + theme_void() 

row2 <- ggplot() + annotate(geom = 'text', x=1, y=1, label="row 2 title", angle = 90) + theme_void() 

col1 <- ggplot() + annotate(geom = 'text', x=1, y=1, label="col 1 title") + theme_void() 

col2 <- ggplot() + annotate(geom = 'text', x=1, y=1, label="col 2 title") + theme_void() 

layoutplot <- "
#cccddd
aeeefff
aeeefff
bggghhh
bggghhh
"

plotlist <- list(a = row1, b = row2, c = col1, d = col2, e= plot1, f=plot2, g=plot3, h=plot4)

wrap_plots(plotlist, guides = 'collect', design = layoutplot)

Created on 2020-02-22 by the reprex package (v0.3.0)

tjebo
  • 21,977
  • 7
  • 58
  • 94
3

I know it's late to reply, but for future searchers (including future me): The ggpubr::annotate_figure function is likely best here to reduce cross-package issues.

Reproducing:

library(ggplot2)
library(ggpubr)

plot1<- ggplot() + geom_point(aes(x=1, y=1, col="a"))
plot2<- ggplot() + geom_point(aes(x=1, y=1, col="a"))
plot3<- ggplot() + geom_point(aes(x=1, y=1, col="a"))
plot4<- ggplot() + geom_point(aes(x=1, y=1, col="a"))

plotlist<- list(plot1, plot2, plot3, plot4)

Here is where you add it in:

commonplot <- ggarrange(plotlist = plotlist, ncol = 2, nrow = 2,
                        common.legend = TRUE, legend="bottom")

annotate_figure(commonplot, 
                top = "Column 1 Title                    Column 2 Title",
                left = "Row 2 Title                   Row 1 Title")

You can either assign the ggarrange object as an object, or you can pipe it down to annotate_figure.

The documentation shows more functionality as well, like adding right and bottom labels and a common title.

The display of the above code.

  • 1
    This should be the accepted answer since the question concerns `ggarrange` usage. It is a shame that there are no column and row titles in the `annotate_figure` function and the solution is so patchy. – arielhasidim Jun 10 '23 at 10:35