我有一个Shiny应用程序,可以动态加载任意数量的outputPlot
UI。在下面的示例中,我只是迭代字母表的前三个字母。
要在动态加载的UI中渲染图,我在循环中这样调用renderPlot
:
for (a in LETTERS[1:3]) {
output[[paste0('p',a)]] <- renderPlot(plot.df(df, a))
}
但是结果是所有三个outputPlot(pA
,pB
和pC
)都是用plot.df(df, 'C'))
渲染的。在循环看来,renderPlot
之后a = 'C'
就呈现出来了。相反,应该分别用pA
,pB
和pC
渲染输出UI plot.df(df, 'A')
,plot.df(df, 'B')
和plot.df(df, 'C')
。但是查看输出时显然不是这种情况。
如果输出UI是一个模块,并且在循环中调用callModule
,那么我以前就已经成功了,它以某种方式强制了参数的求值。但是我现在试图避免为输出UI制作单独的模块。
library(shiny)
library(dplyr)
# Define UI for application that draws a histogram
ui <- fluidPage(
plotOutput('pltA'),plotOutput('pltB'),plotOutput('pltC'),
tags$hr(),
tags$div(id='placeholder')
)
col <- c(A='#66bd63', B='#fdae61', C='#74add1')
plot.df <- function(df, a) {
#browser()
df <- filter(df, letter==a)
if (nrow(df) == 0) return()
plot(df$i, df$y, type='p', col=col[a], pch=19, main=a)
}
# Define server logic required to draw a histogram
server <- function(input, output, session) {
my_data <- reactiveVal(data.frame())
autoInvalidate <- reactiveTimer(2000)
# Generate some random data and assign to one of three different letters:
observe({
autoInvalidate()
a <- sample(LETTERS[1:3], 1)
data.frame(y=rnorm(5), letter=a) %>%
bind_rows(isolate(my_data())) %>%
group_by(letter) %>%
mutate(i=seq_along(y)) %>%
my_data
})
# Proof of function making a plot.
output$pltA <- renderPlot(plot.df(my_data(), 'A'))
output$pltB <- renderPlot(plot.df(my_data(), 'B'))
output$pltC <- renderPlot(plot.df(my_data(), 'C'))
# Dynamically load output UIs.
observe({
let <- unique(my_data()$letter)
if (is.null(let)) return()
for (l in let) {
if (is.null(session$clientData[[paste0('output_p',l,'_hidden')]])) {
insertUI('#placeholder', 'beforeEnd', ui=plotOutput(paste0('p',l)))
}
}
})
# Update dynamically loaded plots
observe({
df <- my_data()
if (nrow(df) == 0) return()
for (a in LETTERS[1:3]) {
cat('Updating ', a, '\n')
output[[paste0('p',a)]] <- renderPlot(plot.df(df, a))
}
})
}
# Run the application
shinyApp(ui = ui, server = server)
答案 0 :(得分:2)
您必须使用local
(请参阅here)。
for (a in LETTERS[1:3]) {
local({
aa <- a
output[[paste0('p',aa)]] <- renderPlot(plot.df(df, aa))
})
}