gpt4 book ai didi

r - 如何在 Shiny App 的 downloadHandler 中使用 callr::r_bg

转载 作者:行者123 更新时间:2023-12-05 02:38:08 25 4
gpt4 key购买 nike

我用下面的最小示例模拟的场景是允许用户在长时间运行的下载过程中使用 Shiny App(单击 numericInput 控件并查看发生服务器端事件)正在发生(用 downloadHandler 中的 Sys.sleep(10) 模拟)。

在同步设置中,单击“下载”按钮时,用户仍然可以与 UI 元素进行交互,但其他 Shiny 计算(在本例中为 renderText)会被放入队列中.我想要异步设置,下载在后台进行,用户仍然可以与 UI 元素交互获得所需的输出(例如renderText)。

我正在使用 callr::r_bg() 在 Shiny 中实现异步,但问题是我当前的 downloadHandler 代码不正确(mtcars 应该是正在下载,但代码无法完成下载,404 错误消息),我相信这是由于 downloadHandler 期望 content() 函数执行的特定方式所致被写入,而我编写 callr::r_bg() 的方式并不适合它。任何见解将不胜感激!

引用:

https://www.r-bloggers.com/2020/04/asynchronous-background-execution-in-shiny-using-callr/

最小示例:

library(shiny)

ui <- fluidPage(
downloadButton("download", "Download"),

numericInput("count",
NULL,
1,
step = 1),

textOutput("text")
)

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

long_download <- function(file) {
Sys.sleep(10)
write.csv(mtcars, file)
}

output$download <- downloadHandler(
filename = "data.csv",
content = function(file) {
x <- callr::r_bg(
func = long_download,
args = list(file)
)
return(x)
}
)

observeEvent(input$count, {
output$text <- renderText({
paste(input$count)
})
})

}

shinyApp(ui, server)

最佳答案

我想出了一个解决方案,并学到了以下内容:

  • 因为 downloadHandler 没有传统的 input$X,所以很难以传统方式包含 react 性。解决方法是将 UI 呈现为隐藏的 downlodButton,并由用户会看到的 actionButton 掩盖。以下过程促进了 react 性:用户点击 actionButton -> react 性更新 -> 当 react 性完成时(reactive()$is_alive() == FALSE),使用 shinyjs::click 启动 downloadHandler
  • 我没有将 callr 函数放在 downloadHandler 中,而是将文件保存在 content arg 中。范围界定似乎有些困难,因为文件需要在 content 功能环境中可用
  • 我正在使用 react 函数来跟踪后台作业(长时间运行的计算)何时完成以使用语法启动下载:reactive()$is_alive()
  • invalidateLater() 和切换全局变量 (download_once) 对于防止 react 不断激活很重要。没有它,您的浏览器将无限期地不断下载文件——这种行为很可怕,并且对您的 Shiny 应用程序用户来说就像病毒一样!
  • 请注意,设置全局变量不是 Shiny 应用程序的最佳实践(会考虑更好的实现方式)

代码解决方案:

library(shiny)
library(callr)
library(shinyjs)

ui <- fluidPage(
shinyjs::useShinyjs(),
#creating a hidden download button, since callr requires an input$,
#but downloadButton does not natively have an input$
actionButton("start", "Start Long Download", icon = icon("download")),
downloadButton("download", "Download", style = "visibility:hidden;"),

p("You can still interact with app during computation"),
numericInput("count",
NULL,
1,
step = 1),

textOutput("text"),

textOutput("did_it_work")
)

long_job <- function() {
Sys.sleep(5)
}

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

#start async task which waits 5 sec then virtually clicks download
long_run <- eventReactive(input$start, {
#r_bg by default sets env of function to .GlobalEnv
x <- callr::r_bg(
func = long_job,
supervise = TRUE
)
return(x)
})

#desired output = download of mtcars file
output$download <- downloadHandler(filename = "test.csv",
content = function(file) {
write.csv(mtcars, file)
})

#output that's meant to let user know they can still interact with app
output$text <- renderText({
paste(input$count)
})

download_once <- TRUE

#output that tracks progress of background task
check <- reactive({
invalidateLater(millis = 1000, session = session)

if (long_run()$is_alive()) {
x <- "Job running in background"
} else {
x <- "Async job in background completed"

if(isTRUE(download_once)) {
shinyjs::click("download")
download_once <<- FALSE
}
invalidateLater(millis = 1, session = session)
}
return(x)
})

output$did_it_work <- renderText({
check()
})
}

shinyApp(ui, server)

关于r - 如何在 Shiny App 的 downloadHandler 中使用 callr::r_bg,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69760709/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com