1

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

S002
  • 31
  • 7

2 Answers2

0

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

})
Eli Berkow
  • 2,628
  • 1
  • 12
  • 22
  • This link might be useful for selecting all. It's neater than the default https://github.com/dreamRs/shinyWidgets#select-picker – Eli Berkow Dec 11 '18 at 14:38
  • thanks eli, but your code didnt work. its not selecting all :/ – S002 Dec 13 '18 at 11:38
  • It seems as if you need to give us a minimal reproducible example as we can't test our answers at the moment. Please include some dummy data otherwise, unfortunately, this exercise seems pointless. – Eli Berkow Dec 13 '18 at 11:52
  • check my question, i inserted the dataset iam working with – S002 Dec 13 '18 at 11:59
  • Thanks, that should help – Eli Berkow Dec 13 '18 at 12:07
  • Thanks ELI for your answer! I really appreciate, but it doesnt show me the map now. I guess it is calculating all the data, which seems to long. very long. have to present this in a 5 min presentation so I need to take the old code (my code) maybe. But at my code if I use the selected = "THEFT" code for example and I run the app it doenst show me the marker of my selected input, why? It starts showing me the markers only if I select something inside the selectInput box, but from beginning not. – S002 Dec 14 '18 at 17:26
  • I tested your code and after I added selected = "STREET" for Location.Description (for example) it worked as that was still NULL. Please at least make the code change Ibusett mentioned to include all years between the min and max otherwise your code is incorrect. – Eli Berkow Dec 15 '18 at 20:13
  • Concerning the issue of rendering the large number of markers you could also try leaflet.glify - (devtools::install_github("tim-salabim/leaflet.glify")) See https://github.com/tim-salabim/leaflet.glify. I mentioned it here https://stackoverflow.com/questions/53038090/r-leaflet-limitations-how-many-markers-does-a-leaflet-map-support/53041771 – Eli Berkow Dec 15 '18 at 20:17
0

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.

Eli Berkow
  • 2,628
  • 1
  • 12
  • 22
lbusett
  • 5,801
  • 2
  • 24
  • 47
  • thanks for your code and answer but this didnt work. Even if i select something in my selectInput field the shiny app crashs. – S002 Dec 13 '18 at 11:38
  • Do you get any error messages you can share? However, this is difficult to debug without a reproducible example. Could you try creating one (that is, a minimal shiny app reproducing the problem) ? – lbusett Dec 13 '18 at 13:09
  • It crashed as a result of copying parts from my answer so variables like mapCrimeType and mapLocation which I created don't exist here. I have made edits so it should be working now. – Eli Berkow Dec 14 '18 at 14:20
  • The second !is.null(input$mapCrimeType) needs to be !is.null(input$mapLocation) and mapCrimeType and mapLocation need to be input$mapCrimeType and input$mapLocation. As mentioned, I have made all these edits so once they're accepted the code should work. – Eli Berkow Dec 14 '18 at 14:23
  • Glad to be of assistance! – Eli Berkow Dec 15 '18 at 19:59