Shiny App not filtering using dplyr and %in% operator

Viewed 130

I am making an app using the diamond dataset that I'd like to show the full table unless inputs are selected. However, if I select, say, cut by itself nothing appears. Also, if I select a lot of things no additional diamonds appear. Here's my code:

library(shiny)
library(DT)
library(tidyverse)

diamonds <- diamonds

#Shiny App

ui = fluidPage(
    fluidRow(
        column(2, selectizeInput(inputId = 'carat',
                                 label = 'Select carat',
                                 choices = unique(diamonds$carat),
                                 selected = NULL,
                                 multiple=TRUE)),
        column(2, selectizeInput(inputId = 'cut',
                                 label = 'Select cut',
                                 choices = unique(diamonds$cut),
                                 selected = NULL,
                                 multiple=TRUE)),
        column(2, selectizeInput(inputId = 'color',
                                 label = 'Select color',
                                 choices = unique(diamonds$color),
                                 selected = NULL,
                                 multiple=TRUE))
    ),
    fluidRow (
        column(12, dataTableOutput('data', height = '100px') ) 
    )           
)

server <- function(input, output, session) {

    df_current <- reactive({
        df <- diamonds%>% 
            filter(carat %in% ifelse(is.null(input$carat), carat, input$carat),
                   cut %in% ifelse(is.null(input$cut), color, input$cut),
                   color %in% ifelse(is.null(input$color), color, input$color))

        df

    })

    output$data <- renderDataTable({

        df_current()

    })
    }



    shinyApp(ui = ui, server = server)

I am not sure why the reactive function df_current doesn't work correctly.

Thanks!

2 Answers

We could change the ifelse to if/else as ifelse requires all the inputs to be same length whereas the is.null returns a single TRUE/FALSE. So, it is better to use if/else. Also, calling unique inside ifelse is also not a correct way because it changes the length of the argument

server <- function(input, output, session) {
   df_current <- reactive({
    df <- diamonds%>% 
        filter(carat %in% if(is.null(input$carat)) carat else input$carat,
               cut %in% if(is.null(input$cut)) cut else input$cut,
               color %in% if(is.null(input$color)) color else input$color)

    df

     })

  output$data <- renderDataTable({

    df_current()

})
}

-output

enter image description here

The problem is that ifelse doesn't deal correctly with the factor variables and returns the numbers of the factor levels instead of the factor level. You can circumvent this by using as.character. Also, I've used unique because you don't need the complete column as the return value.

The second issue is that you have a typo in your filtering for cut as you use color instead of cut as the return value.

server <- function(input, output, session) {
  
  df_current <- reactive({
    
    df <- diamonds%>% 
      filter(carat %in% ifelse(is.null(input$carat), unique(carat), input$carat),
             cut %in% ifelse(is.null(input$cut), as.character(unique(cut)), input$cut),
             color %in% ifelse(is.null(input$color), as.character(unique(color)), input$color))
    
    df
    
  })
  
  output$data <- renderDataTable({
    
    df_current()
    
  })
}
Related