Search code examples
rshinyuser-inputshinydashboardshiny-server

Interdependent Filter cascading in R Shiny - updatePickerInput


I have 4 PickerInputs in the R Shiny app, and the output is a filtered dataframe from these inputs. Sometimes these inputs are selected, and sometimes they are not (means do not apply any filter).

Problem: I want all these inputs to be cascaded by the selection of each other.

column(width=2, id="filters",
       
       shinyWidgets::pickerInput(
         inputId = "filter_a",
         label = 'Filter A',
         choices = c(""),
         multiple = FALSE),
       
       shinyWidgets::pickerInput(
         inputId = "filter_b",
         label = 'Filter B',
         choices = c(""),
         multiple = FALSE),
       
       shinyWidgets::pickerInput(
         inputId = "filter_c",
         label = 'Filter C',
         choices = c(""),
         multiple = FALSE),
       
       shinyWidgets::pickerInput(
         inputId = "filter_d",
         label = 'Filter D',
         choices = c(""),
         multiple = FALSE)
       )

Server: The if-else way of writing these inter-dependent filter cascading does not look good. It is definitely not optimized code. How can I write it as a function?

I need each filter to observe the other 3 filters, and update choices.

Example for updating 'filter C':

observeEvent(c(input$filter_a, input$filter_b, input$filter_d),
             
             {updatePickerInput(session = session,
                                inputId = 'filter_c',
                                
                                choices = if(input$filter_a==" All" & input$filter_b == " All" & input$filter_d == " All"){sort(c(" All", unique(df$column_c)))
                                }else if(input$filter_a ==" All" & input$filter_b == " All" & input$filter_d != " All"){sort(c(" All", unique(df$column_c[df$column_d==input$filter_d])))
                                }else if(input$filter_a ==" All" & input$filter_b != " All" & input$filter_d == " All"){sort(c(" All", unique(df$column_c[df$column_b==input$filter_b])))
                                }else if(input$filter_a !=" All" & input$filter_b == " All" & input$filter_d == " All"){sort(c(" All", unique(df$column_c[df$column_a==input$filter_a])))
                                }else if(input$filter_a ==" All" & input$filter_b != " All" & input$filter_d != " All"){sort(c(" All", unique(df$column_c[df$column_b==input$filter_b & df$column_d==input$filter_d])))
                                }else if(input$filter_a !=" All" & input$filter_b == " All" & input$filter_d != " All"){sort(c(" All", unique(df$column_c[df$column_a==input$filter_a & df$column_d==input$filter_d])))
                                }else if(input$filter_a !=" All" & input$filter_b != " All" & input$filter_d == " All"){sort(c(" All", unique(df$column_c[df$column_a==input$filter_a & df$column_b==input$filter_b])))
                                }else{sort(c(" All", unique(df$column_c[df$column_a==input$filter_a & df$column_b==input$filter_b & df$column_d==input$filter_d])))},
                                selected = c(" All"))
             })

column_a, column_b, column_c and column_d are the 4 filter columns in my df based on which I am selecting filter_a, filter_b, filter_c, filter_d respectively.


Solution

  • Perhaps this might be slightly better

    observeEvent(c(input$filter_a, input$filter_b, input$filter_d), {
       
      if(input$filter_a==" All") {fa <- unique(df$column_a)} else fa <- input$filter_a
      if(input$filter_b==" All") {fb <- unique(df$column_b)} else fb <- input$filter_b
      if(input$filter_d==" All") {fd <- unique(df$column_d)} else fd <- input$filter_d
    
      choices <- c(" All", unique(df$column_c[df$column_a %in% fa & df$column_b %in% fb & df$column_d %in% fd]))
      updatePickerInput(session = session, inputId = 'filter_c', choices = choices, selected = c(" All"))
    
    })