add row and column titles with ggarrange
Asked Answered
P

3

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

Prindle answered 21/2, 2020 at 23:40 Comment(1)
small tip: you can also use plot1<-plot2<-plot3<-plot4<- when all objects are the sameGlobe
G
5

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)

Globe answered 22/2, 2020 at 17:31 Comment(0)
G
6

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.

Gitlow answered 22/7, 2022 at 20:24 Comment(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.Eugenioeugenius
G
5

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)

Globe answered 22/2, 2020 at 17:31 Comment(0)
B
1

Maybe you can add titles for subplots in the first row, i.e.,

plot1<- ggplot() + ggtitle("col title 1")
plot2<- ggplot() + ggtitle("col title 2")

If there are multiple graphs in several rows, this may compress the height of the plots in the first row as we have added a title there.

The solution is to use the ggpubr::ggarrange, pass param to heights() to increase the relative heights of the compressed subplot, e.g.,

g <- ggpubr::ggarrange(
    plotlist=c(plot1, plot2, plot3, plot4),
    nrow=2,
    ncol=2,
    heights=c(1.2, 1)
)
Berte answered 1/1 at 1:35 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Aeon

© 2022 - 2024 — McMap. All rights reserved.