如何在闪亮的应用中使用多个过滤器有效处理数据

时间:2017-07-27 08:06:47

标签: r memory shiny data.table reactive-programming

我们创建了一个闪亮的应用程序,用户可以上传大数据集(RDB文件超过200MB),也可以从我们这里选择一个。然后有三个不同的选项卡,用户可以在其中过滤数据(数字选项卡,分类选项卡)

所以目前我有3 reactive个功能来实现这个目的。但缺点是对象在内存中保留了三次。有没有更有效的方法来做到这一点?

请在下面找到简化的示例应用: 注意:在此应用中,每个标签只能看到1个过滤器。通常它更像是这样:

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

我在看reactiveValues,但无法找到它是如何运作的。 我不希望在1 reactive中使用它的原因是,每当我更改其中一个工作表上的其中一个过滤器时,整个过滤过程再次启动,这非常耗时。我更喜欢只使用当时使用的过滤器来更新一个数据集。这就是我加入不同反应的原因

## 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)

我希望像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])

编辑:我还想包含书签:https://shiny.rstudio.com/articles/advanced-bookmarking.html,您似乎需要reactiveValues。这是我离开所有这些reactives / eventReactive

的另一个原因

2 个答案:

答案 0 :(得分:5)

不是将数据集存储在反应变量中,而是存储符合条件的行。这样,每个无功值仅在其滤波器改变时被替换;他们没有联系在一起。输出只使用通过所有过滤器的行。

在该计划的顶部,将iris更改为data.table

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

然后将其用于服务器逻辑:

server <- function(input, output) {
  filter1_rows <- reactive({
    iris[Species %in% input$filter1,   which = TRUE]
  })
  filter2_rows <- reactive({
    iris[Sepal.Length < input$filter2, which = TRUE]
  })
  filter3_rows <- reactive({
    iris[Sepal.Width > input$filter3,  which = TRUE]
  })
  output$mydata <- renderDataTable({
    final_rows <- intersect(filter1_rows(), filter2_rows())
    final_rows <- intersect(final_rows,     filter3_rows())
    iris[final_rows]
  })
}

这使用which经常被忽略的data.table[...]参数,这意味着只应返回子集化表的行号。

答案 1 :(得分:2)

我认为你的问题与闪亮和/或反应式编程无关。它是一个经典的时间与记忆的关系#34;情况。基本上,你只有两个选择:Store&#34; partial&#34;是否过滤了对象。

如果存储它们,则会占用大量内存但可以立即返回对象。如果没有,您只需要存储原始对象,但每次都必须对其进行过滤。两者之间没有任何东西。您无法创建与原始对象不同的对象(即已过滤)但不会占用额外的内存,即使使用reactiveValues也不会。

当然,您可以进行权衡,例如:为第一个过滤器创建一个中间对象,并在运行中计算第二个和第三个过滤器,但这不会改变潜在的问题。