Created
March 31, 2020 11:18
-
-
Save PaulC91/31c05f84b25975047092f13c2474507a to your computer and use it in GitHub Desktop.
Add a custom circle legend to leaflet map in R
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#' Add custom circle legend to leaflet map | |
#' | |
#' To be used alongside \code{leaflet::addCircleMarkers} | |
#' | |
#' @param map a leaflet map | |
#' @param title title of the legend | |
#' @param range vector of numeric values you want to scale the legend to (same vector used with addCircleMarkers) | |
#' @param scaling_fun the scaling function used with addCircleMarkers to scale circle radii appropriately for leaflet | |
#' @param color stroke color | |
#' @param weight stroke width in pixels | |
#' @param fillColor fill color | |
#' @param fillOpacity fill opacity | |
#' @param position the position of the legend | |
#' @param layerId the ID of the legend; subsequent calls to \code{addLegend} | |
#' or \code{addControl} with the same \code{layerId} will replace this | |
#' legend. The ID can also be used with \code{removeControl}. | |
addCircleLegend <- function( | |
map, title = "", range, scaling_fun, ..., | |
color, weight, fillColor, fillOpacity, | |
position = c("topright", "bottomright", "bottomleft", "topleft"), | |
data = leaflet::getMapData(map), layerId = NULL) { | |
range <- base::pretty(sort(range), 20) | |
range <- range[range != 0] | |
min_n <- ceiling(min(range, na.rm = TRUE)) | |
med_n <- round(median(range, na.rm = TRUE), 0) | |
max_n <- round(max(range, na.rm = TRUE), 0) | |
n_range <- c(min_n, med_n, max_n) | |
radii <- scaling_fun(n_range, ...) | |
n_range <- scales::label_number_si()(n_range) | |
circle_style <- glue::glue( | |
"border-radius:50%; | |
border: {weight}px solid {color}; | |
background: {paste0(fillColor, round(fillOpacity*100, 0))}; | |
position: absolute; | |
bottom:1px; | |
right:25%; | |
left:50%;" | |
) | |
text_style <- glue::glue( | |
"text-align: right; | |
font-size: 11px; | |
position: absolute; | |
bottom: 0px; | |
right:1px;" | |
) | |
circle_legend <- htmltools::HTML(glue::glue( | |
'<div class="bubble-legend"> | |
<div id="legendTitle" style="text-align: center; font-weight: bold;">{title}</div> | |
<div class="symbolsContainer" style="min-width: {radii[3]*2 + 20}px; min-height: {radii[3]*2}px;"> | |
<div class="legendCircle" style="width: {radii[3] * 2}px; height: {radii[3] * 2}px; margin-left: {-radii[3]}px; {circle_style}"></div> | |
<div class="legendCircle" style="width: {radii[2] * 2}px; height: {radii[2] * 2}px; margin-left: {-radii[2]}px; {circle_style}"></div> | |
<div class="legendCircle" style="width: {radii[1] * 2}px; height: {radii[1] * 2}px; margin-left: {-radii[1]}px; {circle_style}"></div> | |
<div> | |
<p class="legendValue" style="margin-bottom: {radii[1] * 2 - 12}px; {text_style}">{n_range[1]}</p> | |
</div> | |
<div> | |
<p class="legendValue" style="margin-bottom: {radii[2] * 2 - 12}px; {text_style}">{n_range[2]}</p> | |
</div> | |
<div> | |
<p class="legendValue" style="margin-bottom: {radii[3] * 2 - 12}px; {text_style}">{n_range[3]}</p> | |
</div> | |
</div> | |
</div>' | |
)) | |
return( | |
leaflet::addControl(map, html = circle_legend, position = position, layerId = layerId) | |
) | |
} | |
# example ========================================= | |
library(leaflet) | |
df <- tibble::tibble( | |
lng = (runif(20) - .5) * 10 - 90.620130, # lng | |
lat = (runif(20) - .5) * 3.8 + 25.638077, # lat | |
size = runif(20, min = 1, max = 1000) | |
) | |
# make a scaling function to convert real numbers to radii appropriate for leaflet | |
calc_radius <- function(n, scale_factor = 30) { | |
sqrt(n)/sqrt(max(n)) * scale_factor | |
} | |
leaflet(df) %>% | |
addTiles() %>% | |
addCircleMarkers( | |
lng = ~lng, | |
lat = ~lat, | |
radius = ~calc_radius(size), | |
fillColor = "#57AACB", | |
fillOpacity = 0.8, | |
weight = 1, | |
color = "#FFFFFF" | |
) %>% | |
addCircleLegend( | |
title = "Circle Legend", | |
range = df$size, | |
scaling_fun = calc_radius, | |
fillColor = "#57AACB", | |
fillOpacity = 0.8, | |
weight = 1, | |
color = "#FFFFFF", | |
position = "topright" | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment