我们创建了一个闪亮的应用程序,用户可以上传大数据集(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
答案 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
也不会。
当然,您可以进行权衡,例如:为第一个过滤器创建一个中间对象,并在运行中计算第二个和第三个过滤器,但这不会改变潜在的问题。