Reputation: 428
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
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")
Upvotes: 2
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