user1420372
user1420372

Reputation: 2187

Saving plots in R within a loop

Yesterday I upgraded R to version 3.0.0 and ggplot2 to version 0.9.3.1 (and made a few minor changes to my script). Now I am getting errors when attempting to save plots - unfortunately the error is not reproduced with a smaller dataframe, so I have included code to generate one of the same size.

library("ggplot2")

# Create data frame
# Time interval ID (x)
bin.ts.avg <- as.data.frame(rep(1:18, 31))
names(bin.ts.avg) <- "x"
# Time (sequence of 10 minuter intervals between 7am and 10am)
tt.month.bins <- seq(from=as.POSIXct("2012-01-01 GMT"), to=as.POSIXct("2012-01-01 GMT") + 60*60*24*31, by="10 mins")
tt.month.bins <- tt.month.bins[-length(tt.month.bins)]
temp <- as.numeric(format(tt.month.bins, "%H"))
ind <- which(temp >=7 & temp <= 9)  
tt.month.bins <- tt.month.bins[ind]
bin.ts.avg$dep <- tt.month.bins
# Value (with some NA)
bin.ts.avg$tt <- runif(558, min=2.5, max=5)
bin.ts.avg$tt[trunc(runif(200, min=1, max=558))] <- NA
# Day
bin.ts.avg$depday <- rep(1:31, each=18)

for (i in 1:2){
  if (1){
    hist(rnorm(100))
    dev.print(file="MyHist.png",device=png, bg="white",  width=640, height=352) 

    p <- ggplot(bin.ts.avg, aes(x, tt)) + geom_point() +geom_line() + facet_grid(.~depday)
    p <- p + ggtitle("10 minute averages")+ xlab("Hour") + ylab("Values")    
    p <- p + scale_x_continuous(breaks=c(min(bin.ts.avg$x), max(bin.ts.avg$x)), labels=c("7", "10"))
    print(p)  
    dev.print(file="MyGGPlot.png",device=png, bg="white",  width=640, height=352) 
  }
}

On running this script, I receive the following error message:

Error in UseMethod("depth") : no applicable method for 'depth' applied to an object of class "NULL"

However, if I run the script line by line everything runs okay (picture below). How the ggplot should look Now if I change the for loop and use dev.copy and ggsave instead of dev.print as below

for (i in 1:2){
  if (1){
    hist(rnorm(100))
    dev.copy(file="MyHist.png",device=png, bg="white",  width=640, height=352) 
    dev.off()

    p <- ggplot(bin.ts.avg, aes(x, tt)) + geom_point() +geom_line() + facet_grid(.~depday)
    p <- p + ggtitle("10 minute averages")+ xlab("Hour") + ylab("Values")    
    p <- p + scale_x_continuous(breaks=c(min(bin.ts.avg$x), max(bin.ts.avg$x)), labels=c("7", "10"))
    print(p)  
    ggsave(filename="MyGGPlot.png")
  }
}

On attempting to open "MyGGPlot.png" using Paint, I receive an error message stating

A sharing violation occurred while accessing <filename>

I run the script using RStudio version 0.97.449. Any ideas on what I need to change in order to save current plots?

Upvotes: 7

Views: 14971

Answers (1)

mnel
mnel

Reputation: 115382

A couple of points

Use graphics.off() after dev.copy. This will close all graphics devices. You could also call dev.off() twice (but graphics.off() is a wrapper that will basically call dev.off() sufficient times to close all graphics devices

ggsave doesn't require a printed object (this is not a case where FAQ 7.22 is relevant).

The default is the value of last_plot which is the last ggplot object created, modified or printed. So creating p is sufficient for ggsave('filname.png') to save that object.

for (i in 1:2){
  if (1){
    hist(rnorm(100))
    dev.copy(file="MyHist.png",device=png, bg="white",  width=640, height=352) 
    graphics.off()

    p <- ggplot(bin.ts.avg, aes(x, tt)) + geom_point() +geom_line() + facet_grid(.~depday)
    p <- p + ggtitle("10 minute averages")+ xlab("Hour") + ylab("Values")    
    p <- p + scale_x_continuous(breaks=c(min(bin.ts.avg$x), max(bin.ts.avg$x)), labels=c("7", "10"))
   # no need to print p
   ggsave(filename="MyGGPlot.png")
   # note specifying p is redundant but explicit.
   # ggsave(filename = 'MyGGplot.png', plot = p)
  }
}

Upvotes: 12

Related Questions