Reputation: 11833
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
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