Search code examples
ranimationpnggifmagick

Creating animation (.gif) in R using .png files


Sample data

 location <- c("A","B","C")
 years <- c(2001,2002,2003)

 for(l in seq_along(location)){
    for(y in seq_along(years)){
       loc <- location[l]
       yr <- years[y]
       png(paste0(loc,".",yr,".png"))
       plot(rnorm(10))
       dev.off()
   }
   }

For each location X year combination, I generated png files. My goal is to combine for each location, all the years in a single gif.file to show as animation.

I am doing this

  library(magick)

  # convert each png file as magick object 
  for(l in seq_along(location)){
    for(y in seq_along(years)){
       loc <- location[l]
       yr <- years[y]

       png.dat <- image_read(paste0(loc,".",yr,".png"))

       assign(paste0(loc,".",yr),png.dat)
   }}

This gives me following files for location A, B and C:

A.2001, A.2002, A.2003 B.2001, B.2002, B.2003 C.2001, C.2002, C.2003

  # stack the objects for one location, and create animation
  A.c <- c(A.2001,A.2002,A.2003)
  A.img <- image_scale(A.c)
  A.ani <- image_animate(A.img, fps = 1, dispose = "previous")
  image_write(A.ani, paste0("A_animation.gif"))

  # repeat for B and C
   B.c <- c(B.2001,B.2002,B.2003)
   B.img <- image_scale(B.c)
   B.ani <- image_animate(B.img, fps = 1, dispose = "previous")
   image_write(B.ani, paste0("B_animation.gif"))

 # stack the objects for one location, and create animation
  C.c <- c(C.2001,C.2002,C.2003)
  C.img <- image_scale(C.c)
  C.ani <- image_animate(C.img, fps = 1, dispose = "previous")
  image_write(C.ani, paste0("C_animation.gif"))

enter image description here

enter image description here

enter image description here

My issue is that in reality I have over 100 locations and 30 years. So the above steps on creating animation becomes manual. Does anyone have a quicker method to do the above task.


Solution

  • You can use image_join from magick to coerce a list of objects of class "magick-image" to a multi-frame image.

    Here's how I might do it with your example:

    library(purrr)
    library(magick)
    
    location <- c("A","B","C")
    years <- c(2001,2002,2003)
    
    df <- data.frame(loc = character(0), yr = integer(0), file = character(0))
    
    for(l in seq_along(location)){
      for(y in seq_along(years)){
        loc <- location[l]
        yr <- years[y]
        png(paste0(loc,".",yr,".png"))
        plot(rnorm(10))
        dev.off()
      }
    }
    
    df <- expand.grid(loc = location,
                      yr = years)
    df$file = paste0(df$loc,".",df$yr,".png")
    
    df
    
    #  loc   yr       file
    # 1   A 2001 A.2001.png
    # 2   B 2001 B.2001.png
    # 3   C 2001 C.2001.png
    # 4   A 2002 A.2002.png
    # 5   B 2002 B.2002.png
    # 6   C 2002 C.2002.png
    # 7   A 2003 A.2003.png
    # 8   B 2003 B.2003.png
    # 9   C 2003 C.2003.png
    
    locations <- unique(df$loc)
    
    for(i in 1:length(locations)) {
      images <- map(df$file[df$loc == locations[i]], image_read)
      images <- image_join(images)
      animation <- image_animate(images, fps = 1)
      image_write(animation, paste0(locations[i], ".gif"))
    }