24

I've been thinking of using par() or layout() functions for combining ggplots. Will it be possible to use those functions?

Say I want to plot ggplot for scatterplot and ggplot for histogram. And I want to combine the two plots (NOT IN A SINGLE PLOT). Is it applicable?

I tried it with simple plotting in R, without using the ggplot functions. And it works actually.

Here's a sample from Quick-R, Link: http://www.statmethods.net/advgraphs/layout.html

# 4 figures arranged in 2 rows and 2 columns
attach(mtcars)
par(mfrow=c(2,2))
plot(wt,mpg, main="Scatterplot of wt vs. mpg")
plot(wt,disp, main="Scatterplot of wt vs disp")
hist(wt, main="Histogram of wt")
boxplot(wt, main="Boxplot of wt")

# One figure in row 1 and two figures in row 2
attach(mtcars)
layout(matrix(c(1,1,2,3), 2, 2, byrow = TRUE))
hist(wt)
hist(mpg)
hist(disp)

But when I try to use ggplot, and combine the plot, I don't get an output.

joran
  • 169,992
  • 32
  • 429
  • 468
Al-Ahmadgaid Asaad
  • 1,172
  • 5
  • 13
  • 25
  • ggplot2 is not a base graphics so you cannot combine ggplot2 and layout or par(mfrow). you need to use, e.g., plot.arrange etc in gridExtra. Or, you can play with viewport in grid system. – kohske Feb 28 '12 at 22:21
  • Since you asked for something like `layout()`, you probably want something like `grid.arrange()` (as kohske mentioned). [This linked post](http://stackoverflow.com/questions/7993722/creating-arbitrary-panes-in-ggplot2/7996205#7996205) (and Ben Bolker's answer in particular) will give you a good starting point. – Josh O'Brien Feb 28 '12 at 22:33

3 Answers3

32
library(ggplot2)
library(grid)


vplayout <- function(x, y) viewport(layout.pos.row = x, layout.pos.col = y)


plot1 <- qplot(mtcars,x=wt,y=mpg,geom="point",main="Scatterplot of wt vs. mpg")
plot2 <- qplot(mtcars,x=wt,y=disp,geom="point",main="Scatterplot of wt vs disp")
plot3 <- qplot(wt,data=mtcars)
plot4 <- qplot(wt,mpg,data=mtcars,geom="boxplot")
plot5 <- qplot(wt,data=mtcars)
plot6 <- qplot(mpg,data=mtcars)
plot7 <- qplot(disp,data=mtcars)

# 4 figures arranged in 2 rows and 2 columns
grid.newpage()
pushViewport(viewport(layout = grid.layout(2, 2)))
print(plot1, vp = vplayout(1, 1))
print(plot2, vp = vplayout(1, 2))
print(plot3, vp = vplayout(2, 1))
print(plot4, vp = vplayout(2, 2))


# One figure in row 1 and two figures in row 2
grid.newpage()
pushViewport(viewport(layout = grid.layout(2, 2)))
print(plot5, vp = vplayout(1, 1:2))
print(plot6, vp = vplayout(2, 1))
print(plot7, vp = vplayout(2, 2))
Maiasaura
  • 32,226
  • 27
  • 104
  • 108
  • 1
    To Maiasaura, Thank you for the script/code. But I got an error when I print plot1 and plot2, that says "Error in eval(expr, envir, enclos) : object 'wt' not found". However, I fixed it by rearranging your argument in plot1 and plot2. plot1 <- qplot(x=wt,y=mpg,data = mtcars,geom = "point",main="Scatterplot of wt vs. mpg") and plot2 <- qplot(x=wt,y=disp, data = mtcars,geom="point",main="Scatterplot of wt vs disp") Thank you again for a quick response. – Al-Ahmadgaid Asaad Feb 28 '12 at 23:08
  • @Maiasaura Thanks for the great answers. How can I add a title to the entire grid as a main title. I saw grid.text option but in a 2 by 4 grid it doesn't come nicely at the top and the middle. – add-semi-colons May 22 '14 at 15:11
  • 2
    This solution should be marked as being obsolete as the grid packages was removed from CRAN recently. – ahs85 Nov 30 '14 at 13:41
13

A utility I think deserves more attention for this is the layOut formerly of th wq package (note the capital "O"). It's since been removed from the wq package, so I've put the code below and renamed it lay_out to match typical ggplot style. It is like base::layout in that the plots can be of varying sizes, laid out in rows and columns. Each argument to lay_out is a 3-element list consisting of the plot, the row indices in which to plot it, and the column indices in which to plot it.

For example, using @Paul McMurdie's plots,

lay_out(list(plot1, 1, 1),
        list(plot2, 1, 2),
        list(plot3, 2, 1),
        list(plot4, 2, 2),
        list(plot5, 3, 1:2),
        list(plot6, 4, 1:2),
        list(plot7, 1:2, 3))

enter image description here

lay_out = function(...) {    
    x <- list(...)
    n <- max(sapply(x, function(x) max(x[[2]])))
    p <- max(sapply(x, function(x) max(x[[3]])))
    grid::pushViewport(grid::viewport(layout = grid::grid.layout(n, p)))    

    for (i in seq_len(length(x))) {
        print(x[[i]][[1]], vp = grid::viewport(layout.pos.row = x[[i]][[2]], 
            layout.pos.col = x[[i]][[3]]))
    }
} 

(Code sourced from a prior version of the wq package, from the commit history on the unofficial Github CRAN mirror.)

Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
7

The answer involving grid.layout works, I've used it, and I up-voted it. However, I usually find this solution much too tedious and error-prone, and I suspect most ggplot2 enthusiasts that do this regularly have wrapped this up in a function. I have found several such wrapping functions in previous searches, but my current workhorse solution is in a grid addon package called gridExtra. It has useful arguments, but the default rows/columns setup is often what you wanted in the first place:

library("ggplot2")
# Generate list of arbitrary ggplots
plot1 <- qplot(data = mtcars, x=wt, y=mpg, geom="point",main="Scatterplot of wt vs. mpg")
plot2 <- qplot(data = mtcars, x=wt, y=disp, geom="point",main="Scatterplot of wt vs disp")
plot3 <- qplot(wt,data=mtcars)
plot4 <- qplot(wt,mpg,data=mtcars,geom="boxplot")
plot5 <- qplot(wt,data=mtcars)
plot6 <- qplot(mpg,data=mtcars)
plot7 <- qplot(disp,data=mtcars)
# You might have produced myPlotList using instead lapply, mc.lapply, plyr::dlply, etc 
myPlotList = list(plot1, plot2, plot3, plot4, plot5, plot6, plot7)
library("gridExtra")
do.call(grid.arrange,  myPlotList)

Notice how the actual "combine my plots into one graphic" code was one line (after loading gridExtra). You might argue that putting the plots into a list was an extra line, but actually I could have alternatively used

grid.arrange(plot1, plot2, plot3, plot4, plot5, plot6, plot7)

For small numbers of ggplots this might be preferable. However, for n_plots > 4 you will begin to resent having to name and type them all.

Paul 'Joey' McMurdie
  • 7,295
  • 5
  • 37
  • 41