Search code examples
rr-leaflet

Coloring polylines on leaflet map using continuous variable values


I am trying to create a leaflet map with lines joining a list of stops. I used polylines on a leaflet map to do so.

I am now trying to color the lines by the variable (weight).

I tried creating color values on a defined gradient but it doesn't seem to work. I tried creating a gradient scale based on the weight variable and assigning that to the lines, but I think I'm missing something

enter image description here

gradientFunction <- colorRampPalette(c("red", "yellow"))
colorGradient <- gradientFunction(nrow(x))
x$color = colorGradient

x %>%
  mutate(Lat = as.numeric(Lat),
         Long = as.numeric(Long)) %>%
  arrange(sequence) %>%
  leaflet() %>% 
  addProviderTiles(providers$CartoDB.Positron) %>%
  addPolylines(
    lng = ~Long,
    lat = ~Lat,
    weight = 3,
    opacity = 3,
    color = ~color) %>%
  addCircleMarkers(
    lng = ~Long,
    lat = ~Lat,
    radius = 2,
    fillColor = "Black",
    fillOpacity = 1,
    stroke = F)

Data:

structure(list(Lat = c("1.28210155945393", "1.28329993019059", 
"1.28394108576437", "1.28475980959972", "1.284977", "1.28572048365401", 
"1.28583847140468", "1.28593135445772", "1.28623157720487", "1.28723833324362", 
"1.28736808047078", "1.29078162052352", "1.293615", "1.29395444170081", 
"1.2950426189642", "1.295962316986", "1.29618544092334", "1.29796011528522", 
"1.29811014243867", "1.29831153783592", "1.29986928715834", "1.30027569326586", 
"1.30044251755834", "1.30070547633658", "1.302127", "1.30252834773643", 
"1.304086", "1.30425500081318", "1.30496423786628", "1.30528972611328", 
"1.30566306799291", "1.30595638898755", "1.30674381370885", "1.30711835522323", 
"1.3071917122941", "1.30726086825664", "1.30787614366531", "1.30821308595952", 
"1.30837865741776", "1.30851455788092", "1.30862937328019", "1.30938972202558", 
"1.30943460005849", "1.31135799079971", "1.31250502315071", "1.31295810131062", 
"1.31390444400831", "1.31656999665769", "1.31875790465263", "1.32132832560695", 
"1.32453874317344"), Long = c("103.81722480263163", "103.81547665017668", 
"103.81783962251122", "103.83405671725487", "103.821011", "103.8285292287095", 
"103.83238179897589", "103.82668969231534", "103.83496162445665", 
"103.82259298997768", "103.82346004890803", "103.83440916705554", 
"103.832759", "103.85139096636622", "103.83205533028763", "103.85795174896221", 
"103.84958029974611", "103.83053183555204", "103.84780636909545", 
"103.8452569595532", "103.84093746088925", "103.83877618459663", 
"103.83623804216019", "103.86336013257065", "103.829875", "103.83239784275958", 
"103.907533", "103.9123223933556", "103.91493558885941", "103.90534997934479", 
"103.9110051545323", "103.91698861102066", "103.875264139574", 
"103.87989373246151", "103.91764721757994", "103.88490711001795", 
"103.92111718654822", "103.88850877408412", "103.90304313394574", 
"103.92471047692146", "103.8906311270188", "103.89936888898059", 
"103.8966101212743", "103.92481225868325", "103.9250247698478", 
"103.92790605020116", "103.93171138898548", "103.93334015990408", 
"103.93158674239623", "103.92782177344944", "103.92903818515839"
), Weight = c(0, 79, 124, 276, 333, 332, 341, 500, 287, 458, 
462, 322, 364, 409, 374, 475, 401, 512, 390, 448, 396, 391, 370, 
539, 493, 453, 668, 558, 429, 593, 581, 274, 558, 562, 230, 575, 
225, 593, 652, 214, 939, 818, 1054, 210, 219, 231, 266, 293, 
285, 281, 235), sequence = c(51, 50, 49, 42, 48, 44, 43, 45, 
41, 47, 46, 40, 39, 28, 38, 27, 29, 37, 30, 31, 32, 33, 34, 26, 
36, 35, 16, 14, 13, 17, 15, 12, 25, 24, 11, 23, 10, 22, 18, 9, 
21, 19, 20, 8, 7, 6, 5, 4, 3, 2, 1)), row.names = c(NA, -51L), class = c("tbl_df", 
"tbl", "data.frame"))

