Combined plot of ggplot2 (Not in a single Plot), using par() or layout() function? [duplicate]
Asked Answered
N

3

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.

Nestor answered 28/2, 2012 at 22:5 Comment(2)
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.Cater
Since you asked for something like layout(), you probably want something like grid.arrange() (as kohske mentioned). This linked post (and Ben Bolker's answer in particular) will give you a good starting point.Sanorasans
F
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))
Faustino answered 28/2, 2012 at 22:47 Comment(3)
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.Nestor
@Faustino 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.Sultry
This solution should be marked as being obsolete as the grid packages was removed from CRAN recently.Gooding
C
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.)

Cedilla answered 29/9, 2014 at 23:49 Comment(5)
I really love this solutions. grid.arrange does not offer the nice placement of the plots.Gooding
@Grego. The package wq (water quality) does not seem to have the function layOut() any more. Is that correct?Haldan
@Haldan apparently so. I've added the code to my answer.Cedilla
How do I install the necessary package? I tried install.packages("layOut") and install.packages("lay_out") to no avail.Aframe
Ah sorry got it from your Github link, I didn't realise you'd linked to the function source :)Aframe
T
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.

Tabloid answered 29/9, 2014 at 22:58 Comment(2)
if you wanted two columns, for example, resulting from grid.arrange, what would the final line contain? I have tried variations on args = list( ncol = 2)Haldan
Here's the one-liner: do.call(grid.arrange, c(myPlotList, list(ncol = 2)))Crenelate

© 2022 - 2024 — McMap. All rights reserved.