使用预先加载的数据来组织反应性

时间:2019-09-08 21:09:24

标签: r shiny reactive shiny-reactivity

我有几个表,每个表都存储在一个单独的txt文件中,并且还合并在一个Rdad文件中,如下所示:

# 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文件中预加载那些表,但也使用户可以重新加载它们: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))
 })

```

它工作正常,但我感觉这不是使用反应性的正确方法。例如,每次更新表对象(df.AdfB)后,我都必须显式调用render output$toA <- renderDataTable(...)(每个表3次!)。

我想到的一个解决方案是将表格放入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()仅调用一次。但是现在我的每个表都两次存储在内存中-一个在df.A中(从'alldata.RDat'加载),另一个在rv$df.A中...是否完全有意义,或者有解决这些问题的更简洁的方式?

1 个答案:

答案 0 :(得分:0)

您想从csv或df.A文件中加载df.BRdat的数据。几乎可以肯定,您需要正确创建一个中间变量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;
 })
```