【问题标题】:How to edit a table using DT and Shiny from an uploaded file?如何使用上传文件中的 DT 和 Shiny 编辑表格?
【发布时间】:2023-03-26 03:14:01
【问题描述】:

我依靠找到here 的代码块来创建一个闪亮的应用程序来上传表格,编辑表格,然后下载表格。我已经设法编辑了一个已经加载到内存(iris)中的表格,但是如何编辑要在 Shiny 中上传的表格?

我已经尝试了上面链接中的代码并验证它可以工作。我也尝试了下面的代码,这也有效。我无法实现的是将数据框x 转换为分配给上传文件的反应对象,并相应地编辑对x 的所有引用。

# This code works, but lacks a fileinput object 
# and needs to be amended for a reactive dataframe...
library(shiny)
library(DT)
shinyApp(
  ui = fluidPage(
    fluidRow(
    # ~~ add fileInput("file1", "Choose file") here ~~
    downloadButton("download")
    ),
    fluidRow(
    DT::dataTableOutput('x1')
    )
  ),
  server = function(input, output, session) {
    # Do I make x reactive?
    x = iris
    x$Date = Sys.time() + seq_len(nrow(x))
    output$x1 = DT::renderDataTable(x, selection = 'none', rownames = FALSE, edit = TRUE)

    proxy = dataTableProxy('x1')

    observeEvent(input$x1_cell_edit, {
      info = input$x1_cell_edit
      str(info)
      i = info$row
      j = info$col + 1
      v = info$value
      x[i, j] <<- DT:::coerceValue(v, x[i, j])
      replaceData(proxy, x, resetPaging = FALSE, rownames = FALSE)
    })

    output$download <- downloadHandler("example.csv", 
                                       content = function(file){
                                         write.csv(x, file)
                                       },
                                       contentType = "text/csv")

    }
)

之前的尝试都抛出了错误,主要是因为没有活动的反应上下文就不允许操作。

下面的代码显示了我想要实现的目标,但会引发错误: “缺少参数“expr”,没有默认值”

library(shiny)
library(DT)
shinyApp(
  ui = fluidPage(
    fluidRow(
      fileInput("upload", "Choose CSV File",
                multiple = FALSE,
                accept = c("text/csv",
                           "text/comma-separated-values,text/plain",
                           ".csv")),
    downloadButton("download")
    ),
    fluidRow(
    DT::dataTableOutput('x1')
    )
  ),
  server = function(input, output, session) {
    #x = iris

    # In this edited example x is now a reactive expression, dependent on input$upload
    x <- eventReactive({


      # input$file1 will be NULL initially. After the user selects
      # and uploads a file, head of that data file by default,
      # or all rows if selected, will be shown.

     req(input$upload)

      # when reading semicolon separated files,
      # having a comma separator causes `read.csv` to error
      tryCatch(
        {
          x <- read.csv(input$upload$datapath,
                         header = TRUE,
                         sep = ",",
                         stringsAsFactors = TRUE,
                         row.names = NULL)

        },
        error = function(e) {
          # return a safeError if a parsing error occurs
          stop(safeError(e))
         }
      )
    })

    #x$Date = Sys.time() + seq_len(nrow(x))
    output$x1 = DT::renderDataTable(x(), selection = 'none', rownames = FALSE, edit = TRUE)

    proxy = dataTableProxy('x1')

    observeEvent(input$x1_cell_edit, {
      info = input$x1_cell_edit
      str(info)
      i = info$row
      j = info$col + 1
      v = info$value
      x()[[i, j]] <<- DT:::coerceValue(v, x()[[i, j]])
      newdf <- x()
      replaceData(proxy, newdf, resetPaging = FALSE, rownames = FALSE)
    })

    output$download <- downloadHandler("example.csv", 
                                       content = function(file){
                                         write.csv(x(), file)
                                       },
                                       contentType = "text/csv")

    }
)

【问题讨论】:

  • 我也尝试了here 的建议,但这引发了更多问题。然而,作者正试图做我想做的事。
  • 您能否附上您使用fileInput的尝试?
  • 当然。添加了新代码。

标签: r shiny dt


【解决方案1】:

感谢 Stephane,以及来自 this related question 的灵感,我想我有了答案。

关键是使用 reactiveValues 作为 DT:::coerceValue 不喜欢反应式表达式的解决方法。我已经包含了一个逐字文本输出来说明在编辑数据表后对表的存储更改。下载按钮也允许您下载已编辑的表格。

library(shiny)
library(DT)
shinyApp(
  ui = fluidPage(
    fluidRow(
      fileInput("upload", "Choose CSV File",
                multiple = FALSE,
                accept = c("text/csv",
                           "text/comma-separated-values,text/plain",
                           ".csv")),
    downloadButton("download")
    ),
    fluidRow(
    DT::dataTableOutput('x1'),
    verbatimTextOutput("print")
    )
  ),
  server = function(input, output, session) {

    # In this edited example x is now a reactive expression, dependent on input$upload

    # Key to the solution is the use of reactiveValues, stored as vals
    vals <- reactiveValues(x = NULL)

    observe({


      # input$upload will be NULL initially. After the user selects
      # and uploads a file, head of that data file by default,
      # or all rows if selected, will be shown.

     req(input$upload)

      # when reading semicolon separated files,
      # having a comma separator causes `read.csv` to error
      tryCatch(
        {
          x <- read.csv(input$upload$datapath,
                         header = TRUE,
                         sep = ",",
                         stringsAsFactors = TRUE,
                         row.names = NULL)

        },
        error = function(e) {
          # return a safeError if a parsing error occurs
          stop(safeError(e))
         }
      )
      # Reactive values updated from x
      vals$x <- x
    })

    output$print <- renderPrint({
      vals$x
    })
    output$x1 = DT::renderDataTable(vals$x, selection = 'none', rownames = FALSE, edit = TRUE)

    proxy = dataTableProxy('x1')

    observeEvent(input$x1_cell_edit, {
      info = input$x1_cell_edit
      str(info)
      i = info$row
      j = info$col + 1
      v = info$value
      # Below is the crucial spot where the reactive value is used where a reactive expression cannot be used
      vals$x[i, j] <<- DT:::coerceValue(v, vals$x[i, j])
      replaceData(proxy, vals$x, resetPaging = FALSE, rownames = FALSE)
    })

    output$download <- downloadHandler("example.csv", 
                                       content = function(file){
                                         write.csv(vals$x, file, row.names = F)
                                       },
                                       contentType = "text/csv")

    }
)

【讨论】:

    【解决方案2】:

    ?eventReactive

    你应该这样做:

    x <- eventReactive(input$upload, { # 'input$upload' was the "expr missing"
           ......
    

    x <- reactive({
            req(input$upload)
            ......
    

    【讨论】:

    • 糟糕!那是一个愚蠢的错误。替换为您的第一个建议,我现在有以下错误:“警告:。我不认为它喜欢符合 coerceValue 的反应式表达。
    • @RDavey 那是因为你的反应导体x 什么都没有返回,我想。在关闭它之前添加x(或return(x))。此外,我认为您无法通过 x()[[i, j]] &lt;- ... 更改反应值。
    猜你喜欢
    • 2021-10-23
    • 2018-11-01
    • 2021-03-07
    • 2019-09-05
    • 2021-08-21
    • 1970-01-01
    • 2020-03-07
    • 2015-08-20
    • 1970-01-01
    相关资源
    最近更新 更多