Shiny - 使用 for 循环插入 UI 在每个输出中返回相同的元素

Col*_*FAY 5 r shiny

我想在我的 Shiny 应用程序中插入非预定义数量的图表。我使用了一个for循环和一系列的insertUI。

问题是当我运行它时,文本元素的行为符合预期,但图表都呈现相同的图像。我怎样才能防止这种情况发生?

这是一个代表:

library(shiny)

ui <- fluidPage(
  tags$div(
    class = "this", 
    actionButton("go", "go")
  )
)

server <- function(input, output, session) {

  observeEvent( input$go , {

    x <- reactiveValues(x = list(iris, mtcars, airquality))

    for (i in 1:3){
      insertUI(
        ".this", 
        ui =  tagList(
          p(paste("Number", i)),
          renderPlot({
            plot(x$x[[i]])
          })
        ))
    }
  })

}

shinyApp(ui, server)

Run Code Online (Sandbox Code Playgroud)

欣欣

gre*_*g L 9

当心 for 循环中的闭包;)。R 中没有块作用域,因此每个 for 循环迭代共享相同的迭代器变量i。这些renderXX函数本质上存储的表达式不会立即计算,而是在稍后渲染时才计算。

\n\n

因此,当绘图准备好渲染时,for 循环已完成,i现在为 3,并且每个plot(x$x[[i]])表达式都称为plot(x$x[[3]])

\n\n

local()您可以通过使用或 函数为每个循环迭代创建新范围来解决此问题。lapply正如您所发现的,我最喜欢的解决方案是使用i函数范围内的变量来运行函数中的每个循环迭代。

\n\n

许多没有块作用域的语言都有同样的陷阱,比如 Python 和 JS:

\n\n\n

  • 我在这个问题上找到的最清晰的答案。For 循环失败,因为执行是惰性的,并且所有反应式表达式共享相同的“i”(没有块作用域!),而不是它的值。也感谢您引用 Python 和 JS。 (2认同)

Col*_*FAY 5

因此,找到了我自己的问题 \xe2\x80\x94 的答案,使用lapply()使得这项工作有效:

\n\n
library(shiny)\n\nui <- fluidPage(\n  tags$div(\n    class = "this", \n    actionButton("go", "go")\n  )\n)\n\nserver <- function(input, output, session) {\n\n  observeEvent( input$go , {\n\n    x <- reactiveValues(x = list(iris, mtcars, airquality))\n\n    lapply(1:3, function(i){\n      insertUI(\n        ".this", \n        ui =  tagList(\n          p(paste("Number", i)),\n          renderPlot({\n            plot(x$x[[i]])\n          })\n        ))\n    })\n  })\n\n}\n\nshinyApp(ui, server)\n
Run Code Online (Sandbox Code Playgroud)\n