使用增量计算在闪亮的应用程序中编辑数据表

Posted

技术标签:

【中文标题】使用增量计算在闪亮的应用程序中编辑数据表【英文标题】:Editing data table in shiny app with incremental calculation 【发布时间】:2022-01-19 16:56:19 【问题描述】:

我目前正在开发一个闪亮的应用程序,我希望用户进入其中并对显示的表格上的特定列进行一些更改,然后触发要完成的计算并更新显示的表格。例如,取如下数据框:

input_data <- data.frame(ITEM_NO = c("1000001", "1000001","1000001", "20001", '20001', '20001'),
                     AVAILABLE_QTY = c(1000, 1000, 1000, 500,500,500),
                     DEMAND = c(0, 0, 0, 0, 0, 0),
                     FORECAST = c(0,0,0, 0 ,0, 0),
                     stringsAsFactors = FALSE)

我希望能够以触发简单增量计算的方式更改预测列,以从可用数量中减去输入的预测。诀窍是我希望能够让应用程序对每个单独的项目进行单独的计算。我编写了一些适用于单个项目的代码,所以如果我只为 1000001 做它,它会起作用,或者如果我只为 20001 做它,它会起作用,但是当我尝试同时对两者进行编辑时它因以下错误而崩溃:“警告:[.data.table:j 中的错误([...] 中的第二个参数)是单个符号,但未找到列名 'j'。也许您打算使用 DT[, . .j]. 这种与 data.frame 的差异是经过深思熟虑的,并在 FAQ 1.1 中进行了解释。 "。谁能帮我调整这段代码,让它在那种情况下工作?

这是完整的代码:

library(shiny)
library(dplyr)
library(DT)
input_data <- data.frame(ITEM_NO = c("1000001", "1000001","1000001", "20001", '20001', '20001'),
                         AVAILABLE_QTY = c(1000, 1000, 1000, 500,500,500),
                         DEMAND = c(0, 0, 0, 0, 0, 0),
                         FORECAST = c(0,0,0, 0 ,0, 0),
                         stringsAsFactors = FALSE)
#=================================================================
modFunction <- function(input, output, session, data,reset) 
  
  v <- reactiveValues(data = data)
  
  proxy = dataTableProxy("mod_table")
  
  #need to change this function so that the data gets group split
  observeEvent(input$mod_table_cell_edit, 
    print(names(v$data))
    info = input$mod_table_cell_edit
    str(info)
    i = info$row
    j = info$col
    k = info$value
    str(info)
    print(i)
    print(j)
    print(k)
    isolate(
      #try putting the list stuff out here instead and see if it gets rid of the e
      if (j %in% match(c("FORECAST"), names(v$data))) 
        print(match(c("FORECAST"), names(v$data)))
        v$data[i, j] <<- DT::coerceValue(k, v$data[i, j])
        print(v$data)
        
        if(j %in% match('FORECAST', names(v$data)))
          #convert to a list
          test_stuff<- v$data
          start_list<- test_stuff %>% group_split(ITEM_NO)
          end_list<- list()
          for(t in 1:length(start_list))
            start<- start_list[[t]]
            for(n in 2:nrow(start))
              start$AVAILABLE_QTY[n] <- start$AVAILABLE_QTY[n-1]-start$DEMAND[n]-start$FORECAST[n]
            
            end_list[[t]]<- start
            
          
          final<-  data.table::rbindlist(end_list)
          v$data<<- final
            
        
       else 
        stop("You cannot change this column.") # check to stop the user from editing only few columns
      
    )
    replaceData(proxy, v$data, resetPaging = FALSE)  # replaces data displayed by the updated table
  )
  ### Reset Table
  observeEvent(reset(), 
    v$data <- data # your default data
  )
  
  print(isolate(colnames(v$data)))
  output$mod_table <- DT::renderDataTable(
    DT::datatable(v$data, editable = TRUE)
    
  )


modFunctionUI <- function(id) 
  ns <- NS(id)
  DT::dataTableOutput(ns("mod_table"))
  

#===================================================
shinyApp(
  ui = basicPage(
    mainPanel(
      actionButton("reset", "Reset"),
      tags$hr(),
      modFunctionUI("editable")
    )
  ),
  server = function(input, output) 
    demodata<-input_data
    callModule(modFunction,"editable", demodata,
               reset = reactive(input$reset))
  
)

【问题讨论】:

【参考方案1】:

您的问题是因为 final 是一个 data.table 并且您将其分配给 v$data。只要v$data 是一个数据框,它就可以正常工作。试试这个

library(shiny)
library(dplyr)
library(DT)

input_data <- data.frame(ITEM_NO = c("1000001", "1000001","1000001", "20001", '20001', '20001'),
                         AVAILABLE_QTY = c(1000, 1000, 1000, 500,500,500),
                         DEMAND = c(0, 0, 0, 0, 0, 0),
                         FORECAST = c(0,0,0, 0 ,0, 0),
                         stringsAsFactors = FALSE)
#=================================================================
#modFunction <- function(input, output, session, data,reset,globalSession) 
modFunction <- function(id, data, reset) 
  moduleServer(id, function(input, output, session) 
  v <- reactiveValues(data = NULL)
  observe(v$data <- data())
  
  output$mod_table <- renderDT(
    DT::datatable(v$data, editable = TRUE, rownames = FALSE)
  )
  
  proxy = dataTableProxy("mod_table" ) #, session = globalSession)
  
  #need to change this function so that the data gets group split
  observeEvent(input$mod_table_cell_edit, 
    
    print(names(v$data))
    info = input$mod_table_cell_edit
    str(info)
    i = info$row
    j = info$col + 1
    k = info$value
    # str(info)
    print(i)
    print(j)
    print(k)
    myvar <- match(c("FORECAST"), names(v$data))
    isolate(
      #try putting the list stuff out here instead and see if it gets rid of the e
      if (j == myvar) 
        print(myvar)
        v$data[i, j] <<- DT::coerceValue(k, v$data[i, j])
        print(v$data)
        
        #if(j %in% match('FORECAST', names(v$data)))
          #convert to a list
          test_stuff<- v$data
          start_list<- test_stuff %>% group_split(ITEM_NO)
          end_list<- list()
          lapply(1:length(start_list), function(t)
          #for(t in 1:length(start_list))
            start<- start_list[[t]]
            for(n in 2:nrow(start))
                start$AVAILABLE_QTY[n] <- start$AVAILABLE_QTY[n-1]-start$DEMAND[n]-start$FORECAST[n]
            
            end_list[[t]]<<- start
            
          #
          )
          final <-  data.table::rbindlist(end_list)
          v$data<<- as.data.frame(final)
          
          #
          
       else 
        stop("You cannot change this column.") # check to stop the user from editing only few columns
      
    )
    
    replaceData(proxy, v$data, resetPaging = FALSE, rownames = FALSE)  # replaces data displayed by the updated table
  )
  ### Reset Table
  observeEvent(reset(), 
    v$data <- data() # your default data
  )
  
  print(isolate(colnames(v$data)))

  )


modFunctionUI <- function(id) 
  ns <- NS(id)
  DTOutput(ns("mod_table"))
  


#===================================================
shinyApp(
  ui = basicPage(
    mainPanel(
      actionButton("reset", "Reset"),
      tags$hr(),
      modFunctionUI("editable")
    )
  ),
  server = function(input, output, session) 
    demodata <- reactive(input_data)
    modFunction("editable", demodata, reset = reactive(input$reset))
    #callModule(modFunction,"editable", demodata,reset = reactive(input$reset),globalSession = session)
  
)

【讨论】:

哇,我很感激!我认为这将是一件简单的事情,当它弄清楚时我会打自己的头 - 我是对的!再次感谢!

以上是关于使用增量计算在闪亮的应用程序中编辑数据表的主要内容,如果未能解决你的问题,请参考以下文章

编辑表时如何使用数据表在闪亮表中创建下拉列表?

如何在闪亮的可编辑数据表中指定文件名并限制列编辑

默认情况下,闪亮的应用程序数据对于特殊输入小部件不可见

使用带闪亮的 Flexdashboard 时如何拥有可编辑的 DT 表?

在闪亮应用程序的 DT::datatable 中添加、删除和编辑行

闪亮的DT编辑保存在错误的列中