95

With grid.arrange I can arrange multiple ggplot figures in a grid to achieve a multi-panel figure by using something like:

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

generate some ggplot2 plots , then

plot5 <- grid.arrange(plot4, plot1, heights=c(3/4, 1/4), ncol=1, nrow=2)

How can I obtain an 'unbalanced' 2 col layout with one plot in the entire first col and three plots in the second col? I toyed with a 'grid-of-grids' approach by trying to use grid.arrange to plot one grid (e.g. plot5, above) against another plot, but obtained:

Error in arrangeGrob(..., as.table = as.table, clip = clip, main = main, : input must be grobs!

Update:

Thanks for the advice. I will look into viewports and grid. In the meantime, thanks to @DWin, the layOut function in the 'wq' package worked very well for the compilation figure in my Sweave document: enter image description here

Update 2:

The arrangeGrobcommand (as suggested by @baptiste) also works well, and seems very intuitive - at least it was easy to alter widths of the two columns. It also has the benefit of not requiring the `wq' package.

e.g. Here is the code from my Sweave file:

<<label=fig5plot, echo=F, results=hide>>=
plot5<-grid.arrange(plot4, arrangeGrob(plot1, plot2, plot3, ncol=1), 
                    ncol=2, widths=c(1,1.2))
@
\begin{figure}[]
    \begin{center}
<<label=fig5,fig=TRUE,echo=T, width=10,height=12>>=
<<fig5plot>>
@
\end{center}
\caption{Combined plots using the `arrangeGrob' command.}
\label{fig:five}
\end{figure}

which produces the following output: enter image description here

BTW, Anyone tell me why the '>NA' appears?

markus
  • 25,843
  • 5
  • 39
  • 58
user441706
  • 1,370
  • 2
  • 16
  • 17
  • You might have to set up the viewports yourself -- `grid.arrange` might not be flexible enough (search stackoverflow for "[r] grid viewport") – Ben Bolker Nov 13 '11 at 14:53
  • 2
    @BenBolker Has pointed you in a fruitful direction using `grid`. See also Hadley's ggplot2 book, Section 8.4.2. – Ari B. Friedman Nov 13 '11 at 15:39
  • 1
    @BenBolker `grid.arrange` can be used with nested viewports using its companion `arrangeGrob` (essentially returning a `gTree`), as in the example I gave below. – baptiste Nov 15 '11 at 00:27
  • 1
    your final assignment to `plot5` is not required as `grid.arrange` returns nothing (NULL). If you want to save the resulting grob use `arrangeGrob` again (and `grid.draw` to display it). – baptiste Nov 15 '11 at 21:10

5 Answers5

74

grid.arrange draws directly on the device; if you want to combine it with other grid objects you need arrangeGrob, as in

 p = rectGrob()
 grid.arrange(p, arrangeGrob(p,p,p, heights=c(3/4, 1/4, 1/4), ncol=1),
              ncol=2)

Edit (07/2015): with v>2.0.0 you can use the layout_matrix argument,

 grid.arrange(p,p,p,p, layout_matrix = cbind(c(1,1,1), c(2,3,4)))
baptiste
  • 75,767
  • 19
  • 198
  • 294
  • 6
    Could you explain how the ```cbind(c(1,1,1), c(2,3,4))``` matrix describes the arrangement of the figures? – Ron Gejman Sep 30 '15 at 14:14
  • 5
    @RonGejman it's easy if you print the 3x2 matrix on screen: first column is all 1s, that's where the first plot lives, spanning the three rows; second column contains plots 2, 3, 4, each occupying one row. – baptiste Sep 30 '15 at 18:59
18

I tried figuring it out with grid and thought I had it down but ended up failing (although looking now at the code in the function I cite below, I can see that I was really close ... :-)

The 'wq' package has a layOut function that will do it for you:

p1 <- qplot(mpg, wt, data=mtcars)
layOut(list(p1, 1:3, 1),   # takes three rows and the first column
        list(p1, 1, 2),    # next three are on separate rows
         list(p1, 2,2), 
          list(p1, 3,2))

enter image description here

IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • Wow, that is a useful function! I think copy+paste may have failed you, though; did you mean for `g1`, `g2`, etc to all be `p1`? – joran Nov 13 '11 at 19:18
  • 3
    @joran: I did. I can't remember which of the "three virtues of programming" is Laziness, but I know that is is there somewhere. – IRTFM Nov 13 '11 at 23:04
  • Thanks! Worked very nicely. See above. – user441706 Nov 14 '11 at 16:41
3

Another alternative is the patchwork package by Thomas Lin Pedersen.

# install.packages("devtools")
# devtools::install_github("thomasp85/patchwork")
library(patchwork)

Generate some plots.

p1 <- ggplot(mtcars) + geom_point(aes(mpg, disp)) + facet_grid(rows = vars(gear))
p2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))
p3 <- ggplot(mtcars) + geom_smooth(aes(disp, qsec))
p4 <- ggplot(mtcars) + geom_bar(aes(carb))

Now arrange the plots.

p1 + (p2 / p3 / p4)

enter image description here

markus
  • 25,843
  • 5
  • 39
  • 58
1

There is also multipanelfigure package that is worth to mention. See also this answer.

library(ggplot2)
theme_set(theme_bw())

q1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
q2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))
q3 <- ggplot(mtcars) + geom_smooth(aes(disp, qsec))
q4 <- ggplot(mtcars) + geom_bar(aes(carb))

library(magrittr)
library(multipanelfigure)

figure1 <- multi_panel_figure(columns = 2, rows = 3, panel_label_type = "upper-roman")

figure1 %<>%
  fill_panel(q1, column = 1, row = 1:3) %<>%
  fill_panel(q2, column = 2, row = 1) %<>%
  fill_panel(q3, column = 2, row = 2) %<>%
  fill_panel(q4, column = 2, row = 3)
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
figure1

Created on 2018-07-16 by the reprex package (v0.2.0.9000).

Tung
  • 26,371
  • 7
  • 91
  • 115
0

Another option is using the plot_grid function from the cowplot package. To create nested grid plots, you can combine multiple plot_grid to show multiple plots with different grids. Here is a reproducible example:

library(ggplot2)
library(cowplot)

# plots
p1 <- ggplot(mtcars, aes(disp, mpg)) + 
  geom_point()
p2 <- ggplot(mtcars, aes(carb)) +
  geom_bar()
p3 <- ggplot(mtcars, aes(x = NULL, y = disp)) + 
  geom_boxplot()

# Left column with two plots
left_col <- plot_grid(p1, p2, ncol = 1)
# Combine leff_col with third plot
plot_grid(left_col, p3, ncol = 2)

Created on 2022-08-22 with reprex v2.0.2

As you can see in the example, plot 1 and 2 are from one grid combined with p3 which give the current result. You can modify this to whatever you want.

Quinten
  • 35,235
  • 5
  • 20
  • 53