How to efficiently handle data with multiple filters in a shiny app

Viewed 4798

We have created a shiny application where either the user can upload a big dataset (RData file over 200MB) or they can pick one from us. Then there are three different tabs where the user can filter the data (tab for numerics, tab for categorics)

So currently I have 3 reactive functions to serve that purpose. But downside is that the object is kept three times in memory. Is there a more efficient way to do this?

Please find a simplified example app below: note: in this app you only see 1 filter per tab. normally its more like this:

My_Filtered_Data[Species %in% input$filter1 &
                   x %in% input$x &
                   y %in% input$y &
                   z %in% input$z] #etc.

I was looking at reactiveValues but couldn't really find how it works. Reason I don't want to have it in 1 reactive is that everytime I change one of the filters on one of the sheets, the entire filtering process starts again and that is quite time consuming. I'd prefer to have one dataset that that gets updated with only the filter that is used at that time. That's the reason I included the different reactives

## app.R ##
library(shinydashboard)
library(data.table)
CustomHeader <- dashboardHeader(title='datatest')
iris<-iris

ui <- function(request) {
  dashboardPage(
    CustomHeader,
    ## Sidebar content
    dashboardSidebar(
      sidebarMenu(
        menuItem("filter1 & Import", tabName = "filter1", icon = icon("dashboard")),
        menuItem("filter2", tabName = "filter2", icon = icon("th")),
        menuItem("filter3", tabName = "filter3", icon = icon("th"))
      )
    ),
    ## Body content
    dashboardBody(
      tabItems(
        # First tab content
        tabItem(tabName = "filter1",
                fluidRow(box(width = 3,
                             selectInput(inputId = 'filter1','filter1:species',choices = unique(iris$Species))))

        ),

        tabItem(tabName = "filter2",
                fluidRow(box(width = 3,
                             sliderInput(inputId = 'filter2','filter2:Max.Sepal.Length',min = 0,max = 10,value = 10)
                                         ))

        ),
        tabItem(tabName = "filter3",
                fluidRow(box(width = 3,
                             sliderInput(inputId = 'filter3','filter3:Min.Sepal.Width',min = 0,max = 10,value = 0)
                             ),
                         box(width=9,dataTableOutput('mydata')))

        )
        )
      )
    )

}
server <- function(input, output) {
  My_Uploaded_Data <- reactive({
    My_Uploaded_Data<-data.table(iris)
    My_Uploaded_Data
  })

  My_Filtered_Data <- reactive({
    My_Filtered_Data<-My_Uploaded_Data()
    My_Filtered_Data[Species %in% input$filter1]
  })

  My_Filtered_Data2 <- reactive({
    My_Filtered_Data2<-My_Filtered_Data()
    My_Filtered_Data2[Sepal.Length < input$filter2]
  })  

  My_Filtered_Data3 <- reactive({
    My_Filtered_Data3<-My_Filtered_Data2()
    My_Filtered_Data3[Sepal.Width > input$filter3]
  })  
  output$mydata<-renderDataTable({
    My_Filtered_Data3()
  })

}
shinyApp(ui, server)

I was hoping something like tthis would work in reactiveValues

 react_vals <- reactiveValues(data = NULL)
  observe(react_vals$data <- MyLoadedData())
  observe(react_vals$data <- react_vals$data[Species %in% input$filter1])
  observe(react_vals$data <- react_vals$data[Sepal.Length < input$filter2])
  observe(react_vals$data <- react_vals$data[Sepal.Width > input$filter3])

EDIT: I also would like to include bookmarks: https://shiny.rstudio.com/articles/advanced-bookmarking.html and it seems you need reactiveValues for that. So another reason for me to move away from all these reactives/eventReactive

2 Answers
Related