Multiple Plot Layout

295 views
Skip to first unread message

Nick S

unread,
Jul 2, 2010, 8:33:52 PM7/2/10
to ggplot2
I am working on a script to iterate through the columns in a
data.frame and store/assign the instructions to plot an image to a
unique variable (p1,p2,...etc.). I will then pass these variables to
the assign() function (from the gridExtra package) as a comma
separated list (ex: assign(p1,p2,p3...etc)) in order to generate a
multiplot layout.

The problem I am encountering is that I need to create and store 96
unique variables. I am trying to find a "smart" way to create and
store these variables in a loop (since I need 96 of them).

I have tried creating a list of variable names and then iterating
through the elements in the list to assign graphical elements to. The
problem is that they are being passed as characters and not being
stored into memory by R.

Any advice on how best to achieve this list of unique variables that I
can then pass to the arrange function would be appreciated.

Example Data: (http://dl.dropbox.com/u/3734701/GOP.csv)

Example Code (doesn't work):

library(ggplot2)
library(gridExtra)
cols = 2:96
names = colnames(GOP)
plotVariables = paste(rep("p", 96),
sprintf("%02.0f",as.numeric(seq(1,96))), sep="") # result is a list
of the variables I want to use to assign each graph to
i=1
for(i in 1:length(cols)) {
xmin = GOP$Time[GOP[,cols[i]]==max(GOP[,cols[i]])]-10
xmax = GOP$Time[GOP[,cols[i]]==max(GOP[,cols[i]])]+5

if(length(xmin)>1){
xmin = xmin[1]
}
if(length(xmax)>1){
xmax = xmax[1]
}
p = ggplot(GOP,aes(x=Time,y=GOP[,cols[i]]))
plotVariables[i] = p + geom_line(size=0.05,colour="blue") +
ylim(min(GOP[,cols[i]]), max(GOP[,cols[i]])+100) +
xlim(xmin,xmax) +
labs(x="", y="") +
opts(title=paste(names[i+1])) +
opts(plot.title=theme_text(size=9)) +
opts(axis.text.x=theme_text(size=6)) +
opts(axis.text.y=theme_text(size=6)) +
opts(axis.title.y=theme_text(angle=90,size=8)) +
opts(axis.title.x=theme_text(size=8)) +
opts(axis.ticks=theme_blank())
}

arrange(p1,p2,p3,p4,p5)


Example Code (does work):

library(ggplot2)
library(gridExtra)
cols = 2:96
names = colnames(GOP)
plotVariables = paste(rep("p", 96),
sprintf("%02.0f",as.numeric(seq(1,96))), sep="")
i=1
for(i in 1:length(cols)) {
xmin = GOP$Time[GOP[,cols[i]]==max(GOP[,cols[i]])]-10
xmax = GOP$Time[GOP[,cols[i]]==max(GOP[,cols[i]])]+5

if(length(xmin)>1){
xmin = xmin[1]
}
if(length(xmax)>1){
xmax = xmax[1]
}
p = ggplot(GOP,aes(x=Time,y=GOP[,cols[i]]))
p1 = p + geom_line(size=0.05,colour="blue") +
ylim(min(GOP[,cols[i]]), max(GOP[,cols[i]])+100) +
xlim(xmin,xmax) +
labs(x="", y="") +
opts(title=paste(names[i+1])) +
opts(plot.title=theme_text(size=9)) +
opts(axis.text.x=theme_text(size=6)) +
opts(axis.text.y=theme_text(size=6)) +
opts(axis.title.y=theme_text(angle=90,size=8)) +
opts(axis.title.x=theme_text(size=8)) +
opts(axis.ticks=theme_blank())
p2 = p + geom_line(size=0.05,colour="blue") +
ylim(min(GOP[,cols[i]]), max(GOP[,cols[i]])+100) +
xlim(xmin,xmax) +
labs(x="", y="") +
opts(title=paste(names[i+1])) +
opts(plot.title=theme_text(size=9)) +
opts(axis.text.x=theme_text(size=6)) +
opts(axis.text.y=theme_text(size=6)) +
opts(axis.title.y=theme_text(angle=90,size=8)) +
opts(axis.title.x=theme_text(size=8)) +
opts(axis.ticks=theme_blank())
}

arrange(p1,p2)


Hadley Wickham

unread,
Jul 2, 2010, 8:50:10 PM7/2/10
to Nick S, ggplot2
Hi Nick,

Check out aes_string.

Hadley

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

--
Assistant Professor / Dobelman Family Junior Chair
Department of Statistics / Rice University
http://had.co.nz/

Nick S

unread,
Jul 2, 2010, 10:35:21 PM7/2/10
to ggplot2
Thanks for the reply Hadley.

I'm a little confused as to how aes_string() would apply in my case.
I don't want to change the mappings of variables for the geoms...I
just want to pass a list of variables to assign the output to.

Can you give an example using my code and aes_string()?

baptiste auguie

unread,
Jul 3, 2010, 4:32:41 AM7/3/10
to Nick S, ggplot2
Hi,

Is there a reason you don't want to use a data.frame in the long format?

As an example, you could do,


library(ggplot2)
library(gridExtra)

GOP <- read.csv("http://dl.dropbox.com/u/3734701/GOP.csv")

mgop <- melt(GOP, id="Time")
str(mgop)

commonopts <- opts(plot.title=theme_text(size=9),
axis.text.x=theme_text(size=6),
axis.text.y=theme_text(size=6),
axis.title.y=theme_text(angle=90,size=8),
axis.title.x=theme_text(size=8),
axis.ticks=theme_blank())

## function to generate one plot
plotone <- function(var, ...){

p = ggplot(subset(mgop, variable==var), aes(x=Time,y=value)) +
geom_line(size=0.05,colour="blue") +


labs(x="", y="") +

opts(title=var) +
commonopts
}


## loop over the variables and store all plots (5 in the example)
allplots <- llply(levels(mgop$variable)[1:5], plotone)

## optional, add parameters to be passed to arrange
plotsandoptions <- c(allplots, list(main="All the plots"))

do.call(arrange, plotsandoptions)


(I couldn't figure out what you were trying to do with the axes limits)

HTH,

baptiste

Hadley Wickham

unread,
Jul 3, 2010, 8:11:28 AM7/3/10
to Nick S, ggplot2
Maybe something else is going on, but from a quick scan of your code
the following is unlikely to work:

aes(x=Time,y=GOP[,cols[i]]])

The aesthetic mapping should contain variable names, not values. You
should instead do:

aes_string(x = "Time", y = cols[i])

Hadley

Dennis Murphy

unread,
Jul 3, 2010, 9:56:41 AM7/3/10
to baptiste auguie, Nick S, ggplot2, hadley wickham
Hi:

Firstly, this is a really good strategy to produce multiple plots of the same type - I'm
suitably impressed and am looking forward to using this in the near future. However, the OP has
96 variables in his data frame and the obvious question is how to get them all plotted in
a sensible fashion. Give that the plots appear to be periodograms, you want enough
space to be able to discern the peaks, and it doesn't make much sense to try to get them
all onto one page. This is a textbook example of why multiple page layouts for ggplot2
(and by extension, arrange()) would be a Good Thing. For example, you could easily
facet_wrap() twelve plots per page onto eight pages (e.g., one page per letter) or
perhaps eight plots per page over twelve pages (e.g., one page per number). Not to
be snarky, but this can be done straightforwardly in lattice with the layout = argument.

QOTD: Has any progress been made towards multiple page ggplot layouts since the
            topic was broached a few months ago on this list, and if so, would it be possible to
            illustrate it with an example, perhaps from this data frame?

BTW, most of the peaks occur between 20 and 25 (sec?), but two of them are distinct
outliers. To see this,

xx <- ddply(mgop, .(variable), summarise, peak = max(value), time = Time[which.max(value)])
ggplot(xx, aes(x = time, y = peak)) + geom_point()
subset(xx, time < 10)

   variable  peak     time
14      F02 -9034 1.027778
68      D09 -8916 1.072222

This is a way to bypass the 96 plots, I guess, but it may be of interest to the OP to have
all the plots for presentation purposes.

Thanks in advance for any insights,
Dennis

hadley wickham

unread,
Jul 3, 2010, 10:09:13 AM7/3/10
to Dennis Murphy, baptiste auguie, Nick S, ggplot2
On Sat, Jul 3, 2010 at 8:56 AM, Dennis Murphy <djm...@gmail.com> wrote:
> Hi:
>
> Firstly, this is a really good strategy to produce multiple plots of the
> same type - I'm
> suitably impressed and am looking forward to using this in the near future.
> However, the OP has
> 96 variables in his data frame and the obvious question is how to get them
> all plotted in
> a sensible fashion. Give that the plots appear to be periodograms, you want
> enough
> space to be able to discern the peaks, and it doesn't make much sense to try
> to get them
> all onto one page. This is a textbook example of why multiple page layouts
> for ggplot2
> (and by extension, arrange()) would be a Good Thing. For example, you could
> easily
> facet_wrap() twelve plots per page onto eight pages (e.g., one page per
> letter) or
> perhaps eight plots per page over twelve pages (e.g., one page per number).
> Not to
> be snarky, but this can be done straightforwardly in lattice with the layout
> = argument.

But it's so easy to do it without a layout method:

plotsome <- function(var, ...){
ggplot(subset(mgop, variable %in% var), aes(x=Time,y=value)) +
geom_line(size=0.05,colour="blue") +
facet_wrap(~ variable) +


labs(x="", y="") +
opts(title=var) +

theme_grey(8)
}

levels <- levels(mgop$variable)
letter <- substr(levels, 1, 1)

allplots <- llply(split(levels, letter), plotsome)
# OR
l_ply(split(levels, letter), plotsome, .print = T)

And that way you have total flexibility.

Hadley

Hadley Wickham

unread,
Jul 3, 2010, 10:15:36 AM7/3/10
to Aaron Mackey, Nick S, ggplot2
On Sat, Jul 3, 2010 at 9:13 AM, Aaron Mackey <ama...@virginia.edu> wrote:
> just an aside, but I frequently put data/values in aes(), particularly when
> I'm overlaying geoms on top of one another (when the values are not all in
> the same data frame), and it seems to work just fine:
>
> x <- c(1:10)+rnorm(10)
> qplot(x, sample(x)) + geom_smooth(aes(x=1:3, y=1:3), stat="identity")
>
> am I not supposed to do this (is there some other preferred method to
> accomplish same)?

Definitely don't do this - it will work in simple cases, but will
invoke R's recycling rules in more complex cases, so errors may be
silently ignored. The preferred way is to create a new data frame and
then use the data argument to the layer.

Hadley

Aaron Mackey

unread,
Jul 3, 2010, 10:13:48 AM7/3/10
to Hadley Wickham, Nick S, ggplot2
just an aside, but I frequently put data/values in aes(), particularly when I'm overlaying geoms on top of one another (when the values are not all in the same data frame), and it seems to work just fine:

x <- c(1:10)+rnorm(10)
qplot(x, sample(x)) + geom_smooth(aes(x=1:3, y=1:3), stat="identity")

am I not supposed to do this (is there some other preferred method to accomplish same)?

-Aaron

Dennis Murphy

unread,
Jul 3, 2010, 10:37:30 AM7/3/10
to hadley wickham, ggplot2
Hi:

Why didn't you just say that in the first place? :)

Thanks for the lesson (and message received),
Dennis

Nick S

unread,
Jul 3, 2010, 3:52:30 PM7/3/10
to ggplot2
Thank you all for your suggestions!

It is quite interesting to see the way different people approach the
same problem. I will take the examples that were given and try to
expand on them for my needs.

On Jul 3, 7:37 am, Dennis Murphy <djmu...@gmail.com> wrote:
> Hi:
>
> Why didn't you just say that in the first place? :)
>
> Thanks for the lesson (and message received),
> Dennis
>
>
>
> On Sat, Jul 3, 2010 at 7:09 AM, hadley wickham <h.wick...@gmail.com> wrote:

hadley wickham

unread,
Jul 4, 2010, 9:26:22 AM7/4/10
to Nick S, ggplot2
> I have two questions though...what is the best way to have the output
> for each group get dumped into it's own window? Currently...the graphs
> are being sequentially overwritten as they are being output.

Add dev.new() before each call

> I would also like to save each output to an image file as it is
> cycling through the groups and plotting them.

Add ggsave() after each call.

Juliet Hannah

unread,
Oct 3, 2010, 10:36:54 PM10/3/10
to baptiste auguie, ggplot2
Hi Baptiste,

I was trying to work through this older post written by you from July,
and I was unable to get it to run. Any suggestions on what I may be
doing incorrectly. The error I get is:

> do.call(arrange, plotsandoptions)

Error in rank(x, ties.method = "min", na.last = "keep") :
unimplemented type 'list' in 'greater'

Nick (the OP) had sent me a new data link, and your example is pasted
below my sessionInfo.

> sessionInfo()
R version 2.11.1 (2010-05-31)
i386-pc-mingw32

locale:
[1] LC_COLLATE=English_United States.1252 LC_CTYPE=English_United
States.1252 LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C LC_TIME=English_United
States.1252

attached base packages:
[1] grid stats graphics grDevices utils datasets
methods base

other attached packages:
[1] gridExtra_0.7 ggplot2_0.8.8 proto_0.3-8 reshape_0.8.3 plyr_1.1

### start example

library(ggplot2)
library(gridExtra)

mgop <- melt(GOP, id="Time")

commonopts <- opts(plot.title=theme_text(size=9),


axis.text.x=theme_text(size=6),
axis.text.y=theme_text(size=6),
axis.title.y=theme_text(angle=90,size=8),
axis.title.x=theme_text(size=8),
axis.ticks=theme_blank())

## function to generate one plot
plotone <- function(var, ...){

p = ggplot(subset(mgop, variable==var), aes(x=Time,y=value)) +
geom_line(size=0.05,colour="blue") +
labs(x="", y="") +
opts(title=var) +
commonopts
}


## loop over the variables and store all plots (5 in the example)
allplots <- llply(levels(mgop$variable)[1:5], plotone)

## optional, add parameters to be passed to arrange
plotsandoptions <- c(allplots, list(main="All the plots"))

do.call(arrange, plotsandoptions)

Dennis Murphy

unread,
Oct 4, 2010, 7:42:22 AM10/4/10
to Juliet Hannah, baptiste auguie, ggplot2
Hi Juliet:

Use grid.arrange() rather than arrange().

HTH,
Dennis

baptiste auguie

unread,
Oct 5, 2010, 4:04:29 AM10/5/10
to Juliet Hannah, ggplot2
Hi,

as Dennis said, arrange() was renamed grid.arrange() after plyr
introduced its own arrange() function (unrelated, but which throws the
confusing error message you got).

Best,

baptiste

Reply all
Reply to author
Forward
0 new messages