duHaas
duHaas

Reputation: 428

Unexpected for loop behavior passing ggplot2 parameters to a list

So I've looked at a few other questions related to this: Storing Plot Objects in a List; Store Plots in List in Loop to produce a list of ggplot2 objects.

I was trying a for loop to create and assign ggplot2 parameters to a list that I could call later to create a grid of graphs.

Time <- as.POSIXct(origin="1970-01-01",seq(1522461060,1522467000,by=60),tzone="UTC")
P <- abs(rnorm(100,0.0028,sd=0.038))
Qmin <- abs(rnorm(100,0.007,0.0021))
RE.24hr <- sort(rep(1:20,5))
dt1 <- data.table(Time,P,Qmin,RE.24hr)

require(ggplot2)
require(data.table)

REL <- max(dt1$RE.24hr)
hydl <- list()
maxp <- max(dt1$P); maxq <- max(dt1$Qmin,na.rm=T)
i <- 1

My for loop ends up with NULL being assigned to all but the last entry of the list:

for(i in REL){
mydata <- subset(dt1,RE.24hr==i)
  hydl[[i]] <- ggplot(mydata,aes(x=Time)) + geom_line(aes(y=Qmin),colour='blue') + 
    geom_line(aes(y=P*10)) + scale_y_continuous(limits=c(0,maxp*10),sec.axis = sec_axis(~./10,name="Precip [m]")) + 
    theme_bw() + theme(axis.title=element_blank()) 
  plot(hydl[[i]])
}
do.call(grid.arrange, c(hydl, ncol = 5))

However, when I switched to a while loop logic the code executed as expected:

while(i <= REL){
  mydata <- subset(dt1,RE.24hr==i)
  hydl[[i]] <- ggplot(mydata,aes(x=Time)) + geom_line(aes(y=Qmin),colour='blue') + 
    geom_line(aes(y=P*10)) + scale_y_continuous(limits=c(0,maxp*10),sec.axis = sec_axis(~./10,name="Precip [m]")) + 
    theme_bw() + theme(axis.title=element_blank()) 
  plot(hydl[[i]])
  i <- i + 1
}
do.call(grid.arrange, c(hydl, ncol = 5))

I am confused as to why switching the logical structure from a for loop to a while loop would change how assignment to a list is achieved. My best guess is that I'm overlooking a basic, fundamental coding principle.

R version 3.4.2 (2017-09-28) Platform: x86_64-w64-mingw32/x64 (64-bit) Running under: Windows 10 x64 (build 17134)

Upvotes: 0

Views: 91

Answers (2)

Parfait
Parfait

Reputation: 107642

Currently, in your for loop, you do not iterate across a sequence but just the final value. Simply start from 1 to REL.

for(i in 1:REL){
   ...
}

Nonetheless, consider lapply() to build list of plots without needing to initialize hydl and pass list directly into grid.arrange() without do.call():

hydl2 <- lapply(1:REL, function(i) {
  mydata <- subset(dt1, RE.24hr==i)
  ggplot(mydata, aes(x=Time)) + 
    geom_line(aes(y=Qmin),colour='blue') + geom_line(aes(y=P*10)) + 
    scale_y_continuous(limits=c(0,maxp*10), sec.axis = sec_axis(~./10,name="Precip [m]")) + 
    theme_bw() + theme(axis.title=element_blank())   
})

grid.arrange(grobs=hydl2, ncol=5)

Even consider by() (object-oriented wrapper to tapply) and bypass the need for subset as it subsets your data table by all unique factors of RE.24hr:

hydl3 <- by(dt1, dt1$RE.24hr, function(mydata) {
  ggplot(mydata, aes(x=Time)) + 
    geom_line(aes(y=Qmin),colour='blue') + geom_line(aes(y=P*10)) + 
    scale_y_continuous(limits=c(0,maxp*10), sec.axis = sec_axis(~./10,name="Precip [m]")) + 
    theme_bw() + theme(axis.title=element_blank()) 
})

grid.arrange(grobs=hydl3, ncol=5)

Finally, as commented, simply use facet_wrap to handle the multiple sliced plots. Design will be different though.

ggplot(dt1, aes(x=Time)) + geom_line(aes(y=Qmin),colour='blue') + 
  geom_line(aes(y=P*10)) + scale_y_continuous(limits=c(0,maxp*10),sec.axis = sec_axis(~./10,name="Precip [m]")) + 
  theme_bw() + theme(axis.title=element_blank()) + 
  facet_wrap(~RE.24hr, ncol=5, scales="free") 

Plot Output

Upvotes: 2

B Williams
B Williams

Reputation: 2050

Not sure why you would loop this instead of simply using dplyr and tweaking the figures as needed a la:

df <- data.frame(Time = as.POSIXct(origin="1970-01-01",
                                  seq(1522461060,1522467000, by=60), tzone="UTC"),
             P = abs(rnorm(100,0.0028, sd=0.038)),
             Qmin = abs(rnorm(100, 0.007, 0.0021)),
             RE.24hr = sort(rep(1:20, 5)))

df %>% 
  ggplot(aes(Time, P)) + geom_line(color = 'blue') + 
    geom_line(aes(Time, Qmin * 10)) +
    facet_wrap(~RE.24hr, scales = 'free_x')

Upvotes: 2

Related Questions