94
votes

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?

4
You might have to set up the viewports yourself -- grid.arrange might not be flexible enough (search stackoverflow for "[r] grid viewport")Ben Bolker
@BenBolker Has pointed you in a fruitful direction using grid. See also Hadley's ggplot2 book, Section 8.4.2.Ari B. Friedman
@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
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

4 Answers

73
votes

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

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

2
votes

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

1
votes

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