How can I arrange an arbitrary number of plots using grid.arrange?

1,135 views
Skip to first unread message

Brian Danielak

unread,
Jul 13, 2011, 10:59:02 AM7/13/11
to ggp...@googlegroups.com
My situation is that I'm working on a function that outputs an arbitrary number of plots (depending upon the input data supplied by the user). The function returns a list of n plots, and I'd like to lay those plots out in 2 x 2 formation. I'm struggling with the simultaneous problems of:
  1. How can I allow the flexibility to be handed an arbitrary (n) number of plots?
  2. How can I also specify I want them laid out 2 x 2
My current strategy uses grid.arrange from the gridExtra package. It's probably not optimal, especially since, and this is key, it totally doesn't work. Here's my commented sample code, experimenting with three plots:

library(ggplot2)
library(gridExtra)

x <- qplot(mpg, disp, data = mtcars)
y <- qplot(hp, wt, data = mtcars)
z <- qplot(qsec, wt, data = mtcars)

# Calling grid.arrange works great
grid.arrange(x, y, z)

# For my purposes, I need a 2 x 2 layout, and the command below works fine
grid.arrange(x, y, z, nrow = 2, ncol = 2)

# The problem is that the function I'm developing outputs a LIST of an arbitrary
# number plots, and I'd like to be able to plot every plot in the list on a 2 x 2
# laid-out page. I can at least plot a list of plots by constructing a do.call()
# expression, below. (Note: it totally even surprises me that this do.call expression
# DOES work. I'm astounded.)
plot.list <- list(x, y, z)
do.call(grid.arrange, plot.list)

# But now I need 2 x 2 pages. No problem, right? Since do.call() is taking a list of
# arguments, I'll just add my grid.layout arguments to the list. Since grid.arrange is
# supposed to pass layout arguments along to grid.layout anyway, this should work.
args.list <- c(plot.list, "nrow = 2", "ncol = 2")

# Except that the line below is going to fail, producing an "input must be grobs!"
# error
do.call(grid.arrange, args.list)

Ben Bolker

unread,
Jul 13, 2011, 11:04:34 AM7/13/11
to ggp...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 07/13/2011 10:59 AM, Brian Danielak wrote:
> My situation is that I'm working on a function

> <https://github.com/briandk/granova/blob/dev/R/granova.contr.ggplot.R>


> that outputs an arbitrary number of plots (depending upon the input data
> supplied by the user). The function returns a list of n plots, and I'd
> like to lay those plots out in 2 x 2 formation. I'm struggling with the
> simultaneous problems of:
>

> 1. How can I allow the flexibility to be handed an arbitrary (n)
> number of plots?
> 2. How can I also specify I want them laid out 2 x 2


>
> My current strategy uses grid.arrange from the gridExtra package. It's

> probably not optimal, especially since, and this is key, it /totally
> doesn't work/. Here's my commented sample code, experimenting with three

Have you tried

args.list <- c(plot.list, list(nrow=2, ncol=2)) ...


?
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk4dtAIACgkQc5UpGjwzenNhCwCfSGH8B7uQSJZcUS5snjqjElbt
rKkAn1RpvFBGdZoGbtkrDBmb52MCGnhr
=SJzf
-----END PGP SIGNATURE-----

Adam_L...@keybank.com

unread,
Jul 13, 2011, 11:09:17 AM7/13/11
to ggp...@googlegroups.com, Brian Danielak

This works for me:

function(plt, nrow, ncol)
{
loops <- ceiling(length(plt) / (nrow * ncol))
p <- 1
for (l in 1:loops) {
grid.newpage()
pushViewport(viewport(layout=grid.layout(nrow, ncol)))
for (r in 1:nrow) for (c in 1:ncol) {
if (p > length(plt)) break
print(plt[[p]], vp=viewport(layout.pos.row=r, layout.pos.col=c))
p <- p + 1
}
}}

In your case, nrow and ncol are each 2. I guess you'd need some ggsave logic as well.  



Adam Loveland





Brian Danielak <brian.d...@gmail.com>
Sent by: ggp...@googlegroups.com

07/13/2011 10:59 AM

