0

I have a for loop producing a series of plots and want to plot each one to a file, such as in this answer. The problem is that I don't actually create a new plot every new iteration, but insert an overlapping line on the existing canvas. The code and error are exemplified below:

   for(i in 1:10){
        png(filename = paste0("~/image", i))
        if(i == 1){
             plot(runif(10))
        }else{
             lines(runif(10))
        }
        dev.off()
   }

error message:

Error in plot.xy(xy.coords(x, y), type = type, ...) : 
  plot.new has not been called yet

I understand that it is because the canvas e not recreated, but do not know how to overcome this issue. I have tried using dev.print() with no success either.

Lara
  • 89
  • 7

2 Answers2

1

Currently you're creating a new png device on every iteration of the loop. You need to move things around a bit so that the device is created and then turned off outside of the loop, because you only need each to happen once:

png(filename = paste0("~/image", 1))
for(i in 1:10) {
    if(i == 1) {
         plot(runif(10))
    } else {
         lines(runif(10))
    }
}
dev.off()
Marius
  • 58,213
  • 16
  • 107
  • 105
  • Might as well put the `plot` call before the loop and drop the conditional – alistaire Jun 05 '19 at 01:30
  • The thing is I want to output an image for each "state" of the plot, such as the initial image with only one line, the second with the previous line and the new one, and so on. I corrected the piece of code to make this idea clearer – Lara Jun 05 '19 at 10:38
0

In response to the revised question, here's a couple of solutions. To save a series of images files with the lines added in succession, dev.print can be used. You do have to add more details to the call. Here's a solution in the spirit of your logic:

for (i in 1:10) {
  if (i == 1)
    plot(runif(10)) # this could have inadequate y-limits 
  else {
    lines(runif(10))
  }
  fn <- paste0("~/image", i, ".png")
  dev.print(png, fn, width = 5, height = 5, unit = "in", res = 96)
}

If the results could be acquired before printing, you don't have to guess the limits of the plot. Here is a solution that allows the use png() where the data are generated (or acquired) first.

v <- replicate(10, runif(10), simplify = FALSE)

for (i in seq_along(v)) {
  png(paste0("~/image", i, ".png"))
  plot(v[[1]], ylim = range(v))
  lapply(seq_len(i)[-1], function(j) lines(v[[j]]))
  dev.off()
}
David O
  • 803
  • 4
  • 10