leaflet icon indicating copy to clipboard operation
leaflet copied to clipboard

Cannot bind Legend layer to Polygon layer in Leaflet/R

Open telegott opened this issue 4 years ago • 2 comments

I try to plot a map of concentrations of chemicals. These have very different ranges, so a shared legend is not feasible. The ultimate goal is to have mutually exclusive layers and a legend for each of those that only pops up when the layer is selected.

From what I read in the documentation of addLegend(), exactly this should be handled by the group parameter that was set to the same name in the addPolygons() for that layer before. However, it just does not work. Does anyone have an idea for the reason? Here's what I tried:

library(spData)
#> To access larger datasets in this package, install the spDataLarge
#> package with: `install.packages('spDataLarge',
#> repos='https://nowosad.github.io/drat/', type='source')`
library(leaflet)
library(sf)
#> Linking to GEOS 3.6.2, GDAL 2.2.3, PROJ 4.9.3
library(tidyverse)


set.seed(1)

vietnam <- world %>%
  filter(name_long == "Vietnam")

grid_geometries <-
  st_make_grid(vietnam, square = FALSE)
#> although coordinates are longitude/latitude, st_relate_pattern assumes that they are planar

grid_sf <- st_sf(
  id = 1:length(grid_geometries),
  geometry = grid_geometries,
  category = sample(letters[1:3], size = length(grid_geometries), replace = TRUE),
  value = rnorm(length(grid_geometries))
)

addPolygonsLayers <- function(map, data, layer_by, fill_by) {
  data_groups <- split(data, data[[layer_by]])
  data_groups_names <- names(data_groups)

  for (i in seq_along(data_groups)) {
    group_data <- data_groups[[i]]
    group_name <- data_groups_names[i]
    group_values <- pull(group_data, fill_by)

    pal <- colorNumeric(palette = "viridis", domain = group_values)

    map <-
      map %>%
      addPolygons(
        data = group_data,
        fillColor = ~ pal(group_values),
        fillOpacity = 1,
        group = group_name,
        popup = str_c(group_name, " </br> Value: ", group_values)
      ) %>%
      addLegend(
        group = group_name,
        opacity = 1,
        pal = pal,
        values = group_values,
        position = "bottomright"
      )
  }
  map <-
    map %>%
    addLayersControl(
      baseGroups = data_groups_names,
      options = layersControlOptions(collapsed = FALSE),
      position = "topright"
    )
  return(map)
}


leaflet() %>%
  addTiles() %>%
  addPolygonsLayers(
    data = grid_sf,
    layer_by = "category",
    fill_by = "value"
  )
#> TypeError: Attempting to change the setter of an unconfigurable property.
#> TypeError: Attempting to change the setter of an unconfigurable property.

Created on 2019-11-20 by the reprex package (v0.3.0)

telegott avatar Nov 20 '19 13:11 telegott

I am facing the same problem here. How can I set mutually exclusive layers and legends?

andresimi avatar Jan 21 '23 19:01 andresimi

One workaround is to use overlayGroups instead of baseGroups. This is dumb because the layers can only be toggled as checkboxes (rather than radio buttons), but this does toggle the legends properly based on the layer selection.

library(spData)
#> To access larger datasets in this package, install the spDataLarge
#> package with: `install.packages('spDataLarge',
#> repos='https://nowosad.github.io/drat/', type='source')`
library(leaflet)
library(sf)
#> Linking to GEOS 3.6.2, GDAL 2.2.3, PROJ 4.9.3
library(tidyverse)


set.seed(1)

vietnam <- world %>%
  filter(name_long == "Vietnam")

grid_geometries <-
  st_make_grid(vietnam, square = FALSE)
#> although coordinates are longitude/latitude, st_relate_pattern assumes that they are planar

grid_sf <- st_sf(
  id = 1:length(grid_geometries),
  geometry = grid_geometries,
  category = sample(letters[1:3], size = length(grid_geometries), replace = TRUE),
  value = rnorm(length(grid_geometries))
)

addPolygonsLayers <- function(map, data, layer_by, fill_by) {
  data_groups <- split(data, data[[layer_by]])
  data_groups_names <- names(data_groups)

  for (i in seq_along(data_groups)) {
    group_data <- data_groups[[i]]
    group_name <- data_groups_names[i]
    group_values <- pull(group_data, fill_by)

    pal <- colorNumeric(palette = "viridis", domain = group_values)

    map <-
      map %>%
      addPolygons(
        data = group_data,
        fillColor = ~ pal(group_values),
        fillOpacity = 1,
        group = group_name,
        popup = str_c(group_name, " </br> Value: ", group_values)
      ) %>%
      addLegend(
        group = group_name,
        opacity = 1,
        pal = pal,
        values = group_values,
        position = "bottomright"
      )
  }
  map <-
    map %>%
    addLayersControl(
      overlayGroups = data_groups_names,
      options = layersControlOptions(collapsed = FALSE),
      position = "topright"
    )
  return(map)
}


leaflet() %>%
  addTiles() %>%
  addPolygonsLayers(
    data = grid_sf,
    layer_by = "category",
    fill_by = "value"
  )

mkoohafkan avatar Nov 30 '23 22:11 mkoohafkan