Please respond to
ggp...@googlegroups.com

To
ggp...@googlegroups.com
cc
Subject
How can I arrange an arbitrary number of plots using grid.arrange?





My situation is that I'm working on a function that outputs an arbitrary number of plots (depending upon the input data supplied by the user). The function returns a list of n plots, and I'd like to lay those plots out in 2 x 2 formation. I'm struggling with the simultaneous problems of:
1.        How can I allow the flexibility to be handed an arbitrary (n) number of plots?
2.        How can I also specify I want them laid out 2 x 2
My current strategy uses grid.arrange from the gridExtra package. It's probably not optimal, especially since, and this is key, it totally doesn't work. Here's my commented sample code, experimenting with three plots:

library(ggplot2)
library(gridExtra)

x <- qplot(mpg, disp, data = mtcars)
y <- qplot(hp, wt, data = mtcars)
z <- qplot(qsec, wt, data = mtcars)

# Calling grid.arrange works great
grid.arrange(x, y, z)

# For my purposes, I need a 2 x 2 layout, and the command below works fine
grid.arrange(x, y, z, nrow = 2, ncol = 2)

# The problem is that the function I'm developing outputs a LIST of an arbitrary
# number plots, and I'd like to be able to plot every plot in the list on a 2 x 2
# laid-out page. I can at least plot a list of plots by constructing a do.call()
# expression, below. (Note: it totally even surprises me that this do.call expression
# DOES work. I'm astounded.)
plot.list <- list(x, y, z)
do.call(grid.arrange, plot.list)

# But now I need 2 x 2 pages. No problem, right? Since do.call() is taking a list of
# arguments, I'll just add my grid.layout arguments to the list. Since grid.arrange is
# supposed to pass layout arguments along to grid.layout anyway, this should work.
args.list <- c(plot.list, "nrow = 2", "ncol = 2")

# Except that the line below is going to fail, producing an "input must be grobs!"
# error
do.call(grid.arrange, args.list)

--
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



This communication may contain privileged and/or confidential information. It
is intended solely for the use of the addressee. If you are not the intended
recipient, you are strictly prohibited from disclosing, copying, distributing
or using any of this information. If you received this communication in error,
please contact the sender immediately and destroy the material in its entirety,
whether electronic or hard copy. This communication may contain nonpublic personal
information about consumers subject to the restrictions of the 
Gramm-Leach-Bliley Act. You may not directly or indirectly reuse or redisclose
such information for any purpose other than to provide the services for which
you are receiving the information.

127 Public Square, Cleveland, OH 44114



If you prefer not to receive future e-mail offers for products or services from Key
send an e-mail to mailto:DNERe...@key.com with 'No Promotional E-mails' in the
SUBJECT line.

Brian Danielak

unread,
Jul 13, 2011, 11:19:17 AM7/13/11
to ggp...@googlegroups.com
On Wed, Jul 13, 2011 at 11:04 AM, Ben Bolker <bbo...@gmail.com> wrote:
Have you tried

 args.list <- c(plot.list, list(nrow=2, ncol=2)) ...

Ben,

That totally works, though this does not:

args.list <- c(plot.list, list("nrow=2", "ncol=2"))

So now I have two questions:
  1. Is it obvious I should have been passing an additional LIST for those grid.layout arguments?
  2. Why do they work bare, but not as strings?
Also, feel free to post this answer on StackOverflow and I'll accept it.

- B

baptiste auguie

unread,
Jul 13, 2011, 8:38:04 PM7/13/11
to ggp...@googlegroups.com
Hi,

Try this,


require(ggplot2)
require(gridExtra)
plots = llply(1:11, function(.x) qplot(1:10,rnorm(10),
main=paste("plot",.x)))

params <- list(nrow=2, ncol=2)

n <- do.call(prod, params)
pages <- length(plots) %/% n + as.logical(length(plots) %% n)

groups <- split(seq_along(plots), gl(pages, n, length(plots)))

print(groups)
for (g in groups){
dev.new()
do.call(grid.arrange, c(plots[g], params))
}


[cross-posted from SO for completeness]

HTH,

baptiste

Reply all
Reply to author
Forward
0 new messages