使用 Shiny 应用程序保存数据时出现问题

Problem when using Shiny app to save the data

我有一个闪亮的应用程序,它有很多文本输入。我无法正确保存数据部分,例如,无法保存到本地驱动器。有什么建议么?

     server = function(input, output) {
      values <- reactiveValues()
      #Initial Dataframe 
      values$df <- data.frame(matrix(ncol=4,nrow=0, dimnames=list(NULL, c("Name", "date","Traning",  "certificate"))))

      FinalData =observe({
        if(input$submit >0) {
        isolate(values$df <- rbind(values$df,data.frame("name" = input$name,"date" = input$date, 
                           "training" = input$training, "certificate" = input$certificate)))
    # saveRDS(values$df)
    # saveRDS(FinalData)
                   }})

    #display the inputs
     output$Combined_table = renderDataTable({values$df})
}
)

试试这个演示:

library(shiny)
.log <- function(...) message(format(Sys.time(), format = "[ %H:%M:%S ]"), " ", ...)
.read <- function(path) if (file.exists(path)) return(readRDS(path))
shinyApp(
  ui = fluidPage(
    textInput("txt", "Text: "),
    actionButton("btn", "Submit"),
    tableOutput("tbl")
  ),
  server = function(input, output, session) {
    .log("hello world")
    rv <- reactiveValues()
    rv$df <- data.frame(row = 0L, word = "a", stringsAsFactors = FALSE)[0,]
    observeEvent(req(input$btn), {
      .log("submit!")
      rv$df <- rbind(rv$df,
                     data.frame(row = input$btn, word = input$txt,
                                stringsAsFactors = FALSE))
      .log("saveRDS: ", nrow(rv$df))
      saveRDS(rv$df, "local.rds")
    })
    filedata <- reactiveFileReader(1000, session, "local.rds", .read)
    output$tbl <- renderTable(filedata())
  }
)

此应用程序的工程:

  • 我像你一样使用 reactiveValues 来保存内存中的数据。 (注意:在 long-运行 中迭代地向帧添加行是不好的。如果这是小批量添加,那么你可能没问题,但它的扩展性很差。每次添加一行时,它都会复制整个帧,内存消耗加倍。)
  • 我用零行框预填充了$df,只是为了格式化。这里没什么特别的。
  • observeobserveEvent不要return你感兴趣的东西,应该完全由side-effect操作。它做了 return 一些事情,但实际上只对 shiny 内部有意义。
  • saveRDS 和你一样,没什么特别的,但它确实有效。
  • 我添加了一个 shiny::reactiveFileReader 以证明该文件正在保存。当闪亮的 table 显示更新时,这是因为 (1) 数据已添加到底层框架; (2) 帧保存到"local.rds"文件;然后 (3) reactiveFileReader 注意到基础文件存在并且已经改变,导致 (4) 它调用我的 .read 函数来读取内容,并且 return 它作为反应数据进入 filedata。这个block在一般情况下是完全不需要的,这里只是为了演示。
  • 我为此 reactiveFileReader 创建了一个函数 .read,它可以适应首先不存在的文件。如果该文件不存在,它会无形地 returns NULL。可能有更好的方法来做到这一点。