167

I am trying to plot multiple plots using ggplot2, arranging them using grid.arrange(). Since I managed to find someone describing the exact problem I have, I have quoted from the problem description from link:

When I use ggsave() after grid.arrange(), i.e.

grid.arrange(sgcir1,sgcir2,sgcir3,ncol=2,nrow=2)
ggsave("sgcirNIR.jpg")

I do not save the grid plot but the last individual ggplot. Is there any way of actually saving the plot as displayed by grid.arrange() using ggsave() or something similar? Other than using the older way

jpeg("sgcirNIR.jpg")
grid.arrange(sgcir1,sgcir2,sgcir3,ncol=2,nrow=2)
dev.off()

The same link gives the solution below:

require(grid)
require(gridExtra)
p <- arrangeGrob(qplot(1,1), textGrob("test"))
grid.draw(p) # interactive device
ggsave("saving.pdf", p) # need to specify what to save explicitly

However, I can't figure out how to use ggsave() to save the output of the grid.arrange() call in the following code, which is taken from link:

library(ggplot2)
library(gridExtra)
dsamp <- diamonds[sample(nrow(diamonds), 1000), ] 

p1 <- qplot(carat, price, data=dsamp, colour=clarity)
p2 <- qplot(carat, price, data=dsamp, colour=clarity, geom="path")

g_legend<-function(a.gplot){
tmp <- ggplot_gtable(ggplot_build(a.gplot))
leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
legend <- tmp$grobs[[leg]]
return(legend)}

legend <- g_legend(p1)
lwidth <- sum(legend$width)

## using grid.arrange for convenience
## could also manually push viewports
grid.arrange(arrangeGrob(p1 + theme(legend.position="none"),
                                        p2 + theme(legend.position="none"),
                                        main ="this is a title",
                                        left = "This is my global Y-axis title"), legend, 
                     widths=unit.c(unit(1, "npc") - lwidth, lwidth), nrow=1)

# What code to put here to save output of grid.arrange()?
radek
  • 7,240
  • 8
  • 58
  • 83
I Like to Code
  • 7,101
  • 13
  • 38
  • 48
  • 6
    Use `png(); grid.arrange(); ggplot(); ggplot(); dev.off()` – Andrie Jun 12 '13 at 06:48
  • 2
    Not `print(ggplot())`? – IRTFM Jun 12 '13 at 06:51
  • @DWin Yes, probably! :-) – Andrie Jun 12 '13 at 06:52
  • 1
    @Andrie What you suggest works, but the resolution of the image is very low. When I save a single `ggplot` using `ggsave()`, the resolution of the image is much higher. Is there a way to save the output of `grid.arrange()` with a high resolution, as it would be if it were a single plot saved with `ggsave()`? If I provide for example the options `png(...,height=1600, width=2500)` the image looks very blurry. – I Like to Code Jun 12 '13 at 16:44

7 Answers7

160

grid.arrange draws directly on a device. arrangeGrob, on the other hand, doesn't draw anything but returns a grob g, that you can pass to ggsave(file="whatever.pdf", g).

The reason it works differently than with ggplot objects, where by default the last plot is being saved if not specified, is that ggplot2 invisibly keeps track of the latest plot, and I don't think grid.arrange should mess with this counter private to the package.

baptiste
  • 75,767
  • 19
  • 198
  • 294
  • 3
    When I try this I get an error telling me that g is not of the right type? – Jack Aidley Jun 16 '14 at 12:20
  • @JackAidley ask a new question, with a minimum self-contained reproducible example, and your sessionInfo() (make sure you have recent versions of R and packages). – baptiste Jun 16 '14 at 12:34
  • 3
    @DaveX please don't spread this misleading information; `plot(g)` is **not** the right way to display a gtable, use `grid.draw(g)` instead. – baptiste Oct 07 '15 at 20:03
  • @baptiste Thanks & reworked: Note that if you try to see the result of `g <-arrangeGrob(...)` with `print(g)` you get a text table listing the graphic objects rather than the graphic. Try `grid.draw(g)` to render the graphic as graphics. – – Dave X Oct 08 '15 at 17:35
  • 8
    ggsave is not working with (some or all) grobs anymore. – vak Oct 29 '15 at 14:50
70

I had some problems with babptiste's proposal, but got it finally. Here is what you should use:

 # draw your plots
 plot1 <- ggplot(...) # this specifies your first plot
 plot2 <- ggplot(...) # this specifies your second plot
 plot3 <- ggplot(...) # this specifies your third plot

 #merge all three plots within one grid (and visualize this)
 grid.arrange(plot1, plot2, plot3, nrow=3) #arranges plots within grid

 #save
 g <- arrangeGrob(plot1, plot2, plot3, nrow=3) #generates g
 ggsave(file="whatever.pdf", g) #saves g

This should work well.

user2B4L2
  • 969
  • 1
  • 7
  • 10
27

Another easy way to save a grid.arrange to a pdf file is to use pdf():

pdf("filename.pdf", width = 8, height = 12) # Open a new pdf file
grid.arrange(plot1, plot2, plot3, nrow=3) # Write the grid.arrange in the file
dev.off() # Close the file

It allows to merge other things than ggplots in the arrangement, like tables...

JohnBee
  • 1,720
  • 1
  • 15
  • 19
  • Just a note that when using within a `for()` loop that produces multiple sets of plots using `grid.arrange()`, then `print(grid.arrange())` is needed. – Roasty247 Sep 21 '22 at 11:44
15

You don't need to use arrangeGrob, you can assign the result of grid.arrange directly to a plot and save that using ggsave:

p3 <- grid.arrange(p1,p2, nrow = 1)
ggsave("filename.jpg", p3)
8

I thought it was worth adding to this. I had problems with the above, with ggsave producing an error: "plot should be a ggplot2 plot"

Thanks to this answer: Saving a graph with ggsave after using ggplot_build and ggplot_gtable I have an amendment to the above code.

  # draw your plots
 plot1 <- ggplot(...) # this specifies your first plot
 plot2 <- ggplot(...) # this specifies your second plot
 plot3 <- ggplot(...) # this specifies your third plot

 #merge all three plots within one grid (and visualize this)
 grid.arrange(plot1, plot2, plot3, nrow=3) #arranges plots within grid

 #save
 ggsave <- ggplot2::ggsave; body(ggsave) <- body(ggplot2::ggsave)[-2]

The above line needed to fix the error

 g <- arrangeGrob(plot1, plot2, plot3, nrow=3) #generates g
 ggsave(file="whatever.pdf", g) #saves g

Now it works for me fine.

Community
  • 1
  • 1
docjg
  • 99
  • 1
  • 2
  • I needed this. Apparently the development version of ggplot2 removes the class-test-fault like this, but the CRAN version currently (2015-10-21) does not. – Dave X Oct 21 '15 at 17:47
  • 2
    This works with marrangeGrob for me but not with arrangeGrob or grid.arrange.@DaveX, did you need to do anything else to make it work besides modifying ggsave as shown above? Thanks! – k13 Oct 23 '15 at 03:16
4

try this

ggsave("whatever.png", plot=grid.arrange(plot1, plot2, plot3, nrow=3), device=..., scale = ..., width =..., height = ..., units = "...", dpi = ...)
  • When I use this, with scale = 1 there isa corner cut off on the far right side. Is there any way to avoid this problem? Scaling down to .9 does not help :( – canIchangethis Nov 14 '22 at 18:00
2

Another simple solution: just after your grid.arrange()

grid.arrange(plot1, plot2, plot3, nrow=3)

you do a dev.copy()

dev.copy(pdf,"whatever.pdf")
dev.off()
TeYaP
  • 303
  • 6
  • 21