16

I'm trying to create a leaflet map with points sized by a variable. Is it possible to create a legend with different sized circles representing the different variable values? I found another post showing how to convert squares to circles in the legend, but am not sure how to change the size of different circles in the legend.

For example, here's a dummy script which creates 10 points associated with 2 classes of a variable (5 and 10). I'd like a legend with two circles the same size as that specified with addCircleMarkers with a radius of 5 and 10. If anyone can modify to create what I want I would be extremely grateful! Thanks!

library(shiny)
library(leaflet)

#create data
Points<-data.frame(x=runif(10,20,21), y=runif(10,0,1), var=rep(c(5,10),5))
map = leaflet() %>% addTiles()

# Set up shiny app
shinyApp(ui=bootstrapPage(
tags$style(type = "text/css", "html, body {width:100%;height:100%}",
".leaflet .legend i{
border-radius: 50%;
width: 10px;
height: 10px;
margin-top: 4px;
}
"
),
leafletOutput("myMap", width = "100%", height = "100%")),

server= function(input, output){

output$myMap = renderLeaflet({map %>% 
    addCircleMarkers(Points$x,Points$y,radius=Points$var) %>%
    addLegend(colors=rep("blue",2), labels=c(5,10))
  })
})
Hugh Sturrock
  • 315
  • 2
  • 8

1 Answers1

23

You're in luck. A closer look at the leaflet.js shows that the configurations your add inside the addLegend command, are used literally to create the legend items:

Lines 1083 - 1086 from leaflet.js:

for (var i = 0; i < colors.length; i++) {
  legendHTML += '<i style="background:' + colors[i] + ';opacity:' +
                options.opacity + '"></i> ' + labels[i] + '<br/>';
}

This way, we can sneak in some extra styling. Within the colors arguement, we add some width and height to change the size of the i tag (= the legend circle). And (this is optional) we can make the labels a div with modified alignment style, because they tend to be stuck way to the top of the line, if the circle gets big.

I took the liberty to create a custom legend function for you. This takes an additional value for the circle sizes. (It's a very minimal function for just this one application.) It then adds the styling I mentioned above without you needing to worry about typos or other errors. Note that the standard size is 10.

Code below. Have fun! And please write if there are any mistakes or bugs. I could not test for every possible scenario.

library(shiny)
library(leaflet)

#create data
Points<-data.frame(x=runif(10,20,21), y=runif(10,0,1), var=rep(c(5,10),5))
map = leaflet() %>% addTiles()

# Set up shiny app
shinyApp(
  ui = bootstrapPage(
    tags$style(type = "text/css", "html, body {width:100%;height:100%}",
      ".leaflet .legend i{
      border-radius: 50%;
      width: 10px;
      height: 10px;
      margin-top: 4px;
      }
    "),
    leafletOutput("myMap", width = "100%", height = "100%")
  ),

  server = function(input, output){
    addLegendCustom <- function(map, colors, labels, sizes, opacity = 0.5){
      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, colors = colorAdditions, labels = labelAdditions, opacity = opacity))
    }
    
    output$myMap = renderLeaflet({map %>% 
      addCircleMarkers(Points$x,Points$y,radius=Points$var) %>%
      addLegendCustom(colors = c("blue", "blue", "red"), labels = c("A", "B", "C"), sizes = c(10, 20, 40))
    })
  }
)
Community
  • 1
  • 1
K. Rohde
  • 9,439
  • 1
  • 31
  • 51
  • 1
    Dear Rohde, how can I save the resulting map from your code? I do not know how to export it even if I include a download botton in the ui argument – Marco Mello Apr 12 '19 at 10:03
  • How is that special for my code sample? Did you manage to download the map and just the legend does not show up correctly? Otherwise you should just search for how to download a leaflet in general. – K. Rohde Apr 12 '19 at 12:19
  • Using this code, I get squares in my legend. Is that expected? – Nova Oct 21 '19 at 19:07
  • @Nova Not expected, no, and not likely. Did you try different browsers? Do you have any additional styles that could affect the legend? Did you change any of the styles? Did you leave out the `tags$style` maybe? – K. Rohde Oct 22 '19 at 07:07
  • Ah, ok, I'm definitely missing something then. I am not using `shiny` so wasn't sure how to incorporate that info. If you have a minute, check out my question here: https://stackoverflow.com/questions/58505589/circles-in-legend-for-leaflet-map-with-addcirclemarkers-in-r-without-shiny – Nova Oct 22 '19 at 13:37