You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shiny中调用input$z列时get()触发==比较类型错误

问题描述

尝试在Shiny应用中通过响应式输入复现dr4pl的IC50计算方案,但遇到错误:

Error in ==: comparison (==) is possible only for atomic and list types

已创建包含示例数据的CSV文件,数据如下:

curve列
C1、C1、C1、C1、C1、C1、C1、C1、C1、C2、C2、C2、C2、C2、C2、C2、C2、C2、C3、C3、C3、C3、C3、C3、C3、C3、C3

POC列
1.07129314、0.9112628、0.97914297、0.95904437、0.8850967、0.84338263、0.75843762、0.61319681、0.52635571、0.84563087、1.24435113、1.11757648、0.82383523、0.82763447、0.72585483、0.31953609、0.15056989、0.10057988、0.57384256、0.65984339、0.81439758、0.84572057、0.62797088、0.30800934、0.08957274、0.06360764、0.04451161

dose列
0.078125、0.15625、0.3125、0.625、1.25、2.5、5、10、20、0.078125、0.15625、0.3125、0.625、1.25、2.5、5、10、20、0.078125、0.15625、0.3125、0.625、1.25、2.5、5、10、20

附上完整Shiny代码:

library(shiny)
library(tidyverse)
library(plotly)
library(dr4pl)
library(data.table)

ui <- fluidPage(# Application title
  sidebarLayout(
    sidebarPanel(
      fileInput('file', "Choose CSV File"),
      uiOutput('X_dropdown'),
      uiOutput('Y_dropdown'),
      uiOutput('Z_dropdown'),
      uiOutput('IC50_Checkbox'),
    ),
    
    mainPanel(plotlyOutput("Plot"),
              plotlyOutput("P_IC50_table"))
  ))

# Define server logic required to draw graph
server <- function(input, output, session) {
  #saves uploaded file as a reactive output, file can be changed
  dta <- reactive({
    req(input$file)
    read.csv(input$file$datapath, header = T)
  })
  
  output$X_dropdown <- renderUI({
    req(dta())
    selectInput('x', "X", names(dta()), selected = "dose")
  })
  output$Y_dropdown <- renderUI({
    req(dta())
    selectInput('y', "Y", names(dta()), selected = "POC")
  })
  output$Z_dropdown <- renderUI({
    req(dta())
    selectInput('z', "Color", names(dta()), selected = "curve")
  })
  output$IC50_Checkbox <- renderUI({
    req(dta())
    checkboxInput("ic50", "Calculate ICXX?", value = F)
  })
  
  
  output$Plot <- renderPlotly({
    req(dta())
    req(input$x)
    
    if (input$ic50 == T) {
      #Assign functions to variables
      
      
      multiIC <- function(data, 
                          colDose, colResp, colID, 
                          inhib.percent, 
                          ...) 
      {
        # Get curve IDs
        
        locID <- unique(data[[colID]])
        
        # Prepare a vector to store IC50s
        locIC <- rep(NA, length(locID))
        
        # Calculate IC50 separately for every curve
        #seq_along takes the length of the sequence
        for (ii in seq_along(locID)) {
          # Subset a single dose response
          locSub <- data[get(colID) == locID[[ii]], ]
          
          # Calculate IC50
          locIC[[ii]] <- dr4pl::IC(
            dr4pl::dr4pl(dose = locSub[[colDose]], 
                         response = locSub[[colResp]],
                         ...), 
            inhib.percent)
        }
        
        return(data.frame(id = locID,
                          x = locIC))
      }
      #changed data
      dfIC50 <- multiIC(data = dta(),
                        colDose = input$x,
                        colResp = input$y,
                        colID = input$z,
                        inhib.percent = 50              
      )
      #browser()
      IC50_table <- data.frame(id = locID, x = locIC)
      
      ggplotly(
        width = 500,
        height = 500,
        ggplot(data = dta(),
               aes(
                 x = .data[[input$x]],
                 y = .data[[input$y]],
                 color = as.factor(.data[[input$z]])
               )) +
          labs(color = "") +
          geom_vline(data = IC50_table, aes(xintercept = x))
      )
      
      output$P_IC50_table <- renderTable({
        #Attempt to add in IC50 curve
        IC50_table
      })
    } else{}
})
}
# Run the application
shinyApp(ui = ui, server = server)
错误原因与修正方案

