在处理数据时更新闪亮的界面
Update shiny interface while processing data
如何在处理数据的同时更新界面?
这是完整的故事:
我正在 运行 在 docker 容器中安装一个闪亮的应用程序。在启动该应用程序之前,我需要下载大量数据(这需要一些时间)。在此期间,无法连接到闪亮的网络服务器——因为它还没有启动。但是,我想制作一个简单的页面“请稍候,正在下载数据 (XX%)”或类似的内容,一旦数据加载完毕,停止该应用程序并 运行 另一个应用程序。
下面是一些有效的代码。也就是说,应用程序 运行s,执行“处理块”,当“数据加载”完成时,调用 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 调用也不会在一切完成之前执行。
我觉得是冲水的问题。我假设 shiny 等待与浏览器中的 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))
有没有我遗漏的简单技巧?
是这样的吗?
Source
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)
如何在处理数据的同时更新界面?
这是完整的故事:
我正在 运行 在 docker 容器中安装一个闪亮的应用程序。在启动该应用程序之前,我需要下载大量数据(这需要一些时间)。在此期间,无法连接到闪亮的网络服务器——因为它还没有启动。但是,我想制作一个简单的页面“请稍候,正在下载数据 (XX%)”或类似的内容,一旦数据加载完毕,停止该应用程序并 运行 另一个应用程序。
下面是一些有效的代码。也就是说,应用程序 运行s,执行“处理块”,当“数据加载”完成时,调用 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 调用也不会在一切完成之前执行。
我觉得是冲水的问题。我假设 shiny 等待与浏览器中的 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))
有没有我遗漏的简单技巧?
是这样的吗? Source
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)