Search code examples
rleaflet

Efficient way to draw polylines in leaflet using R


What's up!

I have a data frame where each row I have the information of instant speed and coordinates (lat and long) of an object, but the dataset is very large. It's taking forever or even crashing the webpage when I try to draw the trajectory of the object with speed as a color. Anyone can help me?

Here's some code, but remember my dataset is much more bigger than this:

library(leaflet)
library(tidyverse)


df <- data.frame(lat = seq(14, 15, length.out = 100), 
                 lng = seq(45, 46, length.out = 100), 
                 Speed = runif(100, 50, 70))

pal <- colorNumeric(palette = "Greens", domain = df$Speed) 

colorGradient <- df$Speed %>%
  pal

df1 <- df %>%
  mutate(nextLat = lead(lat),
         nextLng = lead(lng),
         color = colorGradient
  )

gradient_map <- leaflet() %>% 
  addTiles()

for (i in 1:nrow(df1)) {
  gradient_map <- addPolylines(map = gradient_map,
                               data = df1, 
                               lng = as.numeric(df1[i, c('lng', 'nextLng')]), 
                               lat = as.numeric(df1[i, c('lat', 'nextLat')]), 
                               color = as.character(df1[i, c('color')])
  )
}

gradient_map


Solution

  • As a first step try to avoid creating nrow-number of Leaflet layers (the addPolylines loop). Here we'll first create an sf object of line segments, then we'll add all those segments to a single polyline layer:

    library(leaflet)
    library(dplyr)
    library(sf)
    
    # create sf object of line segments from sequential points.
    len_out <- 1000
    df <- data.frame(lat = seq(14, 15, length.out = len_out), 
                     lng = seq(45, 46, length.out = len_out), 
                     Speed = runif(len_out, 50, 70)) %>% 
      st_as_sf(coords = c("lng", "lat"), crs = "wgs84")  %>% 
      mutate(seg_end = lead(geometry)) %>% 
      rowwise() %>% 
      mutate(geometry = st_union(geometry, seg_end) %>% st_cast("LINESTRING")) %>% 
      ungroup() %>% 
      select(!starts_with("seg"))
      
    pal <- colorNumeric(palette = "Greens", domain = df$Speed) 
    
    gradient_map <- leaflet(df) %>% 
      addTiles() %>% 
      addPolylines(color = ~pal(Speed))
    
    gradient_map
    

    Created on 2023-07-25 with reprex v2.0.2

    For further optimization and benchmarking it would be helpful to know the number of actual points (hundreds/thousands/millions), approximate distance (range) between points and if simplifaction of the track is also an option.