1
votes

I am working with R in RStudio and created a shiny dashboard. Within the dashboard I am using the leaflet() function to plot a map. Now I am trying to put markers on the map which shows the crimes in chicago. I am working with the selectInput() and sliderInput() function to select different crime type, location and year. If I select something inside the input field the markers are shown up on the chicago map and it works perfect. But I want that when I start the shiny app all markers are displayed without filtering based on selectInput(). This is my ui.R code:

  tabItem(tabName = "map",
    div(class="outer",
    tags$head(
    tags$style(type = "text/css", "#map {height: calc(100vh - 80px) !important;}"))),

    leafletOutput("map", width = "100%", height = "100%"),

    absolutePanel(id = "mapControls", fixed = TRUE, draggable = TRUE, top = 150, left = "auto", right = 15, bottom = "auto", width = 200, height = "auto",

    selectInput("mapCrimeType", label= "Select Crime Type", choices = unique(cc$Primary.Type), multiple = TRUE),

    selectInput("mapLocation", label= "Select Location", choices = unique(cc$Location.Description), multiple = TRUE),

    sliderInput("mapYear", label = "Select Year", min = 2001, max = 2016, step = 1, sep = '', value = c(2001,2016))

          )
  ),

And this my server.R code:

server <- function(input, output) {

  ### Draw Map ###
  output$map = renderLeaflet({
      leaflet() %>% 
      addProviderTiles(providers$Esri.WorldStreetMap) %>% 
      setView(lng = -87.6105, lat = 41.8947, zoom=11)
  }) 

  reactMap = reactive({
    cc %>% 
    filter(Primary.Type %in% input$mapCrimeType &
             Location.Description %in% input$mapLocation &
             Year %in% cbind(input$mapYear[1],input$mapYear[2]))
  })

  observe({
    proxy = leafletProxy("map", data = reactMap()) %>%
      clearMarkers() %>%
      clearMarkerClusters() %>%
      addCircleMarkers(clusterOptions = markerClusterOptions(),
                       lng =~ Longitude, lat =~ Latitude, radius = 5, group = 'Cluster', 
                       popup =~ paste('<b><font color="Black">', 'Crime Information', 
                      '</font></b><br/>', 'Crime Type:', Primary.Type,'<br/>',
                      'Date:', Date,'<br/>', #'Time:', Time,'<br/>',
                      'Location:', Location.Description,'<br/>', 'Block:', Block, '<br/>', 'Arrest:', Arrest, '<br/>'))
  })

I guess I have to change something in the reactive function inside the server.R file. I hope somebody can help me.

UPDATE: Working with this dataset: https://www.kaggle.com/currie32/crimes-in-chicago

2

2 Answers

0
votes

It's difficult to test without example data but you have 1 of 2 options to try that I can think of:

The first option is to preselect all options for mapCrimeType and mapLocation by adding selected = unique(cc$Primary.Type) and selected = unique(cc$Location.Description) respectively. I added mapYear below but nothing needs to change there as you have selected the entire range with value = c(2001,2016) already.

    selectInput("mapCrimeType", label= "Select Crime Type", choices = unique(cc$Primary.Type), multiple = TRUE, selected = unique(cc$Primary.Type)),

    selectInput("mapLocation", label= "Select Location", choices = unique(cc$Location.Description), multiple = TRUE, selected = unique(cc$Location.Description)),

    sliderInput("mapYear", label = "Select Year", min = 2001, max = 2016, step = 1, sep = '', value = c(2001,2016))

If that is too messy (I'm not sure how many choices they have) you can try the below:

  reactMap = reactive({
    if (is.null(input$mapCrimeType)) {
      mapCrimeType = unique(cc$Primary.Type)
    } else {
      mapCrimeType = input$mapCrimeType
    }
    if (is.null(input$mapLocation)) {
      mapLocation = unique(cc$Location.Description)
    } else {
      mapLocation = input$mapLocation
    }
    cc %>% 
    filter(Primary.Type %in% mapCrimeType &
             Location.Description %in% mapLocation &
             Year %in% cbind(input$mapYear[1],input$mapYear[2]))
  })

Basically, whenever either of the selectInputs is NULL we include all choices for that selectInput (or both when both are NULL). Let me know if this helps.

Update

Please try the full answer below. I had a mistake above.

if (is.null(input$mapLocation)) {
      mapLocation = unique(cc$Location.Description)
    } else {
      mapLocation = input$mapLocation
    }

had is.null(input$mapCrimeType) copied from the previous if statement.

Tested answer here:

library(shiny)
library(shinydashboard)
library(leaflet)
library(dplyr)

ui <- tabItem(tabName = "map",
                          div(class="outer",
                              tags$head(
                                  tags$style(type = "text/css", "#map {height: calc(100vh - 80px) !important;}"))),

                          leafletOutput("map", width = "100%", height = "100%"),

                          absolutePanel(id = "mapControls", fixed = TRUE, draggable = TRUE, top = 150, left = "auto", right = 15, bottom = "auto", width = 200, height = "auto",

                                        selectInput("mapCrimeType", label= "Select Crime Type", choices = unique(cc$Primary.Type), multiple = TRUE),

                                        selectInput("mapLocation", label= "Select Location", choices = unique(cc$Location.Description), multiple = TRUE),

                                        sliderInput("mapYear", label = "Select Year", min = 2001, max = 2016, step = 1, sep = '', value = c(2001,2016))

                          )
    )

server <- function(input, output) {

    ### Draw Map ###
    output$map = renderLeaflet({
        leaflet() %>% 
            addProviderTiles(providers$Esri.WorldStreetMap) %>% 
            setView(lng = -87.6105, lat = 41.8947, zoom=11)
    }) 

    reactMap = reactive({
        if (is.null(input$mapCrimeType)) {
            mapCrimeType = unique(cc$Primary.Type)
        } else {
            mapCrimeType = input$mapCrimeType
        }
        if (is.null(input$mapLocation)) {
            mapLocation = unique(cc$Location.Description)
        } else {
            mapLocation = input$mapLocation
        }
        cc %>% 
            filter(Primary.Type %in% mapCrimeType &
                       Location.Description %in% mapLocation &
                       between(Year, input$mapYear[1], input$mapYear[2]))
    })

    observe({
        proxy = leafletProxy("map", data = reactMap()) %>%
            clearMarkers() %>%
            clearMarkerClusters() %>%
            addCircleMarkers(clusterOptions = markerClusterOptions(),
                             lng =~ Longitude, lat =~ Latitude, radius = 5, group = 'Cluster', 
                             popup =~ paste('<b><font color="Black">', 'Crime Information', 
                                            '</font></b><br/>', 'Crime Type:', Primary.Type,'<br/>',
                                            'Date:', Date,'<br/>', #'Time:', Time,'<br/>',
                                            'Location:', Location.Description,'<br/>', 'Block:', Block, '<br/>', 'Arrest:', Arrest, '<br/>'))
    })
}

shinyApp(ui = ui, server = server)

I added the point from lbusett that your Year filter was displaying data only in the min and max years and not the years between, which I've done with the between function from dplyr.

You could incorporate lbusett's answer which is neater as below:

reactMap <- reactive({

  out_cc <- cc %>% 
    dplyr::filter(., Year >= input$mapYear[1] & 
                  Year <= input$mapYear[2])

  if (!is.null(input$mapCrimeType)) {
    out_cc <- out_cc %>% 
      dplyr::filter(., Primary.Type %in% input$mapCrimeType)
  }

  if (!is.null(input$mapLocation)) {
    out_cc <- out_cc %>% 
      dplyr::filter(., Location.Description %in% input$mapLocation)
  }

  out_cc

})
0
votes

Without testing, but this should work. Just change the reactive to:

reactMap <- reactive({

  out_cc <- cc %>% 
    dplyr::filter(., Year %in% cbind(input$mapYear[1],input$mapYear[2]))

  if (!is.null(input$mapCrimeType)) {
    out_cc <- out_cc %>% 
      dplyr::filter(., Primary.Type %in% input$mapCrimeType)
  }

  if (!is.null(input$mapLocation)) {
    out_cc <- out_cc %>% 
      dplyr::filter(., Location.Description %in% input$mapLocation)
  }

  out_cc

})

When called without a "selected" value, and with multiple = TRUE, the selectors have NULL value at the beginning or when you deselect everything. So, you just need to skip the filtering on a given variable when its corresponding input is NULL.

BTW: I may be wrong, but I think you may have to change your "Year" filter to something like:

dplyr::filter(., Year >= input$mapYear[1] & 
                  Year <= input$mapYear[2])

, otherwise you will get only the values of the minimum and of the maximum selected years, and not those of the years in the middle.