关键错误点

  1. get()作用域问题:multiIC函数中get(colID)默认在全局环境查找,无法正确解析函数内data数据框的列名,导致比较操作失败。
  2. 变量未定义:IC50_table <- data.frame(id = locID, x = locIC)中的locID和locIC是multiIC内部局部变量,外部无法访问。
  3. 输出嵌套违规:在renderPlotly内部定义output$P_IC50_table不符合Shiny输出逻辑,输出应独立定义。

修正后的完整代码

library(shiny)
library(tidyverse)
library(plotly)
library(dr4pl)
library(data.table)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      fileInput('file', "Choose CSV File"),
      uiOutput('X_dropdown'),
      uiOutput('Y_dropdown'),
      uiOutput('Z_dropdown'),
      uiOutput('IC50_Checkbox')
    ),
    mainPanel(
      plotlyOutput("Plot"),
      tableOutput("IC50_table")  # 改用tableOutput适配表格显示
    )
  )
)

server <- function(input, output, session) {
  dta <- reactive({
    req(input$file)
    read.csv(input$file$datapath, header = TRUE)
  })
  
  output$X_dropdown <- renderUI({
    req(dta())
    selectInput('x', "X", names(dta()), selected = "dose")
  })
  output$Y_dropdown <- renderUI({
    req(dta())
    selectInput('y', "Y", names(dta()), selected = "POC")
  })
  output$Z_dropdown <- renderUI({
    req(dta())
    selectInput('z', "Color", names(dta()), selected = "curve")
  })
  output$IC50_Checkbox <- renderUI({
    req(dta())
    checkboxInput("ic50", "Calculate IC50?", value = FALSE)
  })
  
  # 独立封装IC50计算为反应式对象
  dfIC50 <- reactive({
    req(dta(), input$ic50, input$x, input$y, input$z)
    if (!input$ic50) return(NULL)
    
    multiIC <- function(data, colDose, colResp, colID, inhib.percent, ...) {
      locID <- unique(data[[colID]])
      locIC <- rep(NA, length(locID))
      
      for (ii in seq_along(locID)) {
        # 直接用数据框索引子集化,避免get()作用域问题
        locSub <- data[data[[colID]] == locID[[ii]], ]
        # 拟合模型并计算IC值
        dr_model <- dr4pl(dose = locSub[[colDose]], response = locSub[[colResp]], ...)
        locIC[[ii]] <- IC(dr_model, inhib.percent)
      }
      data.frame(id = locID, IC50 = locIC)
    }
    
    multiIC(data = dta(),
            colDose = input$x,
            colResp = input$y,
            colID = input$z,
            inhib.percent = 50)
  })
  
  output$Plot <- renderPlotly({
    req(dta(), input$x, input$y, input$z)
    p <- ggplot(data = dta(),
                aes(x = .data[[input$x]],
                    y = .data[[input$y]],
                    color = as.factor(.data[[input$z]]))) +
      geom_point() +  # 补充散点图层,显示原始数据
      labs(color = "")
    
    # 勾选IC50时添加垂直参考线
    if (input$ic50 && !is.null(dfIC50())) {
      p <- p + geom_vline(data = dfIC50(), aes(xintercept = IC50, color = id), linetype = "dashed")
    }
    
    ggplotly(p, width = 500, height = 500)
  })
  
  # 独立定义表格输出
  output$IC50_table <- renderTable({
    req(dfIC50())
    dfIC50()
  })
}

shinyApp(ui = ui, server = server)

核心修改说明

  • 子集化方式优化:用data[[colID]]直接访问列,替代get(colID),解决作用域导致的类型错误。
  • 反应式逻辑分离:将IC50计算封装为独立反应式对象,让绘图和表格输出复用结果,避免变量作用域问题。
  • 输出结构调整:将表格输出从绘图逻辑中移出,单独定义输出对象,符合Shiny的响应式规则。
  • 可视化完善:补充geom_point()显示原始数据点,让可视化更完整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 00:24:53