4

I'm using dplyr in a Shiny app reactive function. I have an interactive widget in the UI that users can use to select status and data will be shown based on selected status. However I also want to give the option to show everything, which is a status that I have called 'All'.

I know how to achieve this without dplyr:

library(tibble)
library(shiny)

# Test Data -----
test_data <- tribble(
  ~id, ~status,
  1, 'active',
  2, 'inactive',
  3, 'test'
)

# Ui ----
ui = fluidPage(
  selectInput("status", "Choose a status:",
              choices = list("All","active","inactive","test")
  ),
  tableOutput('result')
)

# Server ----
server = function(input, output) {

  table <- reactive({
    if(input$status != 'All')
    {
      test_data <- test_data[test_data$status == input$status,]
    } else {
      test_data
    }
  })

  output$result <- renderTable(table(), rownames = FALSE)

}

# App ---
shinyApp(ui = ui, server = server)

However, I would like to be consistent with the rest of my code and use dplyr. Is there a way to do something like the below?

library(tibble)
library(dplyr)
library(shiny)

# Test Data -----
test_data <- tribble(
  ~id, ~status,
  1, 'active',
  2, 'inactive',
  3, 'test'
)

# Ui ----
ui = fluidPage(
  selectInput("status", "Choose a status:",
              choices = list("All","active","inactive","test")
  ),
  tableOutput('result')
)

# Server ----
server = function(input, output) {

  table <- reactive({
    test_data %>%
      filter(ifelse(input$status != 'All', status == input$status, status == ***pass***))
  })

  output$result <- renderTable(table(), rownames = FALSE)

}

# App ---
shinyApp(ui = ui, server = server)

In other words, is there a way to use ifelse inside filter function to not filtering under a certain condition?

Thanks!

Giacomo
  • 1,796
  • 1
  • 24
  • 35

3 Answers3

6

If your desire is to conditionally apply filter depending on the external value, you could attempt to use syntax:

TRUE

table <- reactive({
  test_data %>%
    filter(if(input$status != 'All')  (status == input$status) else TRUE)
}) 

Passing TRUE as condition would then not filter any rows.

{}

Alternative approach uses {} and returns untouched data set: else ..

table <- reactive({
  test_data %>%
  {if(input$status != 'All') filter(status == input$status) else .}
}) 

%<>%

Finally you could consider breaking the pipe and using %<>% operator available in magrittr package:

if(input$status != 'All') test_data %<>% filter(status == input$status)
Konrad
  • 17,740
  • 16
  • 106
  • 167
3

I do not think that is possible. You could do as follows:

if(input$status!="All")
  test_data %>% filter(status %in% input$status)
else
  test_data

So you only filter if the input is not "All". If you have a very long dplyr chain and you do not want to break it into pieces, you could also do:

if(input$status=="All")
  my_filter=unique(test_data$status)
else
  my_filter = input$status

test_data %>%
  filter(status %in% my_filter) %>%
  ..... %>%
  .....

Hope this helps.

Giacomo
  • 1,796
  • 1
  • 24
  • 35
Florian
  • 24,425
  • 4
  • 49
  • 80
  • 1
    Thanks. The first example you posted needed an else otherwise it was print an empty table with option 'All' - I have edited your post to reflect that. I like the second example you posted. – Giacomo Aug 24 '17 at 09:49
  • @Florian Why, maybe I'm missing something but the way I see it is that the only challenge is for dplyr's filter function to evaluate to `TRUE` depending `input$status == "All"` and return all rows. – Konrad Mar 21 '18 at 16:29
1

How about:

table <- reactive({
test_data %>%
filter(status == input$status | input$status == 'All')
}) 
Algomas
  • 61
  • 7