rimagemagickgifr-leaflet

Create a gif from a series of Leaflet maps in R


I am looking for an automated method to convert leaflet R Studio plots into image files.

Seems like exporting a leaflet widget to HTML is straightforward (Saving leaflet output as html). However I cannot find any answers or docs about how to save the image produced by a leaflet widget as an image. It seems strange that I can do this manually in R Studio but that there isn't some function within R Studio that can be called to do the same thing.

I've tried the usual suspects, variations on the following:

png("test_png.png")
map
dev.off()

But these all just print white or print a file that can't even be opened. IF I understand this Git discussion correctly, seems like something in leaflet is not available but is desired by users.

In the meantime, R Studio clearly has a way to render this image into an image file, making me press a button to do it. Is there a way to automate this? How can I export the images plotted in R Studio to image files? I need image files and I need this to be programmatic because I want to make a gif out of a few hundred maps.

Alternately, I'd welcome suggestions for a workaround. I might try this: Python - render HTML content to GIF image but if someone has alternatibve suggestions, please share.


Solution

  • 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