zesla
zesla

Reputation: 11833

selectInput is not responding to action button properly in my leaflet map shiny app

I need to create an interactive map with leaflet package, where I can use a selectInput to control what data points to show on the map. I also want to use the layer control button to select one or both layers (data points) to appear on the map. My code is shown below.

I want the map to respond to selectInput only when go button is clicked.

My code works when I select one item in the selectInput (map refreshes when I click go). I found when I select the second item, initially I see error: subscript out of bounds. When go clicked, both markers appear. When I remove one of the two item selected, the map responds before the action button clicked.

It appears that the selectInput is not responding to action button properly. Does anyone know why that happens? What did I do wrong? I spend hours trying to figure it out but no luck...... Thanks a lot in advance.

library(shiny)
library(leaflet)


hotels <- read.table(text = "Hotel Year  latitude        longitude
                              A   2000  41.886337      -87.628472
                              B   2005  41.88819       -87.635199
                              C   2010  41.891113      -87.63301", 
                     header = TRUE)


ui <- fluidPage(

    selectizeInput(inputId = 'year', label='Choose Year:',
                   choices = c(2000,2005,2010),
                   multiple=TRUE,
                   options = list(
                       maxItems = 2,
                       placeholder = '',
                       onInitialize = I("function() { this.setValue(''); }"))),
    actionButton("go", "go"),
    leafletOutput("mymap")

)

server <- function(input, output, session) {

    df_list = reactive ({
        input$go

        isolate(
            if (length(input$year)>1) {
                list(hotels[hotels$Year == input$year[1],], 
                     hotels[hotels$Year == input$year[2],])
            } else {
                list(hotels[hotels$Year == input$year[1],])
            }

        )
    })

    output$mymap <- renderLeaflet({

        map = leaflet()  %>%
            addProviderTiles("OpenStreetMap.Mapnik") %>% 
            addCircleMarkers( data = df_list()[[1]] ,
                              group = 'Data Markers 1',
                              lng = ~longitude,
                              lat = ~latitude,
                              radius = 10,
                              stroke = F,
                              fillOpacity = 0.9,
                              color = 'red')
        if ( length(input$year)>1){
            map = map %>% 
                addCircleMarkers( data = df_list()[[2]] ,
                                  group = 'Data Markers 2',
                                  lng = ~longitude,
                                  lat = ~latitude,
                                  radius = 10,
                                  stroke = F,
                                  fillOpacity = 0.9,
                                  color = 'blue')
        }

        if ( length(input$year)>1) {
            map = map %>% 
                addLayersControl(
                    overlayGroups = c('Data Markers 1', 'Data Markers 2'),
                    options = layersControlOptions(collapsed = FALSE) )
        } else {
            map = map %>% 
                addLayersControl(
                    overlayGroups = c('Data Markers 1'),
                    options = layersControlOptions(collapsed = FALSE) )
        }

    })
}

shinyApp(ui, server)

Upvotes: 1

Views: 416

Answers (1)

mnist
mnist

Reputation: 6954

The main point is that you should use observeEvent() when working with action buttons. You mixed up the reactive path, so values changed not in the order you assumed they would.

library(shiny)
library(leaflet)


hotels <- read.table(text = "Hotel Year  latitude        longitude
                     A   2000  41.886337      -87.628472
                     B   2005  41.88819       -87.635199
                     C   2010  41.891113      -87.63301", 
                     header = TRUE)


ui <- fluidPage(

  selectizeInput(inputId = 'year', label='Choose Year:',
                 choices = c(2000,2005,2010),
                 multiple=TRUE,
                 options = list(
                   maxItems = 2,
                   placeholder = '',
                   onInitialize = I("function() { this.setValue(''); }"))),
  actionButton("go", "go"),
  leafletOutput("mymap")

)

server <- function(input, output, session) {

  # use the button for observeEvent
  # ignore values ensure an empty map is loading in the beginning
  observeEvent(input$go, ignoreInit = FALSE, ignoreNULL = FALSE, {

    # no need for a reactive list here
    if (length(input$year)>1) {
      df_list <- list(hotels[hotels$Year == input$year[1],], 
                     hotels[hotels$Year == input$year[2],])
    } else {
      df_list <- list(hotels[hotels$Year == input$year[1],])
    }

    output$mymap <- renderLeaflet({
      map <- leaflet()  %>%
        addProviderTiles("OpenStreetMap.Mapnik") %>% 
        addCircleMarkers( data = df_list[[1]] ,
                          group = 'Data Markers 1',
                          lng = ~longitude,
                          lat = ~latitude,
                          radius = 10,
                          stroke = F,
                          fillOpacity = 0.9,
                          color = 'red')
      # not using input does not invoke reactiveness
      if ( length(df_list) > 1){
        map <- map %>% 
          addCircleMarkers( data = df_list[[2]] ,
                            group = 'Data Markers 2',
                            lng = ~longitude,
                            lat = ~latitude,
                            radius = 10,
                            stroke = F,
                            fillOpacity = 0.9,
                            color = 'blue')
      }

      if ( length(input$year)>1) {
        map <- map %>% 
          addLayersControl(
            overlayGroups = c('Data Markers 1', 'Data Markers 2'),
            options = layersControlOptions(collapsed = FALSE) )
      } else {
        map <- map %>% 
          addLayersControl(
            overlayGroups = c('Data Markers 1'),
            options = layersControlOptions(collapsed = FALSE) )
      }

      map
    })
  })
}

shinyApp(ui, server)

Note: Rather use assignment arrows for assignment ;)

Upvotes: 2

Related Questions