Search code examples
rshinyr-leaflet

Conditional filtering based on user inputs in Shiny


User new to Shiny here. I am trying to create an interactive map which adds circle markers based on 2 groups of users inputs: where each group has 3 possible inputs. I can't seem to figure out how to write the code to properly filter the data and then add the filtered data as circle markers. The filtering logic should go like this:

1) If Religion / Denomination / World = "All", skip that specific filter. (e.g. If Religion 1 = "All", do not filter by Religion 1, but still filter by the rest of the fields if they are not "All").

2) If denomination 1 / 2 is "None", only return the information of the Religion, and exclude the denomination info. (E.g. If Religion 1 = "Christians", Denomination = "None", Geography = "United Kingdom", only the Christian Totals in the UK should be mapped).

3) For all other specific inputs, apply the & operator. (E.g. If Religion 1 = "Christians", Denomination = "Catholics", Geography = "United Kingdom", it should only show Catholics in the UK).

I guess I could just write multiple if / else statements for each possible permutation, but then there will be a lot of conditions and I will have to repeat them twice so that it works for group 1 and group 2.

The year slider input filter should be reactive while the rest of the selectInputs should only work after the user clicks the button.

Here's my UI code:

ui <- fluidPage (
  titlePanel("Religious Affiliations from 1900", windowTitle = "Browser"),
  sidebarLayout(
    sidebarPanel(width = 3,
    conditionalPanel(
      condition = "input.conditionedPanels == 1",
      sliderTextInput("years_map", "Select Year:", 
                      choices = years, selected = 2000,
                      animate = TRUE, grid = TRUE),
      selectInput("religion_1_map", "Religion 1",
                  choices = c("All", religion_names), 
                  selectize = TRUE),  
      selectInput("denom_1_map", "Denomination 1",
                  choices = c("All", "None", denomination_names), 
                  selectize = TRUE),
      selectInput("geography_1_map", "Geography 1", 
                  choices = c("World", all_geography, names(all_regions)), selectize = TRUE),
      selectInput("religion_2_map", "Religion 2",
                  choices = c("All", religion_names),
                  selectize = TRUE),
      selectInput("denom_2_map", "Denomination 2",
                  choices = c("All", "None", denomination_names),
                  selectize = TRUE),
      selectInput("geography_2_map", "Geography 2",
                  choices = c("World", all_geography), selectize = TRUE),
      actionButton("map_button", "Map my choices!")
    ),
  mainPanel(width = 9,
    tabsetPanel(
      tabPanel("Maps", 
      leafletOutput("mymap"),
               value = 1),

      tabPanel("Stacked Area Chart", 
               "test2",
               value = 2),
      tabPanel("Pie Chart", value = 3),
      tabPanel("Line Chart", value = 4),
      tabPanel("Statistics", value = 5),
      tabPanel("Data", value = 6),
      id = "conditionedPanels"
      )


server <- function(input, output) {


  output$mymap <- renderLeaflet({
    leaflet() %>% addTiles()
    #Make the map dependent on the button
    input$map_button
  })

  year <- reactive({
    all_cleaned %>% filter(year == input$years_map)
  })

  religion_1 <- reactiveValues({
    if(input$religion_1_map == "All") {
      year()
    }
    else if(input$religion_1_map == "None") {
      return()
    }
    else {
      year() %>% filter(religion == input$religion_1_map)
    }
  })

  denom_1 <- reactive({
    if(input$denom_1_map == "All") {
      religion_1()
    }
    else if(input$denom_1_map == "None") {
      religion_1[!duplicated(religion_1[,'religion']), ]
    }
    else {
      religion_1() %>% filter(denom == input$denom_1_map)
    }
  })

  geography_1 <- reactive({
    if(input$geography_1_map == "All") {
      denom_1()
    }
    else if(input$geography_1_map == "None") {
      return()
    }
    else {
      denom_1() %>% filter(country_name %in% input$geography_1_map)
    }
  })

  religion_2 <- reactiveValues({
    if(input$religion_2_map == "All") {
      year()
    }
    else if(input$religion_2_map == "None") {
      return()
    }
    else {
      year() %>% filter(religion == input$religion_2_map)
    }
  })

  denom_2 <- reactive({
    if(input$denom_2_map == "All") {
      religion_2()
    }
    else if(input$denom_2_map == "None") {
      religion_2[!duplicated(religion_2[,'religion']), ]
    }
    else {
      religion_2() %>% filter(denom == input$denom_2_map)
    }
  })

  geography_2 <- reactive({
    if(input$geography_2_map == "All") {
      denom_2()
    }
    else if(input$geography_2_map == "None") {
      return()
    }
    else {
      denom_2() %>% filter(country_name %in% input$geography_2_map)
    }
  })

  proxy <- observeEvent(input$map_button, {
    leafletProxy("mymap") %>% 
      addCircleMarkers(data = geography_1()) %>%
      addCircleMarkers(data = geography_2())
  })

}

Update: To fix the problem of subsetting from a reactive filter, I simply cleaned my data instead for a workaround. It now works.


Solution

  • I guess it is hard to give you a proper answer without your server.R file. In my opinion this is pretty straight forward reactive and/or eventReactive Programming. The easiest way is to label the data (entrys and columns) the way you want it to be displayed in the UI. This enables reactive programming. Please upload your current server.R file or a reproducible example.

    EDIT: Call filtered dataset from the reactive the shiny way: year --> year() change the second reactive from:

    religion_1 <- reactive({
    if(input$religion_1_map == "All") {
      year
    }
    else if(input$religion_1_map == "None") {
      return()
    }
    else {
      year %>% filter(religion == input$religion_1_map)
    }
    })
    

    to this:

    religion_1 <- reactive({
    if(input$religion_1_map == "All") {
      year()
    }
    else if(input$religion_1_map == "None") {
      return()
    }
    else {
      year() %>% filter(religion == input$religion_1_map)
    }
    })
    

    and respectively the others as well.

    Update server <- function(input, output) {

    output$mymap <- renderLeaflet({
    leaflet() %>% addTiles()
    #Make the map dependent on the button
    input$map_button
    })
    
    year <- reactive({
    all_cleaned %>% filter(year == input$years_map)
    })
    
    religion_1 <- reactiveValues({
    if(input$religion_1_map == "All") {
      year()
    }
    else if(input$religion_1_map == "None") {
      return()
    }
    else {
      year() %>% filter(religion == input$religion_1_map)
    }
    })
    
    denom_1 <- reactive({
    if(input$denom_1_map == "All") {
      religion_1()
    }
    else if(input$denom_1_map == "None") {
      unique(religion_1())
    }
    else {
      religion_1() %>% filter(denom == input$denom_1_map)
    }
    })
    
    geography_1 <- reactive({
    if(input$geography_1_map == "All") {
      denom_1()
    }
    else if(input$geography_1_map == "None") {
      return()
    }
    else {
      denom_1() %>% filter(country_name %in% input$geography_1_map)
    }
    })
    
    religion_2 <- reactive({
    if(input$religion_2_map == "All") {
      year()
    }
    else if(input$religion_2_map == "None") {
      return()
    }
    else {
      year() %>% filter(religion == input$religion_2_map)
    }
    })
    
    denom_2 <- reactive({
    if(input$denom_2_map == "All") {
      religion_2()
    }
    else if(input$denom_2_map == "None") {
      unique(religion_2())
    }
    else {
      religion_2() %>% filter(denom == input$denom_2_map)
    }
    })
    
    geography_2 <- reactive({
    if(input$geography_2_map == "All") {
      denom_2()
    }
    else if(input$geography_2_map == "None") {
      return()
    }
    else {
      denom_2() %>% filter(country_name %in% input$geography_2_map)
    }
    })
    
    proxy <- observeEvent(input$map_button, {
    leafletProxy("mymap") %>% 
      addCircleMarkers(data = geography_1()) %>%
      addCircleMarkers(data = geography_2())
    })
    
    }