Add a tint band (aka shapeburst fill) in leaflet
Stackoverflow is again a source of inspiration. I found this question on tint bands in leaflet, not related to R originally but I though I could answer it with R easily. This is also a good one for me to play with this new simple feature library sf and use it with leaflet.
My simple solution is to create a new multipolygon from the original one, but with holes inside, so that we only get a doughnut polygon for each area. As raised by my question on stackoverflow (again…), I recently remarked that it could be tricky to plot multipolygons with holes in ggplot2 with SpatialPolygons
from library sp
, which is another reason to use library sf
.
Get French regions data
Let’s use some French regions polygons and attribute one colour to each region. I like piratepal
colours of library yarrr
.
fra.sp <- getData('GADM', country = 'FRA', level = 1, path = extraWD)
fra.sf <- st_as_sf(fra.sp)
ggplot(fra.sf) +
geom_sf(aes(fill = NAME_1), alpha = 0.8) +
scale_fill_manual(values = rep(unique(yarrr::piratepal("basel")),
length.out = nrow(fra.sf))) +
guides(fill = FALSE)
Create future holes with buffer
We create the future holes with a smaller buffer area.
Here, st_buffer
returns an object without geometry type (geometry type: GEOMETRY
), which prevents it to be plot (Error in CPL_gdal_dimension(st_geometry(x), NA_if_empty)
). A workaround is to use st_cast
after.
fra.sf.buf <- st_cast(st_buffer(fra.sf, dist = -0.1))
ggplot() +
geom_sf(data = fra.sf.buf, aes(fill = factor(NAME_1)), alpha = 0.8) +
geom_sf(data = fra.sf,
colour = "grey20", fill = "transparent",
size = 0.5) +
scale_fill_manual(values = rep(unique(yarrr::piratepal("basel")),
length.out = nrow(fra.sf))) +
guides(fill = FALSE)
Create holes in the original polygons
To create the doughnuts using original and buffer polygons, I used st_difference
. However as discussed with edzer in the sf
github repository, I had to transform the buffer polygons into a Multipolygon of a unique Multipolygon using st_combine
. Moreover, because the resulting Multipolygon object as no identified geometry, I had to pass it through st_cast
.
# st_difference work if the mask is a unique multipolygon
fra.sf.buf.comb <- fra.sf.buf %>% st_combine() %>% st_sf()
fra.sf.doug <- st_difference(fra.sf, fra.sf.buf.comb) %>% st_cast()
ggplot() +
geom_sf(data = fra.sf.doug, aes(fill = factor(NAME_1)),
alpha = 0.6, colour = "transparent") +
# geom_sf(data = fra.sf, colour = "grey20") +
scale_fill_manual(values = rep(unique(yarrr::piratepal("basel")),
length.out = nrow(fra.sf.doug))) +
guides(fill = FALSE)
Output tint bands in leaflet
To allow for a quick view, polygons were simplified with st_simplify
. You’ll see it if you zoom.
# Simplify geometry to get a lighter widget
# Separate "Rhône-Alpes", "Franche-Comté", "Bourgogne", "Bretagne" as it does not support to much simplification
fra.sf.doug.simple1 <- st_simplify(filter(fra.sf.doug, NAME_1 %in% c("Rhône-Alpes", "Franche-Comté")), dTolerance = 1e-4)
fra.sf.doug.simple2 <- st_simplify(filter(fra.sf.doug, NAME_1 %in% c("Bourgogne")), dTolerance = 1e-5)
fra.sf.doug.simple3 <- st_simplify(filter(fra.sf.doug, NAME_1 %in% c("Bretagne")), dTolerance = 1e-2)
fra.sf.doug.simple4 <- st_simplify(filter(fra.sf.doug, !NAME_1 %in% c("Rhône-Alpes", "Franche-Comté", "Bourgogne", "Bretagne")), dTolerance = 0.02)
fra.sf.doug.simple <- rbind(fra.sf.doug.simple1, fra.sf.doug.simple2, fra.sf.doug.simple3, fra.sf.doug.simple4) %>% st_cast()
fra.sf.simple <- st_simplify(fra.sf, dTolerance = 0.02)
Now we can use it to produce a leaflet map with tinted bands having transparency and original polygons in black.
factpal <- colorFactor(rep(unique(yarrr::piratepal("basel")),
length.out = nrow(fra.sf.doug.simple)),
fra.sf.doug.simple$NAME_1)
# leaflet widget
m <- leaflet() %>%
addProviderTiles(providers$Stamen.Toner) %>%
addPolygons(data = fra.sf.doug.simple, weight = 1, smoothFactor = 0.75,
opacity = 0, fillOpacity = 0.6,
color = "#000000",
fillColor = ~factpal(fra.sf.doug.simple$NAME_1),
highlightOptions = highlightOptions(color = "white", weight = 2,
bringToFront = TRUE)) %>%
addPolygons(data = fra.sf.simple, weight = 1, smoothFactor = 0.75,
opacity = 1.0, fillOpacity = 0,
color = "#000000")
The full rmarkdown script
If you want to reproduce these figures, the full rmarkdown script is available here on my github.
Citation:
For attribution, please cite this work as:
Rochette Sébastien. (2017, Aug. 10). "Polygons tint band with leaflet and simple feature (library sf)". Retrieved from https://statnmap.com/2017-08-10-polygons-tint-band-with-leaflet-and-simple-feature-library-sf/.
BibTex citation:
@misc{Roche2017Polyg,
author = {Rochette Sébastien},
title = {Polygons tint band with leaflet and simple feature (library sf)},
url = {https://statnmap.com/2017-08-10-polygons-tint-band-with-leaflet-and-simple-feature-library-sf/},
year = {2017}
}