You need to enable JavaScript to run this app. Shiny修改输入时出现Can't extract columns that don't exist报错如何解决
优惠活动
大模型
产品
解决方案
定价
更多

Shiny修改输入时出现Can't extract columns that don't exist报错如何解决

问题原因
  • 核心为响应式表达式的执行时序问题:重新选择列后点击按钮时,input$select_var/input$select_var_2的更新、df_sel/df_sel_global的重计算、joined_dfs的拼接、matched_val的计算、DT的渲染几乎同时触发,旧的响应式结果还在引用已经被替换的列名,就会触发「列不存在」的报错;第二次点击时所有依赖更新完成,即可正常渲染。
  • 次要问题:dplyr的动态列选择没有用all_of()包裹字符串类型的列名,容易触发变量解析错误;formatStyle写死列索引3,健壮性差。
修复方案

对代码的核心逻辑做以下修改即可解决问题:

  1. 所有动态列选择/提取操作,用all_of()包裹列名字符串,明确告知dplyr输入为列名字符串而非环境变量
  2. 给joined_dfs补充必填参数校验,确保两个选中的列都存在再执行拼接
  3. formatStyle用动态列名代替固定索引,避免后续列顺序调整后高亮逻辑失效
  4. DT渲染前补充joined_dfs()和matched_val()的校验,确保所有数据就绪后再执行渲染

修改后的核心代码如下:

server <- function(input, output) {
  
  # File handler ----
  mydata <- reactive({
    req(input$xlsxfile)
    inFile <- input$xlsxfile
    req(file.exists(input$xlsxfile$datapath))
    openxlsx::read.xlsx(xlsxFile = inFile$datapath,
                        sheet = 1 ,
                        detectDates = TRUE,
                        sep.names = "_")
  })
  
  # Dynamically generate UI input when data is uploaded, only show numeric columns ----
  output$checkbox <- renderUI({
    selectInput(inputId = "select_var", 
                label = "Select variables", 
                choices = c("", names(mydata() %>%
                                        dplyr::select_if(is.numeric))),
                selected = NULL, 
                multiple = FALSE)
  })
  
  # Select columns to print ----
  df_sel <- reactive({
    req(input$select_var)
    mydata() %>% 
      dplyr::select(all_of(input$select_var), date)
  })
  
  
  # Same as above but for global.R variable  ----
  output$checkbox_2 <- renderUI({
    if (is.null(mydata())) return(NULL)
    selectInput(inputId = "select_var_2", 
                label = "Select variables", 
                choices = c("", names(local_iris %>%
                                        dplyr::select_if(is.numeric))),
                selected = NULL, 
                multiple = FALSE)
  })
  
  
  df_sel_global <- reactive({
    req(input$select_var_2)
    local_iris %>% 
      dplyr::select(all_of(input$select_var_2), Date)
  })
  
  output$joinnow <- renderUI({
    if (is.null(input$xlsxfile)) return()
    actionButton("action", "Press after selecting variables")
  })
  
  # Join the dataframes together based on a key  ----
  joined_dfs <-  eventReactive(input$action, {
    req(input$select_var, input$select_var_2)
    dplyr::inner_join(df_sel(), df_sel_global(), by= c("date" = "Date")) %>%
      dplyr::select(date, all_of(input$select_var), all_of(input$select_var_2))
  })
  
  # Render data frame ----
  matched_val <- reactive({ 
    req(input$action, input$select_var, input$select_var_2, joined_dfs())
    ifelse(
      joined_dfs() %>% dplyr::pull(all_of(input$select_var)) != joined_dfs() %>% dplyr::pull(all_of(input$select_var_2)),
      yes = joined_dfs() %>% dplyr::pull(all_of(input$select_var_2)),
      no = -979025189201
    )
  })
  
  
  output$contents <- DT::renderDT(server = FALSE, {
    req(input$action, joined_dfs(), matched_val())
    df_render <- if(input$disp == "head") {head(joined_dfs())} else {joined_dfs()}
    DT::datatable(
      df_render, 
      filter = 'top', 
      extensions = c('Buttons'),
      options = list(
        scrollY = 600,
        scrollX = TRUE,
        pageLength = 20,
        dom =  '<"float-left"l><"float-right"f>rt<"row"><"col-sm-4"B><"col-sm-4"i><"col-sm-4"p>>',
        lengthMenu=  list(c(20, 40, 60, -1), c('20', '40', '60','All')),
        scrollCollapse= TRUE,
        lengthChange = TRUE,
        rownames = TRUE
      )
    ) %>%
      formatStyle(
        columns = input$select_var_2,
        backgroundColor = styleEqual(levels = matched_val(), values = rep("yellow", length(matched_val())))
      )
  })
}

内容的提问来源于stack exchange,提问作者WannabeSmith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 16:57:03