首页 > 解决方案 > 处理数据时更新闪亮的界面

问题描述

处理数据时如何更新界面?

这是完整的故事:

我在 docker 容器中运行一个闪亮的应用程序。在启动应用程序之前,我需要下载大量数据(这需要一些时间)。在此期间,无法连接到闪亮的 Web 服务器——因为它还没有启动。但是,我想制作一个简单的页面“请稍候,正在下载数据(XX%)”或类似的内容,一旦加载数据,停止应用程序并运行另一个应用程序。

下面是一些有效的代码。即应用程序运行,执行“处理块”,当“数据加载”完成时,调用stopApp并返回结果。但是,在完成所有“工作”之前不会呈现输出。

library(shiny)

ui <- fluidPage(
                titlePanel("Please wait!"),
                fluidRow(
                         textOutput("msg")))

srv <- function(input, output) {

  output$msg <- renderText("Waiting")

  observe({
    ## the data loading block
    message("doing the job")
    Sys.sleep(10)

    message("proceeding")
    output$msg <- renderText("OK, proceeding")

    Sys.sleep(10)
    output$msg <- renderText("Nearly finished")
    message("nearly")

    Sys.sleep(10)
    message("done")
    stopApp(list(a=1, b=2))
  })
}

foo <- runApp(shinyApp(ui=ui, server=srv))

现在,我做错了什么?更奇怪的是,即使是“请等待” renderText 调用也不会执行,直到一切都完成。

我认为问题是冲洗。我假设闪亮等待与浏览器中的 JS 通信,直到所有反应表达式都完成评估。我不知道如何告诉它立即更新 UI。

我想可以将处理拆分为一系列相互依赖并与接口交互的反应式表达式,一点一点地更新接口,但首先,这很难扩展(我需要加载几个数据集而我不需要事先知道他们的号码),其次它看起来很奇怪。最重要的是,我尝试了几种方法,但都失败了。我想出的最佳解决方案是这样的:

ui <- fluidPage(
                titlePanel("Please wait!"),
                fluidRow(
                         numericInput("xxx", label="testlab", value=0),
                         textOutput("msg")))

srv <- function(input, output, session) {

  steps <- reactiveVal(1)

  observe({
    message("starting stuff")
      updateNumericInput(session=session, inputId="xxx", value=1)
  })
    
  observeEvent(input$xxx, {

    n <- req(input$xxx)

    message("Running job ", n)
    Sys.sleep(10)
    updateNumericInput(inputId="xxx", value=n + 1)

    if(n == 3) {
      stopApp(list(steps=n, done=TRUE))
    }
  })

  output$msg <- renderText({
    n <- req(input$xxx)
    return(sprintf("Processing job %d", n))
  })
}

foo <- runApp(shinyApp(ui=ui, server=srv))

我缺少一个简单的技巧吗?

标签: rshinyreactive

解决方案


像这样的东西? 资源

library(shiny)
library(waiter)

ui <- fluidPage(
  useWaitress(),
  p("App content")
)

server <- function(input, output){

  # call the waitress
  waitress <- Waitress$
    new(theme = "overlay-percent")$
    start() # start

# insert data loading here instead of the for loop
# put some waitress$inc(X) between loading data if your data
# is composed of several variables

  for(i in 1:10){
    waitress$inc(10) # increase by 10%
    Sys.sleep(.3)
  }

  # hide when it's done
  waitress$close() 

}

shinyApp(ui, server)

推荐阅读