2

In working with a map in shiny using mapview, I've been flummoxed by reactives and trying to make my map dynamically update. Here is a reproducible example that doesn't work properly, despite being designed using principles from other SO answers:

#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
#    http://shiny.rstudio.com/
#

library(shiny)
library(sf)
library(mapview)

# Define UI for application that draws a histogram
ui <- fluidPage(

    # Application title
    titlePanel("Test of Mapview Selective Viewing"),

    # Sidebar with a slider input for number of bins 
    sidebarLayout(
        sidebarPanel(
         selectInput("county", "County Name",
                    choices = c("All", levels(franconia$NAME_ASCI)),
                    selected = "All"
         )

        ),

        # Show a plot of the generated distribution
        mainPanel(
           mapviewOutput("mapPlot")
        )
    )
)

# Define server logic required to draw a histogram
server <- function(input, output) {

    fran <- reactive({
        f <- franconia
        if(input$county != "All") f <- franconia %>% filter(NAME_ASCI == input$county)

        f
    })

    output$mapPlot <- renderMapview({

        #get the data
        f <- isolate(fran())

        #generate a map
        mapview(f, zcol = "NAME_ASCI")
    })
}

# Run the application 
shinyApp(ui = ui, server = server)

This works, but the map will not update. I've tried putting in an action button - and putting input$button before the isolate statement, but, that causes the whole thing to throw an error.

I want to either see everything or a single county.

Any thoughts on what is missing/wrong here? I'm somewhat new to shiny and dealing with reactives!

jebyrnes
  • 9,082
  • 5
  • 30
  • 33

4 Answers4

4

Usage of renderMapview seems to be somehow "discouraged" (see https://github.com/r-spatial/mapview/issues/160#issuecomment-398130788; https://github.com/r-spatial/mapview/issues/58). You should instead use renderLeaflet on the @map attribute of the mapview object. This should work:

library(shiny)
library(sf)
library(mapview)
library(leaflet)

# Define UI for application that draws a histogram
ui <- fluidPage(
  
  # Application title
  titlePanel("Test of Mapview Selective Viewing"),
  
  # Sidebar with a slider input for number of bins 
  sidebarLayout(
    sidebarPanel(
      selectInput("county", "County Name",
                  choices = c("All", levels(franconia$NAME_ASCI)),
                  selected = "All"
      )
      
    ),
    
    # Show a plot of the generated distribution
    mainPanel(
      mapviewOutput("mapPlot")
    )
  )
)

# Define server logic required to draw a histogram
server <- function(input, output) {
  
  fran <- reactive({
    f <- franconia
    if(input$county != "All") f <-  f <- franconia[franconia$NAME_ASCI == input$county, ] 
    
    f
  })
  
  output$mapPlot <- renderLeaflet({
    
    #get the data
    f <- fran()
    
    #generate a map
    mapview(f, zcol = "NAME_ASCI")@map
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

(Note that I also had to remove the isolate call as suggested by @Kent Johnson)

HTH!

lbusett
  • 5,801
  • 2
  • 24
  • 47
  • Note, that filter() doesn't work on sf objects the way you have it written. I posted a small fix but you deserve best answer. – Carlos Mercado Jul 15 '20 at 19:30
  • 1
    Change to: f <- franconia[ franconia$NAME_ASCI == input$county, ] and it works. – Carlos Mercado Jul 15 '20 at 19:37
  • 1
    @CarlosMercado `filter` works on sf objects-... provided that it is `dplyr::filter`... Thanks for pointing this out! I modified using your suggestion since it is more "general. – lbusett Jul 16 '20 at 16:12
1

Put the map output inside observe and get rid of the isolate. isolate is preventing the update, observe lets you remove it:

  observe({
    output$mapPlot <- renderMapview({
      f <- fran()
      mapview(f, zcol = "NAME_ASCI")
    })
  })
Kent Johnson
  • 3,320
  • 1
  • 22
  • 23
0

Generally, you shouldn't nest a render output inside an observe, you can split them up like this:

mapPlot <- reactive(mapview(fran(), zcol = "NAME_ASCI"))

output$mapPlot <- renderMapview(mapPlot())
SmokeyShakers
  • 3,372
  • 1
  • 7
  • 18
0

@ibusett is correct but this is the working code including the subsetting (their code only works with input == All).

Edit: they updated their code to match my general subset, but you can use dplyr::filter on sf objects (as they mention).

library(sf)
library(mapview)
library(leaflet)

ui <- fluidPage(
  
  # Application title
  titlePanel("Test of Mapview Selective Viewing"),
  
  # Sidebar with a slider input for number of bins 
  sidebarLayout(
    sidebarPanel(
      selectInput("county", "County Name",
                  choices = c("All", levels(franconia$NAME_ASCI)),
                  selected = "All"
      )
      
    ),
    
    # Show a plot of the generated distribution
    mainPanel(
      mapviewOutput("mapPlot")
    )
  )
)

# Define server logic required to draw a histogram
server <- function(input, output) {
  
  fran <- reactive({
    f <- franconia
    if(input$county != "All"){ 
       f <- franconia[franconia$NAME_ASCI == input$county, ]
       }
    
    f
  })
  
  output$mapPlot <- renderLeaflet({
    
    #get the data
    f <- fran()
    
    #generate a map
    mapview(f, zcol = "NAME_ASCI")@map
  })
}

# Run the application 
shinyApp(ui = ui, server = server)
Carlos Mercado
  • 165
  • 1
  • 5