【问题标题】:Error: object of type 'closure' is not subsettable错误:“闭包”类型的对象不可子集
【发布时间】:2019-10-18 02:25:36
【问题描述】:

我正在尝试借助滑块更改 2 个 ValueBoxes 中的值(属性“pf_score”和“ef_score”每年的平均值),滑块的时间为 2008-2016 年。 输出如我所愿可见,但我也看到一个错误“'closure'类型的对象不是子集”

更新:我无法通过单击 Run-App 来运行整个代码。我收到错误“找不到函数 df1”。我必须先单独读取所有数据帧,然后单击 Run-App 才能看到 UI。

server.r

require(shiny)
require(dplyr)
require(shinydashboard)

shinyServer(function(input,output){
  
  df <- read.csv("hfi_cc_2018.csv", header = T)
  
  summary(df)
  sapply(df, function(x) sum(is.na(x)))
  #Replace Null Values
  df[is.na(df)] <- 0
  df[,5:ncol(df)] <- round(df[,5:ncol(df)], 2)
  
  #adding selective columns new df1
  #https://stackoverflow.com/questions/10085806/extracting-specific-columns-from-a-data-frame
  df1<- df[, (names(df) %in% c("year","pf_score", "ef_score"
  ))]

output$select_years <- renderUI(
{
   card <- df1 %>%
              filter(year == input$years)
   output$pfrank = renderValueBox(
     valueBox(round(mean(card$pf_score),1),
              "Personal Freedom Score")
   )
   output$efrank = renderValueBox(
     valueBox(round(mean(card$ef_score),1),
              "Economic Freedom Score")
   )
}
)
})

ui.r

require(shiny)
require(shinydashboard)

shinyUI(
  
  dashboardPage( 
    dashboardHeader(title = "Human Freedom Index", titleWidth = 300),
    dashboardSidebar(
      sliderInput("years","Select Year:",
                  min = min(df1$year),
                  max = max(df1$year),
                  value = min(df1$year),
                  step = 1),
      selectInput("variable","Select Freedom Factor:",
                  choices = colnames(df1)
                  )
    ),
    
    dashboardBody(
      uiOutput("select_years"),
      fluidRow(
        valueBoxOutput("pfrank"),
        valueBoxOutput("efrank")
      )
    )
  )
  
)

【问题讨论】:

  • df改成DF看看会发生什么
  • 嗨迈克尔,尝试更改它,仍然无法正常工作!
  • 错误是否改变了?
  • 没有。这是同样的错误。此外,我刚刚意识到我无法使用 Run App 运行我的代码。我必须一个接一个地运行所有数据帧,然后单击运行应用程序才能成功查看 UI。

标签: r shiny shinydashboard


【解决方案1】:

此类错误在:Error in <my code> : object of type 'closure' is not subsettable

中讨论

在这种情况下,看起来您将 card 作为纯数据框,而您需要 reactive 以便在您移动滑块时重新计算它。此外,renderUI 的表达式可以简化为一个列表。例如,

ui <- shinyUI( ... )
server <- function(input, output) {
  card <- reactive({
    df1 %>%
    filter(year == input$years)
  })
  output$select_years <- renderUI(
    c(renderValueBox(valueBox(round(mean(card()$pf_score), 1),
                   "Personal Freedom Score")),
      renderValueBox(valueBox(round(mean(card()$ef_score), 1),
                   "Economic Freedom Score"))))
}
shinyApp(ui, server)

还要注意,新版本的 Shiny 稍微简化了语法。代码可以直接进入app.R,你需要定义uiserver

【讨论】:

  • 这是一个比我发布的更好的解决方案,我希望@Advait 更改接受的答案以反映这一点。 @James 为什么renderUI({renderValueBox(...); renderValueBox(...)})renderUI({renderValueBox(...)}) 都给出“闭包不是子集”错误,而renderUI(c(renderValueBox(...), renderValueBox(...))) 却没有?回溯显示它在paste8 内的106: lapply 行失败,但源代码没有帮助。所以我认为这与 renderValueBox 是一个反应性表达式有关,它是一个闭包?
  • renderUI 参数可以采用多种不同的形式,但我认为这里要记住的是您正在设置一个将作为output 的一部分返回的数据结构。您给出的第一个示例在 {...} 内进行计算,然后将最后一个表达式结果提供给 renderUI。所以这不太好,因为您可能希望同时包含 renderValueBox 表达式。我认为闭包的问题在于您传递的东西应该是反应式或数据结构 - 而不是闭包。
【解决方案2】:

您可以使用observe() 代替renderUI 来呈现值框:

require(shiny)
require(dplyr)
require(shinydashboard)

   df <- read.csv("hfi_cc_2018.csv", header = T)

   summary(df)
   sapply(df, function(x) sum(is.na(x)))
   #Replace Null Values
   df[is.na(df)] <- 0
   df[,5:ncol(df)] <- round(df[,5:ncol(df)], 2)

   #adding selective columns new df1
   #https://stackoverflow.com/questions/10085806/extracting-specific-columns-from-a-data-frame
   df1 <- df[, (names(df) %in% c("year","pf_score", "ef_score"))]

 #UI  
 ui <- dashboardPage( 
    dashboardHeader(title = "Human Freedom Index", titleWidth = 300),
    dashboardSidebar(
      sliderInput("years","Select Year:",
                  min = min(df1$year),
                  max = max(df1$year),
                  value = min(df1$year),
                  step = 1),
      selectInput("variable","Select Freedom Factor:",
                  choices = colnames(df1)
      )
    ),

    dashboardBody(
      fluidRow(
        valueBoxOutput("pfrank"),
        valueBoxOutput("efrank")
      )
    )
  )

#Server
 server <- function(input,output){

   observe({
       card <- df1 %>%
         filter(year == input$years)
       output$pfrank = renderValueBox(
         valueBox(round(mean(card$pf_score),1),
                  "Personal Freedom Score")
       )
       output$efrank = renderValueBox(
         valueBox(round(mean(card$ef_score),1),
                  "Economic Freedom Score")
       )
     })
 }

#Run app
shinyApp(ui, server)

【讨论】:

  • 非常感谢。有效。你能解释一下观察的目的吗?
  • 没问题! observe() 监听 input$years 的值,并在每次 input$years 更改时重新执行其中的表达式。 observeEvent(input$years, {...}) 会给出相同的结果。 render_ 函数中的表达式必须返回 Shiny 标记对象、HTML 或此类对象的列表,而您问题中的 renderUI 返回的对象是 output$efrank,其中包含更新值所需的代码box,即反应式表达式,它定义了一个闭包。我可能弄错了,但我认为这就是错误的来源。
  • PS 像 df 这样的全局变量应该定义在 ui/server 函数之外或者在你的 app 目录下的 global.R 文件中。在我的回答中,我在 UI 调用之前定义了它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 2017-03-30
相关资源
最近更新 更多