Semihcan Doken
Semihcan Doken

Reputation: 828

How to make one of the filter functions conditional in a reactive function for a shiny flexdashboard?

I have a dataset and am building a shiny flexdashboard with multiple user inputs which filter the data down to a subset. I am struggling with just one of the filters, where if the user chooses 'ALL' in selectInput, I want that filter function not to do anything and just return the data as is. Below is one of my attempts:

library(flexdashboard)
library(DT)
library(lubridate)
library(readr)
library(tidyverse)
...
qry <- read_file("some_query.sql")
Data_df  <- con %>% tbl(sql(qry)) %>% collect()
doctors_to_choose <- unique(pull(Data_df, 'Doctor')) %>%append('ALL')


Column {data-width=200 .sidebar}
-----------------------------------------------------------------------

```{r}
checkboxGroupInput("drug_classes",
  label = "Choose the classes of drugs",
  choices = c("II", "III", "IV", "V"),
  selected = c("V"),
)


selectInput(
  inputId="chosen_doctor",
  label="Choose Doctor",
  choices=doctors_to_choose,
  selected = "ALL",
  multiple = FALSE,
  size = NULL
)


show_data_df <- reactive({
  Data_df %>% 
filter(`Drug Class` %in% input$drug_classes) %>%
 {if (input$chosen_doctor != "ALL") filter(Doctor == input$chosen_doctor ) 
else filter(`Drug Class` %in% input$drug_classes) }
} )
``` 

I tried to use an if-else statement as above but failed. because In the original code, I have a long list of filters applied so ideally I would like to use something that does not require me to retype all the previous filters/actions like I did in the else part above.

Upvotes: 0

Views: 269

Answers (2)

Limey
Limey

Reputation: 12461

@TimTeaFan has given you a very good answer. I am not suggesting you should change your acceptance of his answer.

In response to your question in comment about placeholders, here's a demonstration of the technqiue. I've used Shiny rather than flexdashboard because it's easier to see changes in action, but the principle will carry over into dashboard directly. Also, because I don't have access to your input data, I've used mtcars as a data source.

The method I've demonstrated works for any number of potential filters without the need to retype any of the filter code.

And to answer your direct question: yes, I did mean "". That was something I didn't notice when using an unfamiliar keyboard.

library(shiny)
library(tidyverse)

cylChoices <- c("", sort(unique(mtcars$cyl)))
names(cylChoices) <- c("- All -", sort(unique(mtcars$cyl)))
gearChoices <- c("", sort(unique(mtcars$gear)))
names(gearChoices) <- c("- All -", sort(unique(mtcars$gear)))

ui <- fluidPage(
  selectInput(
    "cylCount", 
    "Cylinder count:", 
    multiple=TRUE,
    selected="- All -",
    choices=cylChoices
  ),
  selectInput(
    "gearCount", 
    "Gear count:", 
    multiple=TRUE,
    selected="- All -",
    choices=gearChoices
  ),
  tableOutput("table")
)

server <- function(input, output, session) {
  filteredData <- reactive({
    df <- as_tibble(mtcars, rownames="Model")
    if (!is.null(input$gearCount)) df <- df %>% filter(gear %in% input$gearCount)
    if (!is.null(input$cylCount)) df <- df %>% filter(cyl %in% input$cylCount)
    df
  })
  
  output$table <- renderTable({ filteredData() })
}

shinyApp(ui, server)

Upvotes: 1

TimTeaFan
TimTeaFan

Reputation: 18541

One option is to use purrr::when to apply a case_when like statement within the pipe logic for data.frames:

library(dplyr)
library(purrr)

Data_df %>% 
  filter(`Drug Class` %in% input$drug_classes) %>% 
  when(input$chosen_doctor != "ALL" ~ filter(., Doctor == input$chosen_doctor),
       TRUE                         ~ filter(., `Drug Class` %in% input$drug_classes))

Upvotes: 0

Related Questions