1

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 the different layers for the different chemicals selectable and show the respective legend.

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)
library(leaflet)
library(sf)
library(tidyverse)


set.seed(1)

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

grids <-
  st_make_grid(vietnam, square = FALSE)

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

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 = grids_sf,
    layer_by = "category",
    fill_by = "value"
  )
3

You can add a custom className to the legend (it should match the group name), and then, using htmlwidgets::onRender(), hide all legends except for the one whose class matches the selected group.

Note that you should keep "info legend" in the className since they are important attributes.

Modifying the function from here:

... %>%
   addPolygonsLayers(
      ...,
      group = "xxx"
   ) %>%
   addLegend(
      ...,
      group = "xxx",
      className = "info legend xxx"
   ) %>%
   addLayersControl(
      baseGroups = c("xxx", ...),
      options = layersControlOptions(collapsed = FALSE)
   ) %>%
   htmlwidgets::onRender("
      function(el, x) {
         var updateLegend = function () {
            var selectedGroup = document.querySelectorAll('input:checked')[0].nextSibling.innerText.substr(1);

            document.querySelectorAll('.legend').forEach(a => a.hidden=true);
            document.querySelectorAll('.legend').forEach(l => {
               if (l.classList.contains(selectedGroup)) l.hidden=false;
            });
         };
         updateLegend();
         this.on('baselayerchange', el => updateLegend());
      }"
   )
| improve this answer | |
  • Thanks alot, this is perfect! :) – telegott Sep 5 at 13:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.