Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to update polygon fill in leaflet for shiny without recreating the map object

Tags:

r

leaflet

shiny

In leaflet, I would normally create a map with:

server.R

shinyServer(function(input, output, session) {
url <- "custommapboxurl"
attrib <- "Maps by http://www.mapbox.com/Mapbox"

...
     map_out <- reactive({

        map <- leaflet()%>%
        addTiles(urlTemplate = url, attribution = HTML(attrib))%>%
        addPolygons(data = sub_shape,
                    fill = TRUE,
                    fillColor = colors$color,
                    fillOpacity = .8,
                    stroke = TRUE,
                    weight = 3,
                    color = "white",
                    dashArray = c(5,5),
                    popup = pops
        )
    })

    output$myMap <- renderLeaflet({
            map_out()
    })
...
})

sub_shape above is my shapefile (in this case, zip codes in the US), and colors$color is a dynamic vector of colours that corresponds to each shape. You could recreate with the link here: http://www.nws.noaa.gov/geodata/catalog/national/html/province.htm, and colors <- data.frame(color = colorRampPalette(c("white","blue"))(13))

ui.R

shinyUI(
    ...
    leafletOutput('myMap', width = "100%" , height = "100%")
    ...
)

This gives:

enter image description here

What I would like to do is change the vector of colours based on a user's input. For example, they might select a different variable to colour each zip code by, generating a new gradient.

Shiny allows us to do this, as if I change the color vector based on an input widget, the reactive function refreshes, and recreates the map based on the new vector. The problem is that with large shapefile objects, this refresh takes a long time.

Is there any way to change the color of the currently rendered shapes directly, without recreating the entire layer? It seems like the color argument is locked within the leaflet() function. Is there any other way to get at it?

like image 938
Chris Avatar asked May 07 '15 02:05

Chris


People also ask

How do you add a polygon to a leaflet?

Create a polygon using the L. Pass the locations/points as variable to draw the polygon, and an option to specify the color of the polygon. var polygon = L. polygon(latlngs, {color: 'red'}); Add the polygon to the map using the addTo() method of the Polygon class.


1 Answers

To illustrate @Yihui Xie's comment, here is an example using leafletProxy to change the colors of the Polygon, based on a selectInput.

library(shiny)
library(leaflet)
library(sp)
library(raster)

## Spatial Polygon ##########
Sr1 = Polygon(cbind(c(2,4,4,1,2),c(2,3,5,4,2)))
Sr2 = Polygon(cbind(c(5,4,2,5),c(2,3,2,2)))
Sr3 = Polygon(cbind(c(4,4,5,10,4),c(5,3,2,5,5)))
Sr4 = Polygon(cbind(c(5,6,6,5,5),c(4,4,3,3,4)), hole = TRUE)
Srs1 = Polygons(list(Sr1), "s1")
Srs2 = Polygons(list(Sr2), "s2")
Srs3 = Polygons(list(Sr3, Sr4), "s3/4")
SpP = SpatialPolygons(list(Srs1,Srs2,Srs3), 1:3)
SpPDF <- SpatialPolygonsDataFrame(SpP, data = data.frame(x=1:length(SpP)), match.ID = F)
Extent = extent(SpPDF)

## UI ##########
ui <- fluidPage(
  selectInput("col", label = "Select a color", choices = c("Blues", "viridis", "magma")),
  leafletOutput("map")
)

## SERVER ##########
server <- function(input, output) {
  output$map <- renderLeaflet({
    leaflet()  %>% 
      addTiles() %>% 
      fitBounds(lng1 = Extent[1],lat1 = Extent[3], lng2 = Extent[2], lat2 = Extent[4])
  })

  observe({
    req(input$col)
    pal = colorFactor(input$col, domain = factor(SpPDF$x))
    leafletProxy("map") %>%
      addPolygons(data = SpPDF, color = ~pal(factor(SpPDF$x)))
  })
}

shinyApp(ui, server)
like image 146
SeGa Avatar answered Nov 14 '22 18:11

SeGa