Skip to Content

R save images to create animation of plot incrementally generated with large number of points

I'm trying to create an animation based on a scatter plot that is incrementally built up over time. The use case is that I have a database of about 2 million points with timestamps for each, and want to generate frames that show all the points at or before a specific date.

Without saving the images, I'm able to do this by first calling plot(), and then having a for loop that incrementally draws the data for each successive day using the points() function.

When I try to save images using the code below, I get an error of "plot.new has not been called yet". As I understand, dev.off() is needed to save image, but that also closes the device that is being drawn to. Is there a way to get around this? Having to re-plot the data for every frame isn't much of an option due to the size of the data.

plot(info$lon, info$lat, xlim=c(0,30), ylim=c(30,60))
for (i in c(1:length(allDates))){
    filename=paste(sprintf('%05d', i), ".png", sep="")  
    png(filename=fileName)
    # (code that gets the data for a particular date via a database query)
    points(info$lon, info$lat, cex=0.1)
    dev.off()
}

UPDATE:
The comment by @roman-lustrik about ggsave() was what I was looking for, and results in the code below:

plotObj = ggplot(...) + geom_point() + xlim(...) + ylim(...)
for (i in c(1:length(allDates))){
    filename=paste(sprintf('%05d', i), ".png", sep="")  
    # (code that gets the data for a particular date via a database query)
    plotObj = plotObj + geom_point(data=info, aes(x=lon, y=lat), size=0.5)
    print(plotObj)
    ggsave(filename=filename, width=6, height=6)
}

However, this is still a bit slow, so my current solution to render images quickly is to use the code similar to the original, but where I just use plot() to render frames with data for a single date (using a transparent background). To progressively stack up the images, I then use a bash script which uses the imagemagick convert -composite command to blend two images together. This blended image is then blended with the image from the next date, and so on, until the final image shows all of the data:

#!/bin/bash
for i in $files
do
    convert $prevFile $i -composite ./stackedImages/$i
    prevFile=./stackedImages/$i
done