使用预加载数据组织反应性
organize reactivity with pre-loaded data
我有几个 table 分别存储在一个单独的 txt 文件中,并且还组合在一个 Rdat 文件中,如下所示:
# generate tables
df.A <- data.frame(colA1=letters[1:20],colA2=LETTERS[1:20], stringsAsFactors = F)
df.B <- data.frame(colB1=rnorm(20),colB2=rnorm(20), stringsAsFactors = F)
# save tables as separate files
write.csv(df.A, 'tableA.txt')
write.csv(df.B, 'tableB.txt')
# I may have more tables
# save all tables in a single Rdat file
save(df.A,df.B, file = 'alldata.RDat')
现在在我闪亮的降价文档中,我想从 RDat
文件中预加载那些 tables,但也让用户有可能重新加载它们 a) 与个人分开文件,或 b) 完全来自 RDat 文件。这是我来到的第一个版本:
---
runtime: shiny
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
```{r}
load('alldata.RDat')
```
Tables below:
```{r}
inputPanel(
actionButton('load.A','Reload Table A'),
actionButton('load.B','Reload Table B'),
actionButton('load.Rdat','Load all from Rdat file')
)
tabsetPanel(type = "tabs",
tabPanel("table A", dataTableOutput("toA")),
tabPanel("table B", dataTableOutput("toB"))
)
# next 2 lines render pre-loaded tables before any buttons are pressed:
output$toA <- renderDataTable(df.A, options=list(pageLength=5))
output$toB <- renderDataTable(df.B, options=list(pageLength=5))
observeEvent(input$load.A, {
df.A <- read.csv('tableA.txt');
output$toA <- renderDataTable(df.A, options=list(pageLength=5))
})
observeEvent(input$load.B, {
df.B <- read.csv('tableB.txt');
output$toB <- renderDataTable(df.B, options=list(pageLength=5))
})
observeEvent(input$load.Rdat, {
load('alldata.RDat', verbose = T);
output$toA <- renderDataTable(df.A, options=list(pageLength=5));
output$toB <- renderDataTable(df.B, options=list(pageLength=5))
})
```
它工作正常,但我感觉这不是使用反应性的正确方法。例如,每次更新我的 table 对象(df.A
或 dfB
)后,我都必须显式调用 render output$toA <- renderDataTable(...)
(每个 table 调用 3 次! ).
我想到的一个解决方案是将我的 table 放入 reactiveValues()
,结果如下:
---
runtime: shiny
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
```{r}
load('alldata.RDat')
```
Tables below:
```{r}
inputPanel(
actionButton('load.A','Reload Table A'),
actionButton('load.B','Reload Table B'),
actionButton('load.Rdat','Load all from Rdat file')
)
tabsetPanel(type = "tabs",
tabPanel("table A", dataTableOutput("toA")),
tabPanel("table B", dataTableOutput("toB"))
)
rv <- reactiveValues(df.A = df.A, df.B = df.B)
output$toA <- renderDataTable(rv$df.A, options=list(pageLength=5))
output$toB <- renderDataTable(rv$df.B, options=list(pageLength=5))
observeEvent(input$load.A, {
rv$df.A <- read.csv('tableA.txt');
})
observeEvent(input$load.B, {
rv$df.B <- read.csv('tableB.txt');
})
observeEvent(input$load.Rdat, {
load('alldata.RDat', verbose = T);
rv$df.A <- df.A;
rv$df.B <- df.B;
})
```
这看起来更好,因为我的代码中每个 renderDataTable()
只有一个调用。但是现在我的每个 table 都在内存中存储了两次 - 一个在 df.A
中(从 'alldata.RDat' 加载),另一个在 rv$df.A
中...是否有意义完全没有,或者有更符合犹太洁食标准的方法来解决这类问题?
您想从 csv 或 Rdat
文件加载 df.A
和 df.B
的数据。这几乎肯定需要一个中间变量,rv
正如您正确创建的那样。
您创建的第二个示例比第一个好得多,我们必须避免对同一个 output
进行多次渲染调用,尤其是在观察者内部进行渲染调用。
下面的代码从观察者内部执行 load('alldata.RDat', verbose = T)
并且 rv
的初始值是从观察者内部设置的,而不是使用全局 load('alldata.RDat', verbose = T)
。这样可以防止数据被加载两次。
---
runtime: shiny
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
```{r}
#load('alldata.RDat')
```
Tables below:
```{r}
inputPanel(
actionButton('load.A','Reload Table A'),
actionButton('load.B','Reload Table B'),
actionButton('load.Rdat','Load all from Rdat file')
)
tabsetPanel(type = "tabs",
tabPanel("table A", dataTableOutput("toA")),
tabPanel("table B", dataTableOutput("toB"))
)
rv <- reactiveValues(df.A = NULL, df.B = NULL)
output$toA <- renderDataTable({
req(rv$df.A)
rv$df.A
}, options=list(pageLength=5))
output$toB <- renderDataTable({
req(rv$df.B)
rv$df.B
}, options=list(pageLength=5))
observeEvent(input$load.A, {
rv$df.A <- read.csv('tableA.txt');
})
observeEvent(input$load.B, {
rv$df.B <- read.csv('tableB.txt');
})
observeEvent(c(input$load.Rdat), {
load('alldata.RDat', verbose = T);
rv$df.A <- df.A;
rv$df.B <- df.B;
})
```
我有几个 table 分别存储在一个单独的 txt 文件中,并且还组合在一个 Rdat 文件中,如下所示:
# generate tables
df.A <- data.frame(colA1=letters[1:20],colA2=LETTERS[1:20], stringsAsFactors = F)
df.B <- data.frame(colB1=rnorm(20),colB2=rnorm(20), stringsAsFactors = F)
# save tables as separate files
write.csv(df.A, 'tableA.txt')
write.csv(df.B, 'tableB.txt')
# I may have more tables
# save all tables in a single Rdat file
save(df.A,df.B, file = 'alldata.RDat')
现在在我闪亮的降价文档中,我想从 RDat
文件中预加载那些 tables,但也让用户有可能重新加载它们 a) 与个人分开文件,或 b) 完全来自 RDat 文件。这是我来到的第一个版本:
---
runtime: shiny
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
```{r}
load('alldata.RDat')
```
Tables below:
```{r}
inputPanel(
actionButton('load.A','Reload Table A'),
actionButton('load.B','Reload Table B'),
actionButton('load.Rdat','Load all from Rdat file')
)
tabsetPanel(type = "tabs",
tabPanel("table A", dataTableOutput("toA")),
tabPanel("table B", dataTableOutput("toB"))
)
# next 2 lines render pre-loaded tables before any buttons are pressed:
output$toA <- renderDataTable(df.A, options=list(pageLength=5))
output$toB <- renderDataTable(df.B, options=list(pageLength=5))
observeEvent(input$load.A, {
df.A <- read.csv('tableA.txt');
output$toA <- renderDataTable(df.A, options=list(pageLength=5))
})
observeEvent(input$load.B, {
df.B <- read.csv('tableB.txt');
output$toB <- renderDataTable(df.B, options=list(pageLength=5))
})
observeEvent(input$load.Rdat, {
load('alldata.RDat', verbose = T);
output$toA <- renderDataTable(df.A, options=list(pageLength=5));
output$toB <- renderDataTable(df.B, options=list(pageLength=5))
})
```
它工作正常,但我感觉这不是使用反应性的正确方法。例如,每次更新我的 table 对象(df.A
或 dfB
)后,我都必须显式调用 render output$toA <- renderDataTable(...)
(每个 table 调用 3 次! ).
我想到的一个解决方案是将我的 table 放入 reactiveValues()
,结果如下:
---
runtime: shiny
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
```{r}
load('alldata.RDat')
```
Tables below:
```{r}
inputPanel(
actionButton('load.A','Reload Table A'),
actionButton('load.B','Reload Table B'),
actionButton('load.Rdat','Load all from Rdat file')
)
tabsetPanel(type = "tabs",
tabPanel("table A", dataTableOutput("toA")),
tabPanel("table B", dataTableOutput("toB"))
)
rv <- reactiveValues(df.A = df.A, df.B = df.B)
output$toA <- renderDataTable(rv$df.A, options=list(pageLength=5))
output$toB <- renderDataTable(rv$df.B, options=list(pageLength=5))
observeEvent(input$load.A, {
rv$df.A <- read.csv('tableA.txt');
})
observeEvent(input$load.B, {
rv$df.B <- read.csv('tableB.txt');
})
observeEvent(input$load.Rdat, {
load('alldata.RDat', verbose = T);
rv$df.A <- df.A;
rv$df.B <- df.B;
})
```
这看起来更好,因为我的代码中每个 renderDataTable()
只有一个调用。但是现在我的每个 table 都在内存中存储了两次 - 一个在 df.A
中(从 'alldata.RDat' 加载),另一个在 rv$df.A
中...是否有意义完全没有,或者有更符合犹太洁食标准的方法来解决这类问题?
您想从 csv 或 Rdat
文件加载 df.A
和 df.B
的数据。这几乎肯定需要一个中间变量,rv
正如您正确创建的那样。
您创建的第二个示例比第一个好得多,我们必须避免对同一个 output
进行多次渲染调用,尤其是在观察者内部进行渲染调用。
下面的代码从观察者内部执行 load('alldata.RDat', verbose = T)
并且 rv
的初始值是从观察者内部设置的,而不是使用全局 load('alldata.RDat', verbose = T)
。这样可以防止数据被加载两次。
---
runtime: shiny
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
```{r}
#load('alldata.RDat')
```
Tables below:
```{r}
inputPanel(
actionButton('load.A','Reload Table A'),
actionButton('load.B','Reload Table B'),
actionButton('load.Rdat','Load all from Rdat file')
)
tabsetPanel(type = "tabs",
tabPanel("table A", dataTableOutput("toA")),
tabPanel("table B", dataTableOutput("toB"))
)
rv <- reactiveValues(df.A = NULL, df.B = NULL)
output$toA <- renderDataTable({
req(rv$df.A)
rv$df.A
}, options=list(pageLength=5))
output$toB <- renderDataTable({
req(rv$df.B)
rv$df.B
}, options=list(pageLength=5))
observeEvent(input$load.A, {
rv$df.A <- read.csv('tableA.txt');
})
observeEvent(input$load.B, {
rv$df.B <- read.csv('tableB.txt');
})
observeEvent(c(input$load.Rdat), {
load('alldata.RDat', verbose = T);
rv$df.A <- df.A;
rv$df.B <- df.B;
})
```