【问题标题】:How to edit an uploaded data in rshiny如何在 r shiny 中编辑上传的数据
【发布时间】:2017-12-07 21:52:21
【问题描述】:

这是要求。

1)我需要浏览并上传一个 excel 文件(带有包 readxl),该文件用于得出一些我需要在闪亮窗口中显示为不同表格输出的计算

2) 手动编辑上传文件中的一些数据,它应该会自动反映在显示的结果中

3) 我们应该可以下载编辑后的文件了。

到目前为止我已经写了。我在输入数据中有列 ID、曝光和频率。对于每个 ID,我需要使用将显示的相应曝光和频率来计算一个变量。我需要使用 ID 手动编辑频率和曝光(这是唯一的)。我添加了一个“更新”按钮。但改变不是永久的。一旦我再次单击更新按钮,它就会返回

library(shiny)
ui = fluidPage( 

     titlePanel("HEllo world"),
     sidebarLayout(
          sidebarPanel(

               fileInput('file1', 'Choose xlsx file',
                         accept = c(".xlsx")),
               actionButton("go", "update"),
               numericInput('NewVal', 'Enter new Frequency',NULL),
               numericInput('NewExp', 'Enter new Exposure',NULL)),


          mainPanel(
               textInput('ID', 'Enter ID'),
               dataTableOutput('contents')

          )))

server = function(input,output){
     ef <- eventReactive(input$go, {
          infile <- input$file1 
          if(is.null(infile))
               return(NULL)
          file.rename(infile$datapath,paste(infile$datapath, ".xlsx", sep=""))
          data<-read_excel(paste(infile$datapath, ".xlsx", sep=""), 1)

          if(input$ID!="" && input$go>0){
               for( i in 1:nrow(data)){

                    if( input$ID == data$'ID'[i]){

                         if(!is.na(input$NewVal)){
                              data$' Frequency'[i] <- input$NewVal
                         }

                         if(!is.na(input$NewExp)){
                              data$'Exposure'[i] <- input$NewExp
                         }
                    }}}

          data
     }, ignoreNULL =  FALSE)  


     output$contents <- renderDataTable({ef()})}
shinyApp(ui,server)

更新!:根据一个答案,我对我的代码进行了一些更改。新代码似乎运行良好。这是工作代码,供任何可能在同一问题上需要帮助的人使用。

ui = fluidPage( 

 titlePanel("HEllo world"),
  sidebarLayout(
  sidebarPanel(

  fileInput('file1', 'Choose xlsx file',
            accept = c(".xlsx")),
  actionButton("go", "update"),
  numericInput('NewVal', 'Enter new Frequency',NULL),
  numericInput('NewExp', 'Enter new Exposure',NULL)),


mainPanel(
  textInput('ID', 'Enter ID'),
  tableOutput('contents')

)))

  server = function(input,output){
  # Reactive value to save input data frame for use elsewhere
   original <- reactiveValues()

  observeEvent(input$file1, {
  theFile <- input$file1
   if(is.null(theFile)) {
    return(NULL)}
    **file.rename(theFile$datapath,paste(theFile$datapath, ".xlsx", sep=""))**
     original$oldData <- read_excel(paste(theFile$datapath, ".xlsx", sep = ""), 1)    
    })

   observeEvent(input$go, {

   original$newData <- original$oldData
   if(input$ID !="") {
    for( i in 1:nrow(original$oldData)){

     if( input$ID == original$oldData$'ID'[i]){

      if(!is.na(input$NewVal)){
        original$newData$'Frequency'[i] <- input$NewVal
      }

      if(!is.na(input$NewExp)){
        original$newData$'Exposure'[i] <- input$NewExp
      }
     }
    }
    **original$oldData<-original$newData**  }
  })

output$contents <- renderTable({
  if(!is.null(original$newData)) {
  original$newData}
else {
  original$oldData}
  })
  }
  shinyApp(ui = ui, server = server)

【问题讨论】:

  • 对象dat 在您的代码中来自哪里? “数据”有什么区别?
  • 我猜这个问题是因为在一个函数中你正在读取文件并更新它。制作 2 个功能,首先您读取文件并存储它。将该函数传递给您的第二个函数,您将在其中进行更新,然后显示输出。
  • @agenis 抱歉,它的数据不是 dat。一样的。数据包含“ID”、“曝光”和“频率”
  • 好几句话:首先你不需要一个操作按钮,而是一个内置的submitButton,这正是这个目的。然后我想你可以摆脱你的 for 循环,如果它只是在那里找到要更改的行......你应该使用使用 reactiveValues 的结构。有一些类似这样的问题已回答:stackoverflow.com/a/30502250/3871924
  • 抱歉,如果我在错误的树上吠叫,但您是否考虑过使用rhandsontable?它提供excel-like GUI,并且(如果设置)允许单元级编辑。它可能不会使代码变得更简单(当然,您需要知道如何处理更改的单元格),但至少为用户提供了更好的体验。

标签: r shiny


【解决方案1】:

一些 cmets 似乎对这里发生的事情走在了正确的轨道上。有几种解决方案可以使用,但我只会分享对我来说最直观的东西。另外,我只会更改服务器功能。

