The leaflet package in R has built-in functionality for creating color encoded geometries and annotating with color legends. Support is lacking in the area of providing the ability to encode data with sizes or symbology except for the case of circle markers. Size and symbology are an important part of data visualization on a map. Using the leaflegend package, you can add both to your leaflet maps without adding external css or javascript.

Adding Proportional Sizing to Symbols

To create the appropriately sized symbols, The makeSymbol function can create a list of icons based on the output of sizeNumeric. The baseSize argument sets the center point size of the data scale to the mean of the values e.g. with values 1, 2, 3, 4, 5 and a base size of 10, the resultant size in pixels of the symbols are 3.33, 6.67, 10, 13.33, 16.67. The symbols can be added as icons to the map since they are svg elements. Some transparency is added here to show overlapping symbols.

To add a legend for the sizes, addLegendSize takes in the same values and uses the pretty function and breaks argument to create the scale. There may be some inconsistency between the number of breaks specified (leaflet internals also make use of the pretty function). It is easy to customize other aspects of the legend for appearance such as here: the color, symbol, and transparency are matched to the symbols and we align the legend items horizontally.

library(leaflet)
library(leaflegend)
data("quakes")
symbols <- makeSizeIcons(
  values = quakes$depth,
  shape = 'diamond',
  color = 'red',
  fillColor = 'red',
  opacity = .5,
  baseSize = 10
)

leaflet() %>%
  addTiles() %>%
  addMarkers(data = quakes,
             icon = symbols,
             lat = ~lat, lng = ~long) %>%
  addLegendSize(
    values = quakes$depth,
    color = 'red',
    fillColor = 'red',
    opacity = .5,
    title = 'Depth',
    shape = 'diamond',
    orientation = 'horizontal',
    breaks = 5)

Encoding Color and Size

A helper function makeSizeIcons simplifies the above code and allows a palette function to be passed. The symbols are switched to a plus sign to provide a smaller impact of area for overlapping points. The result is called double-encoding and is a way to emphasize differences in data. Because the Richter scale is on a logarithmic scale, the actual reading of magnitude was taken as ten to the power of.

numPal <- colorNumeric('viridis', 10^(quakes$mag))
symbols <- makeSizeIcons(values = 10^(quakes$mag),
                         shape = 'plus',
                         pal = numPal,
                         opacity = .5,
                         baseSize = 1)

leaflet(quakes) %>%
  addTiles() %>%
  addMarkers(icon = symbols,
             lat = ~lat, lng = ~long) %>%
  addLegendSize(
    values = 10^(quakes$mag),
    pal = numPal,
    title = 'Magnitude',
    baseSize = 1,
    shape = 'plus',
    orientation = 'horizontal',
    opacity = .5,
    fillOpacity = .3,
    position = 'bottomleft',
    breaks = 5)

Split Color and Size Encodings

It is also possible to color encode and size encode with different values. The colorValues argument can be used to base the color encoding on a different vector of data than the values argument which is for size.

numPal <- colorNumeric('viridis', quakes$mag)
symbols <- makeSizeIcons(values = quakes$depth,
                         shape = 'plus',
                         pal = numPal,
                         color = 'black',
                         colorValues = quakes$mag,
                         baseSize = 10,
                         opacity = .5)

leaflet(quakes) %>%
  addTiles() %>%
  addMarkers(icon = symbols,
             lat = ~lat, lng = ~long) %>%
  addLegendSize(
    values = quakes$depth,
    color = 'black',
    title = 'Depth',
    shape = 'plus',
    orientation = 'horizontal',
    opacity = .5,
    fillOpacity = 0,
    breaks = 5,
    position = 'bottomright') %>%
  addLegendNumeric(
    pal = numPal, 
    title = 'Magnitude',
    shape = 'stadium',
    values = quakes$mag, 
    fillOpacity = .5,
    decreasing = TRUE,
    position = 'bottomright')
  

Size Legend Options

Specifying color and fillColor will override any palette function that is provided. Below are examples of all the different configurations for the legend. The symbols are also available for makeSizeIcons to match the desired legend.

numPal <- colorNumeric('viridis', quakes$depth)
leaflet() %>%
  addTiles() %>%
  addLegendSize(
    values = quakes$mag,
    color = 'black',
    title = 'Magnitude',
    labelStyle = 'margin: auto;',
    shape = 'cross',
    orientation = 'horizontal',
    opacity = .7,
    breaks = 5,
    position = 'topright') %>%
  addLegendSize(
    values = quakes$mag,
    color = 'black',
    fillColor = 'transparent',
    title = 'Magnitude',
    labelStyle = 'margin: auto;',
    shape = 'cross',
    orientation = 'horizontal',
    opacity = .7,
    breaks = 5,
    position = 'topright') %>%
  addLegendSize(
    values = quakes$depth,
    pal = numPal,
    title = 'Depth',
    labelStyle = 'margin: auto;',
    shape = c('cross'),
    orientation ='horizontal',
    opacity = .7,
    color = 'black',
    breaks = 5,
    position = 'topright') %>%
  addLegendSize(
    values = quakes$depth,
    pal = numPal,
    title = 'Depth',
    labelStyle = 'margin: auto;',
    shape = c('cross'),
    orientation ='horizontal',
    opacity = .7,
    fillColor = 'black',
    breaks = 5,
    position = 'topright') %>%
  addLegendSize(
    values = quakes$depth,
    pal = numPal,
    title = 'Depth',
    labelStyle = 'margin: auto;',
    shape = c('cross'),
    orientation ='horizontal',
    opacity = .7,
    breaks = 5,
    position = 'topright')

[CRAN] [github]