Saving a grid plot

385 views
Skip to first unread message

Paul Metzner

unread,
Sep 16, 2011, 8:02:07 AM9/16/11
to ggp...@googlegroups.com
Hi all!

I know that there's already several threads covering how to save grid plots. However, pdf() doesn't do it for me. If I create a number of plots and arrange them with the following code, I get something like this: http://dl.dropbox.com/u/6281903/is.png

> vplayout <- function(x, y, ...){
> viewport(layout.pos.row = x, layout.pos.col = y, ...)
> }
>
> pdf('plot.pdf')
>
> grid.newpage()
> pushViewport(viewport(layout = grid.layout(length(plots), 1)))
>
> for(i in 1:length(plots)){
> print(plots[[i]], vp = vplayout(i, 1))}
> }
>
> dev.off()

If I resize that plot in a Quartz window and save it manually, it looks like it should: http://dl.dropbox.com/u/6281903/should.png. Does anybody have an idea how I can accomplish this automatically? The reason why I have to use grids is that I have several subplots with different numbers of facets.
On a sidenote, it would be great if I could solve my problem with just ggplot2 by giving facet_wrap() a matrix that contains the number of columns in each row, e.g. ncol = c(3, 5, 4, 5, ...).

Best,
Paul

Brandon Hurr

unread,
Sep 16, 2011, 8:22:15 AM9/16/11
to Paul Metzner, ggp...@googlegroups.com
Have you played with the  width and height or dpi settings in the pdf()?

Previously I've set up if/then statements that detect the size of the output and adjust these settings in my ggsave() call. I haven't used grid much so this is mostly a guess and I don't have a working example to play with. 


On a sidenote, it would be great if I could solve my problem with just ggplot2 by giving facet_wrap() a matrix that contains the number of columns in each row, e.g. ncol = c(3, 5, 4, 5, ...).
This indeed would be nice. I've wanted this for a long time too, but only come across it now and then. I've used factor ordering to get around this. I think you could do a blank plot to space things out, but it would look weird with empty plots all over. Perhaps someone knows how to do this? 

Paul Metzner

unread,
Sep 16, 2011, 8:46:06 AM9/16/11
to Brandon Hurr, ggp...@googlegroups.com
> Have you played with the width and height or dpi settings in the pdf()?

Yes, and the problem persists, all plots get stretched to the same width again.

> Previously I've set up if/then statements that detect the size of the output and adjust these settings in my ggsave() call. I haven't used grid much so this is mostly a guess and I don't have a working example to play with.

Another idea might be to save all subplots seperately with ggsave and stitch them together with ghostscript or LaTeX. How do I determine the size of the output?

> I think you could do a blank plot to space things out, but it would look weird with empty plots all over.


It would, but maybe I could use theme_blank() for the placeholder plots.

Paul

Brandon Hurr

unread,
Sep 17, 2011, 4:45:24 AM9/17/11
to Paul Metzner, ggp...@googlegroups.com
I'm hoping someone who knows more about grid will be able to help. Hadley and Baptiste are pretty good at it. 

baptiste auguie

unread,
Sep 17, 2011, 6:10:01 AM9/17/11
to Paul Metzner, Brandon Hurr, ggp...@googlegroups.com
Hi,

On Sat, Sep 17, 2011 at 12:46 AM, Paul Metzner <paul.m...@gmail.com> wrote:
>> Have you played with the  width and height or dpi settings in the pdf()?
>

> Yes, and the problem persists, all plots get stretched to the same width again.

That's what I saw too, but not what you show in the image file
http://dl.dropbox.com/u/6281903/is.png?
I came up with the following code as a reproducible example, and an
attempt to arrange the plots with approximately equal panel widths,


library(ggplot2)

## made up data
dd <- function(){

nfacets <- sample(1:10,1)
d <- data.frame(x = rnorm(10), matrix(rnorm(10*nfacets), ncol=nfacets))
names(d) <- c("x", letters[seq_len(nfacets)])
melt(d, id="x")
}

## plot
pp <- function(x, maxfacets=10){
ggplot(x) + facet_grid(.~variable)+
geom_path(aes(x, value))
}

## made up plots
set.seed(123)
d <- rlply(4, dd)
p <- llply(d, pp)


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

pdf('plot.pdf')
grid.newpage()
pushViewport(viewport(layout = grid.layout(length(p), 1)))

## how many cols per plot
findNumber <- function(x){
g <- ggplot_build(x)
nrow(g$facet$facet_levels)
}
cols <- sapply(p, findNumber)

## scaling factor for the plot widths
factors <- cols / max(cols)
for(i in 1:length(p)){
## push a viewport in the right row
pushViewport(vp=vplayout(i, 1))
## print the plot in a viewport with constrained width
## (5 lines offset for the axis lab etc.)
print(p[[i]], vp = viewport(width=factors[i]*(unit(1, "npc") -
unit(5,"lines")) + unit(5,"lines")))
upViewport()
}
upViewport()
dev.off()


the 5 lines offset is obviously quite arbitrary. Also, I'm not sure
how one should implement the function findNumber(); this one worked
for me using ggplot2_0.8.9.

HTH,

baptiste

> --
> You received this message because you are subscribed to the ggplot2 mailing list.
> Please provide a reproducible example: http://gist.github.com/270442
>
> To post: email ggp...@googlegroups.com
> To unsubscribe: email ggplot2+u...@googlegroups.com
> More options: http://groups.google.com/group/ggplot2
>

Paul Metzner

unread,
Sep 23, 2011, 3:14:16 AM9/23/11
to baptiste auguie, Brandon Hurr, ggp...@googlegroups.com
Hi,

thanks for all the suggestions! When I tried Baptistes solution with my plots, they came out too narrow, as well. I thus figured that the plots themselves must be the problem and shrunk all opts to a minimum (axis.text.x, axis.text.y, strip.background, etc.). It works now, the final code is this (plots is a list with ggplot2 objects):

> grid.newpage()
> pushViewport(viewport(layout = grid.layout(length(plots), 1)))
>

> cols <- sapply(plots, findNumber)


> factors <- cols / max(cols)
>

> for(i in 1:length(plots)){
> h <- unit(1, 'npc')
> w <- factors[i] * unit(1, 'npc')
> if(i < length(plots)){
> print(plots[[i]] + opts(legend.position = 'none'),
> vp = vplayout(i, 1, width = w, height = h))}
> else {
> print(plots[[i]], vp = vplayout(i, 1, width = w, height = h))}
> }

Best,
Paul

Reply all
Reply to author
Forward
0 new messages