Sujay
Sujay

Reputation: 87

combine multiple plots to a gif

Im trying to use the caTools package to combine multiple plots into a gif.

My basic code looks like :

 for( i in 1:100){
     plot(....) // plots few points and lines, changes slightly with each i
  }

I would like to combine these to a gif to see the "evolution" of the plot.

However for write.gif() from caTools, I need to give an image as an input. For each i, how do I convert the plot into an image without

  1. saving to disc as an intermediate step
  2. depending on ImageMagick or similar external dependencies.

Please feel free to point out if this is a duplicate. [ Creating a Movie from a Series of Plots in R doesnt seem to answer this ]

EDIT: Basically this requires us to convert a plot to a matrix. Since this very likely happens every time someone saves a plot, it should not be very difficult. However Im not able to get hold of how to exactly do this.

Upvotes: 4

Views: 7952

Answers (3)

Nova
Nova

Reputation: 5861

I liked @ttlngr's answer but I wanted something a bit simpler (it still uses ImageMagick).

saveGIF({
  for (i in 1:10){  
    a <- ggplot(df[1:i,], aes(a,b)) + 
      geom_point() + 
      scale_x_continuous(limits=c(0,10)) +
      scale_y_continuous(limits=c(0,10))
  print(a)}
}, interval = .2, movie.name="test.gif")

Upvotes: 0

lukeA
lukeA

Reputation: 54237

I suggest using the animation package and ImageMagick instead:

library(animation)
## make sure ImageMagick has been installed in your system
saveGIF({
  for (i in 1:10) plot(runif(10), ylim = 0:1)
})

Otherwise you could try it in the veins of this (plenty of room for optimization):

library(png)
library(caTools)
library(abind)

# create gif frames and write them to pngs in a temp dir 
dir.create(dir <- tempfile(""))
for (i in 1:8) {
  png(file.path(dir, paste0(sprintf("%04d", i), ".png")))
  plot(runif(10), ylim = 0:1, col = i)
  dev.off()
}

# read pngs, create global palette, convert rasters to integer arrays and write animated gif
imgs <- lapply(list.files(dir, full.names = T), function(fn) as.raster(readPNG(fn)))
frames <- abind(imgs, along = 3) # combine raster pngs in list to an array 
cols <- unique(as.vector(frames)) # determine unique colors, should be less then 257
frames <- aperm(array(match(frames, cols) - 1, dim = dim(frames)), c(2,1,3)) # replace rgb color codes (#ffffff) by integer indices in cols, beginning with 0 (note: array has to be transposed again, otherwise images are flipped) 
write.gif(
  image = frames, # array of integers 
  filename = tf <- tempfile(fileext = ".gif"), # create temporary filename
  delay = 100, # 100/100=1 second delay between frames 
  col = c(cols, rep("#FFFFFF", 256-length(cols))) # color palette with 256 colors (fill unused color indices with white) 
)

# open gif (windows)
shell.exec(tf)  

Upvotes: 8

ttlngr
ttlngr

Reputation: 53

Is that what you are looking for?

   library(ggplot2)
   a <- 0:10
    df <- data.frame(a=a,b=a)
    steps <-function(end){
      a <- ggplot(df[1:end,], aes(a,b)) + 
        geom_point() + 
        scale_x_continuous(limits=c(0,10)) +
        scale_y_continuous(limits=c(0,10))
      print(a)
    }
    gif <- function() {
      lapply(seq(1,11,1), function(i) {
        steps(i)
      })
    }
    library(animation)
    saveGIF(gif(), interval = .2, movie.name="test.gif")

Upvotes: 1

Related Questions