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

Shiny应用本地运行正常,部署网页时遇'closure类型对象不可子集化'错误

问题根源

你遇到的object of type 'closure' is not subsettable错误,核心原因是UI渲染时机早于数据加载:

  • UI代码在应用启动时就会执行,而你把data <- read.csv(...)放在了server函数内部,此时UI里的unique(data$Product)调用的是R内置的data()函数(一种closure类型的对象),而非你加载的数据集,自然无法用$子集化。
  • 本地RStudio运行时不报错,是因为你之前在全局环境中加载过data,UI能直接读取到;但部署时是全新的运行环境,全局环境没有这个数据集,就触发了错误。
修复方案

有两种可靠的修复方式,选其中一种即可:

方案1:将数据加载移到全局环境

把数据读取和预处理代码放在ui和server定义之前,让UI渲染时能直接访问到数据集:

library(shiny)
library(ggplot2)
library(plotly)

# 全局环境加载并预处理数据(移到UI/Server之前)
data <- read.csv("Dataset_Chile.csv", sep=";")
data$Campaigns <- as.factor(data$Campaigns)
data$Date <- as.numeric(as.Date(data$Date, format="%m/%d/%Y")) - as.numeric(as.Date("01/01/2019", format="%m/%d/%Y"))

# UI function
ui <- fluidPage(
  titlePanel("SellOut Chile predictive model"),
  sidebarLayout(
    sidebarPanel(
      dateInput("date", "Date:", value = as.Date("2023-01-01")),
      numericInput("customers", "Customers:", min = 6, max = 8, value = 7),
      selectInput("campaigns", "Campaigns:", choices = c(0, 1), selected = 0),
      sliderInput("sellin", "SellIn.UDS:", min(0), max(60000), value = 20000),
      # 现在能正常访问data$Product了
      selectInput("product", "Product:", choices = unique(data$Product), selected = unique(data$Product)[1])
    ),
    mainPanel(
      h4("Predicted SellOut:"),
      verbatimTextOutput("prediction"),
      h4("Plot of Date vs SellOut:"),
      plotlyOutput("plot")
    )
  )
)

# Server function
server <- function(input, output) {
  # 这里不再重复加载数据,直接用全局环境的data
  model <- lm(SellOut.UDS ~ Date + Product + SellIn.UDS + Customers + Campaigns, data=data)
  
  new <- reactive({
    data.frame(Date=as.numeric(input$date - as.Date("2019-01-01")), 
               Customers=input$customers, 
               SellIn.UDS=input$sellin, 
               Product=input$product, 
               Campaigns=as.factor(input$campaigns))
  })
  
  output$prediction <- renderPrint({
    predict(model, newdata=new())
  })
  
  output$plot <- renderPlotly({
    subset_data <- subset(data, Product == input$product)
    predicted_value <- predict(model, newdata=new())
    
    gg <- ggplot(subset_data, aes(Date, SellOut.UDS, group = Product, text = paste("SellIn.UDS: ", SellIn.UDS))) + 
      geom_line() +
      xlab("Date") + 
      ylab("SellOut.UDS") +
      geom_point(data=new(), aes(x=Date, y=predicted_value), color="blue", size=2.5)
    
    ggplotly(gg)
  })
}

shinyApp(ui, server)

方案2:用renderUI动态生成产品选择框

如果不想把数据放在全局环境(比如数据很大或需要动态加载),可以在server中用renderUI生成selectInput,确保数据加载完成后再生成选项:

library(shiny)
library(ggplot2)
library(plotly)

# UI function
ui <- fluidPage(
  titlePanel("SellOut Chile predictive model"),
  sidebarLayout(
    sidebarPanel(
      dateInput("date", "Date:", value = as.Date("2023-01-01")),
      numericInput("customers", "Customers:", min = 6, max = 8, value = 7),
      selectInput("campaigns", "Campaigns:", choices = c(0, 1), selected = 0),
      sliderInput("sellin", "SellIn.UDS:", min(0), max(60000), value = 20000),
      # 用uiOutput占位,后续由server动态生成
      uiOutput("product_select")
    ),
    mainPanel(
      h4("Predicted SellOut:"),
      verbatimTextOutput("prediction"),
      h4("Plot of Date vs SellOut:"),
      plotlyOutput("plot")
    )
  )
)

# Server function
server <- function(input, output) {
  # 加载并预处理数据
  data <- read.csv("Dataset_Chile.csv", sep=";")
  data$Campaigns <- as.factor(data$Campaigns)
  data$Date <- as.numeric(as.Date(data$Date, format="%m/%d/%Y")) - as.numeric(as.Date("01/01/2019", format="%m/%d/%Y"))
  
  model <- lm(SellOut.UDS ~ Date + Product + SellIn.UDS + Customers + Campaigns, data=data)
  
  # 动态生成产品选择框
  output$product_select <- renderUI({
    selectInput("product", "Product:", choices = unique(data$Product), selected = unique(data$Product)[1])
  })
  
  new <- reactive({
    data.frame(Date=as.numeric(input$date - as.Date("2019-01-01")), 
               Customers=input$customers, 
               SellIn.UDS=input$sellin, 
               Product=input$product, 
               Campaigns=as.factor(input$campaigns))
  })
  
  output$prediction <- renderPrint({
    predict(model, newdata=new())
  })
  
  output$plot <- renderPlotly({
    subset_data <- subset(data, Product == input$product)
    predicted_value <- predict(model, newdata=new())
    
    gg <- ggplot(subset_data, aes(Date, SellOut.UDS, group = Product, text = paste("SellIn.UDS: ", SellIn.UDS))) + 
      geom_line() +
      xlab("Date") + 
      ylab("SellOut.UDS") +
      geom_point(data=new(), aes(x=Date, y=predicted_value), color="blue", size=2.5)
    
    ggplotly(gg)
  })
}

shinyApp(ui, server)
额外提醒
  • 部署时要确保Dataset_Chile.csv文件和app代码在同一目录下,或者使用完整文件路径。
  • 避免用R内置函数名(比如data、new)作为变量名,虽然语法允许,但容易引发这类混淆错误,建议把data改成chile_data,new改成new_pred_data这类更清晰的名字。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 16:44:58