Search code examples
rshinyr-leaflet

Create dynamic legend on R Shiny Leaflet Maps, Error: 'colors' and 'labels' must be of the same length


I have been struggling in creating a dynamic maps legend in R shiny Leaflet Maps. The idea is to have a template code so whenever the data change, the map and its legend will follow. The coordinate is already able to adjust with change in data, but still have no idea how to make the legend become dynamic as well

Here is the code

test_map.csv contains list of data
dat_map <- read.csv("data_input/test_map.csv", header = T)

This is for the UI. where there is input to access specific data in the test_map.csv which I named it as "querymap"

      tabItem(tabName = "maps",
          fluidRow(
             
             sidebarPanel(width = 4,
                          selectInput("querymap","Title:",dat_map$Title),
                          strong("Description:"), textOutput("captionmap"), br(),
                          strong("Reference:"), uiOutput("referencemap"), #textOutput("reference"), 
                          em(textOutput("latestmap")), br(),
                          strong("Tags: "), verbatimTextOutput("tagsmap")),
             mainPanel(
                h2(textOutput("dinTitlemap")),
                tabsetPanel(
                   tabPanel("Map",br(),leafletOutput("mapall")),
                   tabPanel("Table", br(), DT::dataTableOutput("dinTablemap")), 
                   tabPanel("Download", br(), downloadButton("dlTablemap", label = "Download Table"))
                )))))

This is the "reactive" to get data from the test_map.csv

    db_map <- reactive({
   filename <- dat_map$Filename[dat_map$Title == input$querymap]
   db_map <- read.csv(paste("data_input/", filename, sep = "")) %>% 
      select(-No)
   db_map})

And here's the output code

output$mapall <- renderLeaflet({
db_map <- db_map ()

  pal <- colorFactor(
     palette = c('red', 'blue', 'yellow', 'orange','grey','green'),
     domain = db_map$kategori) #pallete for coordinate and legend color
  
  addLegendCustom <- function(map, colors, labels, sizes, opacity = 0.8){
     colorAdditions <- paste0(colors, "; width:", sizes, "px; height:", sizes, "px")
     labelAdditions <- paste0("<div style='display: inline-block;height: ",
                              sizes, "px;margin-top: 4px;line-height: ",
                              sizes, "px;'>", labels, "</div>")
     
     return(addLegend(map, title = "Category", colors = colorAdditions,
                      labels = labelAdditions, opacity = opacity, position = "bottomleft"))}
  
  leaflet(options = leafletOptions(zoomControl = FALSE, minZoom = 3, maxZoom = 100), data = db_map) %>% 
     fitBounds(min(db_map$long),min(db_map$lat),max(db_map$long),max(db_map$lat)) %>%
     addTiles('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', group = "CartoDB Light") %>% 
     addCircleMarkers(
        radius = 7, 
        color = 'black',
        stroke = TRUE, weight = 1,
        fillOpacity = 0.7,
        fillColor = ~pal(kategori),
     )%>%
     kategori = as.factor(db_map$kategori) %>%
     addLegendCustom(colors = ~pal, labels = db_map$kategori, sizes = c(10,10,10)) %>% #here is the problem
     })

Then the error is "Error: 'colors' and 'labels' must be of the same length"

Yes I know that it is not at the same length because the color pallette is set for 6 color, but the labels depends on how many variables in db_map$kategori. So my question is how to create same length of colors with the labels?


Solution

  • You can do as shown below. Add more colors to your list, if necessary.

    output$mapall <- renderLeaflet({
        db_map <- db_map()
        
        numcolor = length(unique(db_map$kategori))
        mycolor <- c("red", "blue", "black", "brown", "purple", "green", "darkblue", "darkgreen", "orange", "maroon", "yellow", "cyan","grey")
        pal <- mycolor[1:numcolor]  ##  this ensures that you have the same length of colors as labels
        
        # pal <- colorFactor(
        #   palette = c('red', 'blue', 'yellow', 'orange','grey','green'),
        #   domain = db_map$kategori) #pallete for coordinate and legend color
        
    .
    .
    .
    })