2
votes

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.

1
I don't get it. What parts are "manual"? Your code produces these images, and so you know what files to feed into imagemagick, right?Jongware
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")) this part is 'manual'. If I have 1000 locations, I have to edit this part 1000 times replace A with the relevant name of the location89_Simple

1 Answers

3
votes

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"))
}