I'm creating a Leaflet Shiny app that has several different interactive elements and I'm having some problems getting everything to gel together correctly.
I've created some heavily trimmed example code that (hopefully) captures the extent of my problem:
library(raster)
library(RColorBrewer)
library(leaflet)
library(shiny)
#load rwa shapefile, remove extra columns
rwa <- getData("GADM", country = "RWA", level = 1)
rwa <- rwa[, -(6:13)]
#load bdi shapefile, remove extra columns, prepare to merge with rwa
bdi <- getData("GADM", country = "BDI", level = 1)
bdi <- bdi[, -(6:13)]
bdi <- spChFIDs(bdi, paste("bdi", row.names(bdi), sep = "."))
#merge
z <- rbind(rwa, bdi)
#add dummy data
z@data$data1 <- sample(1:20, size = length(z@data$OBJECTID), replace = T)
z@data$data2 <- sample(1:20, size = length(z@data$OBJECTID), replace = T)
z@data$data3 <- sample(1:20, size = length(z@data$OBJECTID), replace = T)
z@data$data4 <- sample(1:20, size = length(z@data$OBJECTID), replace = T)
#define color palettes
colorPal <- brewer.pal(4, "RdYlGn")
pal <- colorBin(palette = colorPal, domain = 1:20, bins = c(0, 5, 10, 15, 20), pretty = T)
#run shiny app
shinyApp(
ui = fluidPage(
#country dropdown selection
selectInput(inputId = "country",
label = "Country",
choices = c("", z@data$NAME_0),
selected = ""),
#test slider
sliderInput(inputId = "test",
label = "Test Slider",
min = 1,
max = 4,
value = 0,
step = 1,
animate = T), #end slider
#map image
leafletOutput('myMap')#end output, c6, fluidrow
), #END UI
#world level default map output
server <- function(input, output, session) {
#initial map rendering (blank tiles)
output$myMap <- renderLeaflet({
leaflet() %>%
addProviderTiles("CartoDB.PositronNoLabels",
options = tileOptions(noWrap = T)) %>%
setView(lng = 29.85, lat = -2.7, zoom = 7)
}) #END LEAFLET OUTPUT
#observe slider to update map
observe({
#define input as variable
x <- input$test
#create object for input country
dd <- input$country
#subset regions polygon by the selected country
selected <- z[z@data$NAME_0 == dd, ]
#define proxy map object for dynamic updating
proxy <- leafletProxy("myMap")
#create test layerId for polygon removal
test <- selected@data$OBJECTID
if(dd != ""){
#use proxy object so that tiles don't update with each slider input change
proxy %>%
# clearShapes() %>%
addPolygons(data = selected,
fillColor = ~pal(selected@data[[x + 5]]), #add 5 to match column number
fillOpacity = 1,
weight = 1,
stroke = T,
layerId = test)
} #END CONDITIONAL
}) #END OBSERVE EVENT
} #END SERVER
) #END SHINYAPP
There are several different things going on. First, you select your country of interest from the dropdown selection menu (it's important to keep the initial map output as blank tiles with no polygons drawn--shapefiles are only drawn upon country selection from the dropdown menu). From there, you can use the slider to update the choropleth map's color scheme.
I'm using leafletProxy to dynamically update the map so that it is not redrawn every time the user enables some kind of interactivity. This is particularly important when using the slider to update the polygon styles--if the map is redrawn each time, it's very choppy and unsightly. When I run the code as it is written above, the result (in short video form) is here. As you can see, the colors change seamlessly.
With this code, however, I'm not sure how to remove map elements (countries) that have previously been drawn. As you can see in the above linked example, when I click on a second country, the first selected country is not removed. I realize that this is because I'm using leafletProxy
to update the map. I am familiar with using layerIds and removeShape()
to remove polygons, but with the way that my code is written, I can't get it to work. I've tried employing the layerIds in several different ways with zero luck.
I am able to remove previously selected polygons when I uncomment the line clearShapes() %>%
after the proxy
call. Unfortunately, this results in the map redrawing every time the slider is updated, resulting in really ugly choppiness.
Is there any way that I can use leafletProxy
to both remove previously selected polygons AND seamlessly update the map style with the slider?