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

时间:2019-01-23 12:23:46

标签: 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)

shinyui

2 个答案:

答案 0 :(得分:4)

因此,找到了我自己的问题的答案-使用lapply()可以完成这项工作:

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))

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

}

shinyApp(ui, server)

答案 1 :(得分:2)

当心for循环中的闭包;)。 R中没有块作用域,因此每个for循环迭代共享相同的迭代器变量irenderXX函数实际上存储的不是立即求值的表达式,而只是在以后需要渲染时才求值。

因此,在准备绘制图形时,已经完成了for循环,i现在为3,每个plot(x$x[[i]])表达式都称为plot(x$x[[3]])

您可以通过使用local()或函数为每个循环迭代创建一个新的作用域来解决此问题。我最喜欢的解决方案是使用lapply,以i作为函数作用域变量在函数中运行每个循环迭代。

许多没有块范围的语言都具有相同的陷阱,例如Python和JS: