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