Solution

  • To color different segments you'd also need to create those segments first, one possible approach with sf as an example. The resulting x_sf has 2 geometry columns line_seg & points, default being line_seg. And when passing x_sf to leaflet or using it for data argument,line_seg will be used for plotting. To point addCircleMarkers() to point column, data argument becomes x_sf$points.

    Alternatively you could opt for leaflet plugins, https://github.com/Oliv/leaflet-polycolor for example.

    library(leaflet)
    library(dplyr)
    library(sf)
    
    x_sf <- st_as_sf(x, coords = c("Long", "Lat"), crs = "WGS84") %>% 
      arrange(`sequence`) %>% 
      mutate(geom_lead = lead(geometry)) %>% 
      slice(-n()) %>% 
      rowwise() %>% 
      mutate(line_seg = st_union(geometry, geom_lead) %>% st_cast("LINESTRING")) %>% 
      ungroup() %>% 
      st_set_geometry("line_seg") %>% 
      select(Weight, sequence, points = geometry)
      
    
    gradientFunction <- colorRampPalette(c("red", "yellow"))
    colorGradient <- gradientFunction(nrow(x_sf))
    x_sf$color = colorGradient
    
    leaflet() %>% 
    addProviderTiles(providers$CartoDB.Positron) %>%
    addPolylines(
      data = x_sf,
      weight = 3,
      opacity = 3,
      color = ~color)  %>%
    addCircleMarkers(
      data = x_sf$points,
      radius = 2,
      fillColor = "Black",
      fillOpacity = 1,
      stroke = F)
    

    Resulting x_sf object:

    x_sf
    #> Simple feature collection with 50 features and 3 fields
    #> Active geometry column: line_seg
    #> Geometry type: LINESTRING
    #> Dimension:     XY
    #> Bounding box:  xmin: 103.8155 ymin: 1.282102 xmax: 103.9333 ymax: 1.324539
    #> Geodetic CRS:  WGS 84
    #> # A tibble: 50 × 5
    #>    Weight sequence              points                            line_seg color
    #>  *  <dbl>    <dbl>         <POINT [°]>                    <LINESTRING [°]> <chr>
    #>  1    235        1  (103.929 1.324539) (103.9278 1.321328, 103.929 1.3245… #FF0…
    #>  2    281        2 (103.9278 1.321328) (103.9316 1.318758, 103.9278 1.321… #FF0…
    #>  3    285        3 (103.9316 1.318758) (103.9316 1.318758, 103.9333 1.316… #FF0…
    #>  4    293        4  (103.9333 1.31657) (103.9333 1.31657, 103.9317 1.3139… #FF0…
    #>  5    266        5 (103.9317 1.313904) (103.9279 1.312958, 103.9317 1.313… #FF1…
    #>  6    231        6 (103.9279 1.312958) (103.925 1.312505, 103.9279 1.3129… #FF1…
    #>  7    219        7  (103.925 1.312505) (103.9248 1.311358, 103.925 1.3125… #FF1…
    #>  8    210        8 (103.9248 1.311358) (103.9247 1.308515, 103.9248 1.311… #FF2…
    #>  9    214        9 (103.9247 1.308515) (103.9211 1.307876, 103.9247 1.308… #FF2…
    #> 10    225       10 (103.9211 1.307876) (103.9176 1.307192, 103.9211 1.307… #FF2…
    #> # … with 40 more rows
    

    Created on 2023-03-01 with reprex v2.0.2