Create a gif from a series of Leaflet maps in R

I've been trying to do this with a combination of the webshot package and saveWidget from htmltools, although it's pretty slow. For a few hundred maps, it's probably not too bad if you're only doing it here and there. But, for real-time application it is too slow.

There are two external applications you need for this workflow. webshot takes screenshots of webpages and requires you to install PhantomJS first (it's tiny and easy). I also use ImageMagick (and needs to be accessible from the command line) to create the .gif files, but I'm sure there many other programs you could use to make gifs.

The idea is just to create the maps in a loop, save them to a temporary html file with saveWidget and use webshot to turn it into a png (slow). Then, once you have all the pngs, use ImageMagick to convert them to a gif (fast).

Here is an example, I also load ggmap, but only to get a location to zoom in on.

library(webshot)
library(leaflet)
library(htmlwidgets)
library(ggmap)

loc <- geocode('mt everest')  # zoom in everest
zooms <- seq(2,14,3)          # some zoom levels to animate

## Make the maps, this will make some pngs called 'Rplot%02d.png'
## in your current directory
for (i in seq_along(zooms)) {
    m <- leaflet(data=loc) %>%
      addProviderTiles('Esri.WorldImagery') %>%
      setView(lng=loc$lon, lat=loc$lat, zoom=zooms[i])
    if (i==1)
        m <- m %>% addPopups(popup="Going to see Mt Everest")
    if (i==length(zooms))
       m <- m %>%
          addCircleMarkers(radius=90, opacity = 0.5) %>%
          addPopups(popup = 'Mt Everest')

    ## This is the png creation part
    saveWidget(m, 'temp.html', selfcontained = FALSE)
    webshot('temp.html', file=sprintf('Rplot%02d.png', i),
            cliprect = 'viewport')
}

Then, it is just converting pngs to gif. I did this on a Windows, so command might be slightly different on a mac/linux (I think just single quotes instead of double quotes or something). These commands are from a command line/shell, but you could also use system/system2 to call from R or try the animation package that has some wrapper functions for ImageMagick. To make a simle gif with nothing fancy is simply, convert *.png animation.gif. I used a slightly longer code to make the pngs smaller/add some delays/and have the sequence go in and out.

convert Rplot%02d.png[1-5] -duplicate 1,-2-1, -resize "%50" gif:- | convert - -set delay "%[fx:(t==0||t==4)?240:40]" -quiet -layers OptimizePlus -loop 0 cycle.gif

enter image description here


You can create a series of PNG files as answered by jenesaisquoi (first answer). Then create gif with the png files using the below code with magick package.

library(magick)

    png.files <- sprintf("Rplot%02d.png", 1:20) #Mention the number of files to read
GIF.convert <- function(x, output = "animation.gif")#Create a function to read, animate and convert the files to gif
        {
        image_read(x) %>%
        image_animate(fps = 1) %>%
        image_write(output)
        }

        GIF.convert(png.files)

You don't require to install ImageMagick software on PC.

Code Link: Animation.R


I have table with 3 columns: lat,lon,day (376 days).

The process is: create the map -> save the map as HTML -> save the map as PNG -> import the pic -> plot it (with plot + ggimage)

All this process, will be in a loop

library(leaflet)
library(animation)
library(png)
library(htmlwidgets)
library(webshot)
library(ggmap)

saveGIF({
for (i in 1:376) {
  map  = leaflet() %>%
    addTiles() %>%
    setView(lng = lon_lat[1,2], lat = lon_lat[1,1], zoom = 5)%>%
    addMarkers(lng = lon_lat[lon_lat$day == i,2],lat = lon_lat[lon_lat$day == i,1])

  saveWidget(map, 'temp.html', selfcontained = FALSE) ## save the html
  webshot('temp.html', file=sprintf('Rplot%02d.png', 1),cliprect = 'viewport') ## save as png
  img = readPNG("Rplot01.png") ### read the png
  plot(ggimage(img)) ###reading png file
}
})