这是关于Rshiny的询问。我创建了一个名为foo的函数,如下所示。在函数中,for 循环中有 5 个图。在 Shiny 中制作绘图时,只有最后一个绘图可见,其余绘图不可见。您看不到正在创建(更新(五个图吗?
foo <- function(iter = 5){
for(j in 1:iter){
plot(iris$Sepal.Length, iris$Sepal.Width, col = j)
Sys.sleep(0.5)
}
}
ui<-shinyUI(fluidPage(
sth
plotOutput('myplot')
))
server <- shinyServer(function(input, output, session){
sth ...
output$myplot <- renderPlot({
f <- foo(iter = 3)
})
})
})
不能在此处使用循环,因为服务器在 UI 中呈现新输出之前执行所有代码,Sys.sleep()
只会导致整个 R 进程停止指定的时间量。相反,您可以使用invalidateLater()
使绘图函数以设定的时间间隔触发,同时仍允许程序的其余部分正常运行。
library(shiny)
ui <- shinyUI(fluidPage(
sliderInput("iterations", "Iterations", 1, 10, 3),
sliderInput("interval", "Interval (ms)", 100, 1000, 500, step = 100),
actionButton("draw", "Draw"),
plotOutput('myplot')
))
server <- shinyServer(function(input, output, session) {
foo <- function(iterations = 5, interval = 500) {
i <- 0
output$myplot <- renderPlot({
i <<- i + 1
if (i < iterations)
invalidateLater(interval)
plot(iris$Sepal.Length, iris$Sepal.Width, col = i)
})
}
observeEvent(input$draw, foo(input$iterations, input$interval))
})
shiny::shinyApp(ui, server)
现在,你也可以把每个间隔做一些事情的想法包装成一种延迟map
函数,看起来像这样:
map_later <- function(.x, .f, ..., .interval = 500) {
i <- 0
observe({
i <<- i + 1
if (i < length(.x))
invalidateLater(.interval)
.f(.x[i], ...)
})
}
这将产生一个更整洁、更易于管理的服务器:
ui <- shinyUI(fluidPage(
plotOutput('myplot')
))
server <- shinyServer(function(input, output, session) {
map_later(1:5, function(i) {
output$myplot <- renderPlot({
plot(iris$Sepal.Length, iris$Sepal.Width, col = i)
})
}, .interval = 500)
})
shiny::shinyApp(ui, server)
命名在这里可能不是很好,但是嘿,它做了它应该做的事情。