我有Shiny的问题,我不知道这是一个错误还是我错过了一些东西.我试图找到一个解决方案,但我似乎无法在网上找到这个问题的参考.
我有一个按下按钮时应该运行的功能,但它只在用户按下按钮后查看输出时才会运行.
这有点奇怪,所以我创建了一个最小的例子.我有两个标签.在第一个中,我选择一个数字(平均值),在第二个选项卡中,我绘制了该值的值.该按钮位于第一个选项卡中,但"create.plot"功能仅在转到tab2时才开始运行.为了清楚起见,我创建了这个'loading.div',它在函数运行时显示出来.
library(shiny) library(shinyjs) create.plot <- function(mean) { shinyjs::show('loading.div') y <- rep(NA,10) for(i in 1:10) { y[i] <- rnorm(1,mean=mean) Sys.sleep(0.5) } shinyjs::hide('loading.div') return(list(y=y, test='Now it runs from tab1')) } server <- function(input, output, session) { run.function <- eventReactive(input$run,create.plot(input$mean)) output$plot.y <- renderPlot({ plot(run.function()[['y']]) }) output$test <- renderText({ run.function()[['test']] }) } ui <- fluidPage(shinyjs::useShinyjs(), hidden(div(id='loading.div',h3('Loading..'))), tabsetPanel( tabPanel('tab1', numericInput(inputId = 'mean',label='Mean', value=1), actionButton(inputId = 'run', label='Run') #,textOutput('test') ## Uncommenting this line, it works. ), tabPanel('tab2', plotOutput('plot.y')) ) ) shinyApp(server=server,ui=ui)
为了确保问题是用户在tab1时没有查看输出,我创建了一个测试字符串.如果取消注释该行,则问题是"修复":该功能在用户点击按钮后直接运行.但是,这只能起作用,因为他正在查看tab1中的输出.
这成为一个严重的问题,因为我有一个闪亮的仪表板,有很多标签.有带输入的选项卡和带输出的选项卡.我希望在单击按钮时运行该功能,但它仅在用户进入"输出"选项卡时运行.
这是一个已知的问题吗?有变通方法吗?
不可见的反应元素被视为"暂停",并且在取消暂停之前不会更新它们的值.默认情况下,直到它们在屏幕上呈现时才会发生这种情况.
即使不可见,也可以通过更改其挂起状态来设置要更新的元素.您可以使用该outputOptions
功能执行此操作.
对于output$test
元素,您需要运行
outputOptions(output, "test", suspendWhenHidden = FALSE)
如果您想要更新多个元素,即使不可见,也可以使用
lapply(c("test1", "test2", "test3"), function(x) outputOptions(output, x, suspendWhenHidden = FALSE)
但请注意,这意味着所有计算都将立即执行.根据计算的大小,这可能会降低应用程序的性能.例如,如果有一个生成的图并且需要花费一些时间来渲染,并且只有一小部分用户会看到该图,那么在用户请求它以防止放慢速度之前将其保持暂停可能是谨慎的.计算更常用的元素.
事实证明"情节不能提前呈现,因为它们没有宽度和高度."(https://github.com/rstudio/shiny/issues/1409).所以我们必须做一些诡计来提前渲染情节:
我们可以选择我们的情节的尺寸,而不是shiny
自动适应它.这意味着如果屏幕放大,情节不会增长.
library(shiny) library(shinyjs) create.plot <- function(mean) { print("working.....") shinyjs::show('loading.div') y <- rep(NA,10) for(i in 1:10) { y[i] <- rnorm(1,mean=mean) Sys.sleep(0.5) } shinyjs::hide('loading.div') y } server <- function(input, output, session) { run.function <- eventReactive(input$run,create.plot(input$mean)) output$plot.y <- renderPlot({ plot(run.function()) }, width = 72 * 5, height = 72 * 3 ) outputOptions(output, "plot.y", suspendWhenHidden = FALSE) } ui <- fluidPage(shinyjs::useShinyjs(), hidden(div(id='loading.div',h3('Loading..'))), tabsetPanel( tabPanel('tab1', numericInput(inputId = 'mean',label='Mean', value=1), actionButton(inputId = 'run', label='Run') ), tabPanel('tab2', plotOutput('plot.y')) ) ) shinyApp(server=server,ui=ui)