server = function(input,output){
 # Reactive value to save input data frame for use elsewhere
 original <- reactiveValues()

 observeEvent(input$file1, {
   theFile <- input$file1
   if(is.null(theFile)) {return(NULL)}
   original$oldData <- read_excel(paste(theFile$datapath, ".xlsx", sep = ""), 1)    
 })

 observeEvent(input$goButton2, {
   original$newData <- original$oldData
   if(input$ID !="") {
          for( i in 1:nrow(data)){
                if( input$ID == dat$'ID'[i]){

                     if(!is.na(input$NewVal)){
                          original$newData$' Frequency'[i] <- input$NewVal
                     }

                     if(!is.na(input$NewExp)){
                          original$newData$'Exposure'[i] <- input$NewExp
                     }
                }
          }
   }
 })

 output$contents <- renderDataTable({
   if(!is.null(original$newData)) {original$newData}
   else {original$oldData}
 })
}

在单击 go 按钮之前,这不会更改表格输出。我没有完全测试它,因为我没有你的数据,但我相信这至少应该让你走上正确的轨道......我喜欢观察陈述,因为它们会产生副作用并且看起来更开放比 eventReactives 或函数。

这仅有助于解决进行正确更改并继续在输出中显示的初始问题。如果这可行,那么添加下载功能应该相当容易,该功能会在文件更新时保存文件。

更新 1

下面的代码应该做你想做的事。我添加了两种不同的功能来保存新的数据框。只要按下更新按钮,注释掉的代码就会自动保存数据。周围没有 cmets 的代码创建了一个用于下载数据的下载按钮。我还添加了一条根据频率和曝光计算新值的行。在数据集中将此列命名为 Value。希望这可以帮助!

#### Example app for Exchange answer
library(shiny)
library(readxl)

ui = fluidPage( 

  titlePanel("HEllo world"),
  sidebarLayout(
    sidebarPanel(

      fileInput('file1', 'Choose xlsx file',
                accept = c(".xlsx")),
      actionButton("go", "update"),
      numericInput('NewVal', 'Enter new Frequency',NULL),
      numericInput('NewExp', 'Enter new Exposure',NULL),

      # Download button (goes with download handler below)
      # Use if desire is to save at press of button
      downloadButton("save", "Download")
    ),

    mainPanel(
      textInput('ID', 'Enter ID'),
      dataTableOutput('contents')
    )
  )
)

server = function(input,output){
  # Reactive value to save input data frame for use elsewhere
  original <- reactiveValues()

  observeEvent(input$file1, {
    theFile <- input$file1
    if(is.null(theFile)) {
      original$oldData <- NULL
    } else {
      original$oldData <- read_excel(theFile$datapath, 1)      
    }
  })

  observeEvent(input$go, {

    original$newData <- original$oldData
    if(input$ID !="") {
      for(i in 1:nrow(original$oldData)){

        if(input$ID == original$oldData$'ID'[i]){

          if(!is.na(input$NewVal)){
            original$newData$'Frequency'[i] <- input$NewVal
          }

          if(!is.na(input$NewExp)){
            original$newData$'Exposure'[i] <- input$NewExp
          }
          ### Make sure a column in your data set is named Value for this
          # Calculate a new column
          original$newData$'Value'[i] <- (original$newData$'Exposure'[i]*
                                            original$newData$'Frequency'[i])
        }
      }

      original$oldData<-original$newData  
    }

    ### Use this to automatically save table when update is clicked
    # write.csv(original$newData, 
    #           file = #Desired Pathname, 
    #           row.names = FALSE)
  })

  output$contents <- renderDataTable({
     if(!is.null(original$newData)) {
      original$newData}
    else {
      original$oldData
    }
  })

  ### Use this code below if desired saving is through download button
  # Server code for download button
  output$save <- downloadHandler(
    filename = function() {
      paste0("newData - ", Sys.Date(), ".csv")
    },

    content = function(con) {
      if (!is.null(original$newData)) {
        dataSave <- original$newData
      } else {
        dataSave <- original$oldData
      }
      con <- ## Desired save location... could just use `getwd()` to
        # save to working directory
      write.csv(dataSave, con)
    }
  )

}


shinyApp(ui = ui, server = server)

【讨论】:

  • 非常感谢。如果需要,您可以使用随机数据框。我只想要逻辑。
  • 如果您可以使用自己的数据文件进行尝试,将会很有帮助。
  • 我收到错误兄弟。闪亮的窗口正在弹出,但是一旦我加载数据,它就会崩溃。我已经改变了问题。查看问题的第二部分
  • 好的,我明白了。我做了一些更改,现在它可以工作了。请在问题下方找到新代码。非常感谢。
  • 此外,如果您能深入了解 1) 如何使更改反映在计算列中,这将很有帮助。假设我们将列“曝光”和“频率”相乘。假设计算的列显示在单独的选项卡(tab2。2)如何下载更改的数据(在tab1)
猜你喜欢
  • 2019-05-15
  • 1970-01-01
  • 1970-01-01
  • 2015-02-22
  • 1970-01-01
  • 1970-01-01
  • 2019-01-23
  • 2021-02-17
  • 2023-03-14
相关资源
最近更新 更多