Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Store output from gridExtra::grid.arrange into an object

I am placing multiple plots into one image using gridExtra::grid.arrange and would like to have the option of saving the combined plot as an object that could be returned from within a function as part of a list of returned objects. Ideally, I would like to do this without printing the plot object.

The code below creates two plots, combines them with grid.arrange, and attempts to save the result into x. However, x evaluates to NULL and the plot is printed. The documentation for grid.arrange points me to arrangeGrob and suggests plotting can be turned off using plot=FALSE, but I get an error when I try that because FALSE is not a grob object.

Any suggestions for what I'm not understanding?

# R under development
# Windows 7 (32 bit)
# ggplot2 1.0.0
# gridExtra 0.9.1

p1 <- ggplot(mtcars, aes(x=factor(cyl), y=mpg)) + geom_boxplot()

p2 <- ggplot(mtcars, aes(x=factor(cyl), y=wt)) + geom_boxplot()

x <- gridExtra::grid.arrange(p1, p2)

x

Per the comments, I'm adding this edit. When I try it with arrangeGrob, I get no output at all.

> gridExtra::arrangeGrob(p1, p2)
> print(gridExtra::arrangeGrob(p1, p2))
Error: No layers in plot
> x <- gridExtra::arrangeGrob(p1, p2)
> x
Error: No layers in plot
like image 734
Benjamin Avatar asked Mar 15 '15 16:03

Benjamin


2 Answers

The code in your edit does not work properly since you didn't load gridExtra.

library(gridExtra)
y <- arrangeGrob(p1, p2, ncol = 1)
class(y)
#[1] "gtable" "grob"   "gDesc"
grid.draw(y)

enter image description here

Edit: since version 2.0.0, my comment about grid dependency below is no longer valid, since grid is now imported.

Edit: With gridExtra version >= 2.0.0, there is no need to attach either package,

p <- ggplot2::qplot(1,1)
x <- gridExtra::arrangeGrob(p, p)
grid::grid.draw(x)
like image 62
tonytonov Avatar answered Oct 21 '22 06:10

tonytonov


Funny that this was asked so recently - I was running into this problem as well this week and was able to solve it in a bit of a hacky way, but I couldn't find any other solution I was happier with.

Problem 1: ggplotGrob is not found

I had to make sure ggplot2 is loaded. I don't completely understand what's happening (I admit I don't fully understand imports/depends/attaching/etc), but the following fixes that. I'd be open to feedback if this is very dangerous.

if (!"package:ggplot2" %in% search()) {
  suppressPackageStartupMessages(attachNamespace("ggplot2"))
  on.exit(detach("package:ggplot2"))
}

Somebody else linked to this blog post and I think that works as well, but from my (non-complete) understanding, this solution is less horrible. I think.

Problem 2: no layers in plot

As you discovered too, fixing that problem allows us to use grid.arrange, but that returns NULL and doesn't allow saving to an object. So I also wanted to use arrangeGrob but I also ran into the above error when gridExtra was not already loaded. Applying the fix from problem 1 again doesn't seem to work (maybe the package is getting de-attached too early?). BUT I noticed that calling grid::grid.draw on the result of arrangeGrob prints it fine without error. So I added a custom class to the output of arrangeGrob and added a generic print method that simply calls grid.draw

f <- function() {
  plot <- gridExtra::arrangeGrob(...)
  class(plot) <- c("ggExtraPlot", class(plot))
  plot
}
print.ggExtraPlot <- function(x, ...) {
  grid::grid.draw(x)
}

Hooray, now I can open a fresh R session with no packages explicitly loaded, and I can successfully call a function that creates a grob and print it later!


You can see the code in action in my package on GitHub.

like image 37
DeanAttali Avatar answered Oct 21 '22 07:10

DeanAttali