我想在我的 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)
当心 for 循环中的闭包;)。R 中没有块作用域,因此每个 for 循环迭代共享相同的迭代器变量i。这些renderXX函数本质上存储的表达式不会立即计算,而是在稍后渲染时才计算。
因此,当绘图准备好渲染时,for 循环已完成,i现在为 3,并且每个plot(x$x[[i]])表达式都称为plot(x$x[[3]])。
local()您可以通过使用或 函数为每个循环迭代创建新范围来解决此问题。lapply正如您所发现的,我最喜欢的解决方案是使用i函数范围内的变量来运行函数中的每个循环迭代。
许多没有块作用域的语言都有同样的陷阱,比如 Python 和 JS:
\n\n\n因此,找到了我自己的问题 \xe2\x80\x94 的答案,使用lapply()使得这项工作有效:
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)\nRun Code Online (Sandbox Code Playgroud)\n