Keith McNulty
Keith McNulty

Reputation: 972

Passing dplyr filter conditions from shiny inputs into a function

I have been trying to create a general function to use in Shiny apps that will allow a dataframe to be filtered by an arbitrary list of conditions using a sidebar menu. So you can use the sidebar menu to pick both the columns you want to filter on and the conditions you wish to filter by.

Here is a trimmed down reproducible example of the Rmd that I have created which currently works for my purposes, using the mtcars dataset:

https://github.com/keithmcnulty/flexfiltering/blob/master/index.Rmd

Refer to my functions filter1_by, filter2_by, etc, built using dplyr::filter_at because I have to treat the column names differently from the values in non-standard evaluation. This has forced me to have to create several functions depending on how many filters I want. For example:

filter2_by <- function(df, f1, fv1, f2, fv2) {
  filter_f1 <- quo(f1)
  filter_f2 <- quo(f2)

df %>%
  dplyr::filter_at(vars(!!filter_f1), all_vars(. == fv1)) %>%
  dplyr::filter_at(vars(!!filter_f2), all_vars(. == fv2))
}

What I really want to do is just create a single function filter_by(df, ...) which will accept an arbitrary set of filter conditions, for example:

filter_by(mtcars, input$filter1 == input$filter1val, 
                  input$filter2 == input$filter2val)

Would love any advice on how to code filter_by.

Thanks!

Upvotes: 2

Views: 1151

Answers (1)

ozanstats
ozanstats

Reputation: 2864

dplyr is not the only option to achieve your goal. With a simple Google search, it is possible to find many distinct ways to filter a data frame in R . In fact, the key to solving your problem here is the knowledge of the Shiny framework (i.e. return types, reactivity, etc) as you need to adapt any filtering method to your needs in the context.

Below is a concise Shiny example that includes everything you want. In addition to the filtering issue you stated, your code was very complicated. updateSelectInput will be your friend.

library(shiny)
library(kableExtra)

ui <- fluidPage(
  selectInput(
    inputId = "column",
    label = "Choose a column",
    choices = names(mtcars),
    selected = "mpg"
  ),
  selectInput(
    inputId = "value",
    label = "Filter by:",
    choices = sort(mtcars$mpg),
    multiple = T
  ),
  htmlOutput(
    outputId = "table"
  )
)

server <- function(input, output, session) {
  observeEvent(input$column, {
    updateSelectInput(
      session = session,
      inputId = "value",
      choices = sort(mtcars[[input$column]]),
      selected = sort(mtcars[[input$column]])[1]
    )
  })
  output$table <- renderText({
    if(length(input$value) != 0) {
      kable(
        mtcars[mtcars[[input$column]] %in% as.numeric(input$value), ]
        ## just chain any additional conditions using &:
        # mtcars[
        #   mtcars[[input$column]] %in% as.numeric(input$value) &
        #   mtcars[[input$column2]] %in% as.numeric(input$value2) &
        #   mtcars[[input$column3]] %in% as.numeric(input$value3)
        # , ]
      )
    }
  })
}

shinyApp(ui = ui, server = server)

Upvotes: 3

Related Questions