Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create animation of vehicle moving form A to B along a route?

Tags:

r

sp

sf

tmap

osrm

below is an example of finding route, travel time and travel distance from 'One World Trade Center, NYC' to 'Madison Square Park, NYC' using osrm package in R. (I learnt it from Road Routing in R). The travel time here is 10.37 minutes.

I wanted to create an video for visualization.

Q. How can I create an animation of vehicle (represented by a marker) moving from 'One World Trade Center, NYC' to 'Madison Square Park, NYC' along the route ?

Ideally, we should know the speed in each road segment. But lets assume the vehicle moves non-stop at constant speed (= distance/time) between two location.

We can simply use tmap instead of leaflet also to create animation.

enter image description here

library(sf)
library(dplyr)
library(tidygeocoder)
library(osrm)

# 1. One World Trade Center, NYC
# 2. Madison Square Park, NYC
adresses <- c("285 Fulton St, New York, NY 10007", 
            "11 Madison Ave, New York, NY 10010")

# geocode the two addresses & transform to {sf} data structure
data <- tidygeocoder::geo(adresses, method = "osm") %>% 
  st_as_sf(coords = c("long", "lat"), crs = 4326)

osroute <- osrm::osrmRoute(loc = data,
                           returnclass = "sf")

summary(osroute)



library(leaflet)

leaflet(data = data) %>% 
  addProviderTiles("CartoDB.Positron") %>% 
  addMarkers(label = ~address) %>% 
  addPolylines(data = osroute,
               label = "OSRM engine",
               color = "red")

like image 733
SiH Avatar asked Aug 23 '21 22:08

SiH


1 Answers

As an alternative to the tmap approach proposed by @mrhellman I offer an alternative built on ggplot, ggmap (for the basemap) and gganimate based workflow.

I have found the outcome of animations created via {gganimate} preferable, as {gganimate} gives me more control - such as the shadow_wake that in my opinion nicely illustrates the movement of a car along the line. If I remember correctly tmap uses gganimate under the hood.

ggmap does not support CartoDB basemaps - such as the Positron used above - but I have found the toner background adequate.

Note that ggmap does not play quite nicely with ggplot2::geom_sf() and I have found it easier to transform my workflow to old ggplot2::geom_point() approach - i.e. extract the x and y coordinates and map them via aes().

As there is only a single route to display it should be sufficient to calculate a technical variable seq that is used in the transition_reveal() to animate; this may be replaced by a time dimension if & when necessary (such as when displaying more routes with different travel time in a single animation).

library(sf)
library(dplyr)
library(tidygeocoder)
library(osrm)

# 1. One World Trade Center, NYC
# 2. Madison Square Park, NYC
adresses <- c("285 Fulton St, New York, NY 10007", 
              "11 Madison Ave, New York, NY 10010")

# geocode the two addresses & transform to {sf} data structure
data <- tidygeocoder::geo(adresses, method = "osm") %>% 
  st_as_sf(coords = c("long", "lat"), crs = 4326)

osroute <- osrm::osrmRoute(loc = data,
                           returnclass = "sf")

# sample osroute 50 times regularly, cast to POINT, return sf (not sfc) object
osroute_sampled <- st_sample(osroute, type = 'regular', size = 50) %>%
  st_cast('POINT') %>%
  st_as_sf() 


library(ggplot2)
library(ggmap) # warning: has a naming conflict with tidygeocoder!
library(gganimate)

# ggmap does not quite like geom_sf(), 
# the "old school" geom_point will be easier to work with
osroute_xy <- osroute_sampled %>% 
  mutate(seq = 1:nrow(.),
         x = st_coordinates(.)[,"X"],
         y = st_coordinates(.)[,"Y"]) 

# basemap / the bbox depends on yer area of interest
NYC <- get_stamenmap(bbox = c(-74.05, 40.68, -73.9, 40.8),
                     zoom = 13,
                     maptype = "toner-background")

# draw a map 
animation <- ggmap(NYC) + 
  geom_point(data = osroute_xy,
             aes(x = x, y = y),
             color = "red",
             size = 4) +
  theme_void() +
  transition_reveal(seq) +
  shadow_wake(wake_length = 1/6)

# create animation
gganimate::animate(animation, 
                   nframes = 2*(nrow(osroute_xy)+1), 
                   height = 800, 
                   width = 760,
                   fps = 10, 
                   renderer = gifski_renderer(loop = T))

# save animation  
gganimate::anim_save('animated_nyc.gif')

animated map of a car in nyc

like image 68
Jindra Lacko Avatar answered Sep 27 '22 18:09

Jindra Lacko