Shiny野外数据记录应用单元格编辑报错:invalid (NULL) left side of assignment
野外数据记录Shiny应用表格编辑问题解决
问题描述
开发了一款用于野外数据记录的Shiny应用,功能包括:
- 观测人员通过
selectInput或radioGroupButtons录入物种名称(sp)、性别(sexe)、体型(size,限3个选项) - 点击「Update Table」按钮将单行数据追加到响应式表格
- 表格支持单元格编辑以修正录入错误
遇到的问题:
- 编辑表格后新增数据,之前的编辑内容会消失
- 添加
observeEvent尝试修改响应式dataframe时触发错误:Error in <-: invalid (NULL) left side of assignment,仅修改为原值时不报错,修改为新值则报错
原应用代码
ui <- fluidPage( sidebarLayout( sidebarPanel( selectInput(inputId = "sp", label = "sp", choices = c("espece1", "espece2")), radioGroupButtons(inputId = "sexe", label = "sexe", choices = c("M", "F"), status = "custom-class"), radioGroupButtons(inputId = "size", label = "size", choices = c("30", "20", "10"), status = "custom-class"), actionButton("update", "Update Table") ), mainPanel( dataTableOutput("table1") ) ) ) server <- function(input, output, session) { mydata <- reactiveVal(data.frame(sp = character(), sexe = character(), size = character(), stringsAsFactors = FALSE)) observeEvent(input$update, { to_add <- data.frame(sp = input$sp, sexe = input$sexe, size = input$size) mydata(rbind(mydata(), to_add)) }) output$table1 <- DT::renderDataTable({ datatable(mydata(), editable = "cell", options = list(pageLength = 50, paging = FALSE)) }) observeEvent(input$table1_cell_edit, { info <- input$table1_cell_edit row <- info$row col <- info$col value <- info$value mydata()[row,col] <- value }) } shinyApp(ui, server)
已尝试的解决方案
- 给
info$row和info$col加1,仍报错 - 使用
mydata()[row,col] <<- isolate(DT::coerceValue(value, mydata()[row,col])),仍报错 - 将响应式dataframe改为非响应式,触发错误:
Error in <-: object of type 'closure' is not subsettable
解决方案
错误核心原因:
mydata()是获取响应式变量值的函数,直接修改其返回的临时对象无法更新响应式变量,必须先提取当前数据,修改后重新赋值给mydata()- DT的
table1_cell_edit事件中,col是从0开始的索引,而R数据框的列索引从1开始,需要转换为col + 1 - 需确保修改后的数据类型与原列一致,可使用
DT::coerceValue自动转换
修正后的observeEvent逻辑:
observeEvent(input$table1_cell_edit, { info <- input$table1_cell_edit # 转换DT的0起始索引为R的1起始索引 row <- info$row + 1 col <- info$col + 1 value <- info$value # 提取当前响应式数据并修改 current_data <- mydata() current_data[row, col] <- DT::coerceValue(value, current_data[row, col]) # 更新响应式变量 mydata(current_data) })
修正后完整代码
ui <- fluidPage( sidebarLayout( sidebarPanel( selectInput(inputId = "sp", label = "sp", choices = c("espece1", "espece2")), radioGroupButtons(inputId = "sexe", label = "sexe", choices = c("M", "F"), status = "custom-class"), radioGroupButtons(inputId = "size", label = "size", choices = c("30", "20", "10"), status = "custom-class"), actionButton("update", "Update Table") ), mainPanel( dataTableOutput("table1") ) ) ) server <- function(input, output, session) { mydata <- reactiveVal(data.frame(sp = character(), sexe = character(), size = character(), stringsAsFactors = FALSE)) observeEvent(input$update, { to_add <- data.frame(sp = input$sp, sexe = input$sexe, size = input$size) mydata(rbind(mydata(), to_add)) }) output$table1 <- DT::renderDataTable({ datatable(mydata(), editable = "cell", options = list(pageLength = 50, paging = FALSE)) }) observeEvent(input$table1_cell_edit, { info <- input$table1_cell_edit row <- info$row + 1 col <- info$col + 1 value <- info$value current_data <- mydata() current_data[row, col] <- DT::coerceValue(value, current_data[row, col]) mydata(current_data) }) } shinyApp(ui, server)
内容的提问来源于stack exchange,提问作者tomB
相关产品推荐
相关产品推荐

