I want to make a Shiny app where the colouring of a choropleth is based on a numeric value of one of many possible quantitative variables that a user can select from. In simple cases, this is straightforward, but I'm unsure of the best practices when we have 20+ variables, with quite detailed shape files (~2300 polygons).
It might or might not be relevant that the variables might be completely independent to each other such as 'Total Population' or 'Average Temperature' but some of them will have a temporal relationship such as 'Total Population' at 3 or more points in time.
One of the main shapefiles I am using is the ABS Statistical Area 2. Below I give the population density (total population/area) for Australia and a zoomed in view of Sydney to better convey the level of detail I'm interested in.
I have read the shapefile in to R and greatly reduced the complexity/number of points using the ms_simplify()
function in the rmapshaper
package.
Now as far as Shiny and leaflet go, this is what I have been doing:
Before the
server
object is defined inserver.R
, I build a primary map object with all the desired 'layers'. That is, a leaflet with numerousaddPolygon()
calls to define the colouring of each 'layer' (group).# Create main map primary_map <- leaflet() %>% addProviderTiles( providers$OpenStreetMap.BlackAndWhite, options = providerTileOptions(opacity = 0.60) ) %>% # Layer 0 (blank) addPolygons( data = aus_sa2_areas, group = "blank" ) %>% # Layer 1 addPolygons( data = aus_sa2_areas, fillColor = ~palette_layer_1(aus_sa2_areas$var_1), smoothFactor = 0.5, group = "layer_1" ) %>%
...
# Layer N addPolygons( data = aus_sa2_areas, fillColor = ~palette_layer_n(aus_sa2_areas$var_n), smoothFactor = 0.5, group = "layer_n" ) %>% ...
All bar the first layer is then hidden using
hideGroup()
so that the initial rendering of the map doesn't look silly.hideGroup("layer_1") %>% hideGroup("layer_2") %>% ... hideGroup("layer_n")
In the Shiny app, using radio buttons (
layer_selection
), the user can select the 'layer' they'd like to see. I useobserveEvent(input$layer_selection, {})
to watch the status of the radio button options. To update the plot, I useleafletProxy()
andhideGroup()
to hide all the groups and thenshowGroup()
to unhide the selected layer.
I apologize for the lack of reproducible example.
Questions
How can I optimise my code? I am eager to make it more performant and/or easy to work with. I've found using
hideGroup()
's/showGroup()
for each layer selection is far faster than usingaddPolygon()
to a blank map, but this causes the app to take a very significant amount of time to load.Can I change the variable I am colouring the polygons by, without redrawing or adding those polygons again? To clarify, if I have 2 different variables to plot, both using the same shape data, do I have to do 2 distinct
addPolygon()
calls?Is there a more automatic way to sensibly colour the polygons for each layer according to a desired palette (from the viridis package?). Right now I'm finding defining a new palette for each variable, rather cumbersome, eg:
palette_layer_n <- colorNumeric( palette = "viridis", domain = aus_sa2_areas$aus_sa2_areas$var_n )
Side Question
How does this map on the ABS website work? It can be incredibly detailed and yet extremely responsive. Compare the Mesh Block detail to the SA2 (2310 polygons), example below: