Search code examples
rloopsanimated-gif

Looping to Save Each Dataframe Row Plot for ImageMagik


To minimize 3rd party package dependencies & reserve the ability to parallelize the code; this reproduceable example below is intended to create png images for each row step of a plot using R's Base graphics (no Tidyverse or GGPlot).

It, however, produces the entire series for each image, & not the intended iterative build required:

# 
setwd("///images") 
data(mtcars) # load DF 

frames = 50 # set image qty rate 

for(i in 1:frames){
 # creating a name for each plot file with leading zeros
 if (i < 10) {name = paste('000',i,'plot.png',sep='')}
 if (i < 100 && i >= 10) {name = paste('00',i,'plot.png', sep='')}
 if (i >= 100) {name = paste('0', i,'plot.png', sep='')} 
 png(name) 
 # plot(mtcars$mpg,type="l") 
 plot(mtcars$mpg)
 dev.off() 
} 

my_cmd <- 'convert *.png -delay 5 -loop 5 mpg.gif'
system(my_cmd) 
# 

My own attempts to unsuccessfully resolve the issue include:

1) Remove the frame iteration & used nrows (mtcars) as the loop controlling agent? 2) Reference the row index somehow for each plot call? 3) Insert a sleep() call inside the loop after each plot? 4) Use the apply() function instead of a loop?

Any pointers or alternative coding to be more R efficient to make this work as intended?

Thanks.


Solution

  • This code will create one .png file for series of plots where each successive plot has one additional point on it:

    # load data
    data(mtcars)
    
    # specify number of files to create (one per row of mtcars)
    frames <- nrow(mtcars)
    
    # figure out how many leading zeros will be needed in filename
    ndigits <- nchar(as.character(frames))
    for(i in 1:frames){
        # name each file
        zeros <- ndigits - nchar(as.character(i))
        ichar <- paste0(strrep('0',zeros), i)
        name  <- paste0(ichar, 'plot.png')
        # plot as .png
        png(filename = name)
        plot(x=1:i, y=mtcars$mpg[1:i], pch=20, col="blue",
             xlim=c(0,frames), ylim=range(mtcars$mpg))
        dev.off() 
    }