admin管理员组文章数量:1337125
I have a shiny app that uses a function to generate N number of plots (in this example 10).
Rather than use a map to create all 10 charts at the same time, below I am trying to use the futures package to render each plot one by one as they are ready.
library(shiny)
library(plotly)
library(purrr)
library(future)
library(promises)
# Enable parallel processing
plan(multisession)
# Generate 10 titles
titles <- paste0("Chart", 1:10)
# Create the list of lists
charts <- map(titles, ~ list(title = .x)) %>%
setNames(titles)
chart_func <- function(title) {
Sys.sleep(runif(1, 0.5, 2)) # Simulate some computation time
plotly::plot_ly() %>%
layout(
title = title
)
}
ui <- fluidPage(
actionButton("make_plots", "Make Plots"),
uiOutput("all_plots")
)
server <- function(input, output, session) {
# Define plot names
plot_names <- names(charts)
# Render the UI with placeholders for all plots
output$all_plots <- renderUI({
purrr::map(plot_names, ~tags$div(class = "single-plot", plotlyOutput(.x)))
})
# Generate plots asynchronously upon button click
observeEvent(input$make_plots, {
map(charts, function(chart) {
future({
chart_func(chart$title)
}, seed = TRUE) %...>% { result ->
output[[chart$title]] <- renderPlotly({
result
})
}
})
})
}
shinyApp(ui, server)
This code is close but I am getting errors and unsure what to try next. I know that method chaining is correct I just need some help with the output.
I have a shiny app that uses a function to generate N number of plots (in this example 10).
Rather than use a map to create all 10 charts at the same time, below I am trying to use the futures package to render each plot one by one as they are ready.
library(shiny)
library(plotly)
library(purrr)
library(future)
library(promises)
# Enable parallel processing
plan(multisession)
# Generate 10 titles
titles <- paste0("Chart", 1:10)
# Create the list of lists
charts <- map(titles, ~ list(title = .x)) %>%
setNames(titles)
chart_func <- function(title) {
Sys.sleep(runif(1, 0.5, 2)) # Simulate some computation time
plotly::plot_ly() %>%
layout(
title = title
)
}
ui <- fluidPage(
actionButton("make_plots", "Make Plots"),
uiOutput("all_plots")
)
server <- function(input, output, session) {
# Define plot names
plot_names <- names(charts)
# Render the UI with placeholders for all plots
output$all_plots <- renderUI({
purrr::map(plot_names, ~tags$div(class = "single-plot", plotlyOutput(.x)))
})
# Generate plots asynchronously upon button click
observeEvent(input$make_plots, {
map(charts, function(chart) {
future({
chart_func(chart$title)
}, seed = TRUE) %...>% { result ->
output[[chart$title]] <- renderPlotly({
result
})
}
})
})
}
shinyApp(ui, server)
This code is close but I am getting errors and unsure what to try next. I know that method chaining is correct I just need some help with the output.
Share Improve this question edited Nov 21, 2024 at 14:55 ismirsehregal 33.7k5 gold badges45 silver badges92 bronze badges asked Nov 19, 2024 at 22:56 Maya GansMaya Gans 811 silver badge4 bronze badges 01 Answer
Reset to default 4To unblock the session calculating the plots you'll need to wrap the future
with shiny::ExtendedTask()
. Using future
or future_promise
without ExtendedTask
will only unblock concurrent shiny sessions - please see this related but closed issue.
Please check ?shiny::ExtendedTask
:
The ExtendedTask class allows you to have an expensive operation that is started by a reactive effect, and whose (eventual) results can be accessed by a regular observer, calc, or output; but during the course of the operation, the current session is completely unblocked, allowing the user to continue using the rest of the app while the operation proceeds in the background.
Applied to your example:
library(shiny)
library(plotly)
library(purrr)
library(future)
library(promises)
library(bslib)
# Enable parallel processing
plan(multisession)
# Generate 10 titles
titles <- paste0("Chart", 1:10)
# Create the list of lists
charts <- map(titles, ~ list(title = .x)) %>%
setNames(titles)
chart_func <- function(title) {
Sys.sleep(runif(1, 0.5, 2)) # Simulate some computation time
plotly::plot_ly(type = "scatter", mode = "markers") %>%
layout(
title = title
)
}
ui <- fluidPage(
input_task_button("make_plots", "Make Plots"),
uiOutput("all_plots")
)
server <- function(input, output, session) {
# Define plot names
plot_names <- names(charts)
compute_plot <- ExtendedTask$new(function(chart) {
future_promise({
list(title = chart$title, plotly_obj = chart_func(chart$title))
}, seed = TRUE)
}) |> bind_task_button("make_plots")
# Render the UI with placeholders for all plots
output$all_plots <- renderUI({
purrr::map(plot_names, ~tags$div(class = "single-plot", plotlyOutput(.x)))
})
# Generate plots asynchronously upon button click
observeEvent(input$make_plots, {
map(charts, function(chart) {
compute_plot$invoke(chart)
})
})
observeEvent(compute_plot$result(), {
output[[compute_plot$result()$title]] <- renderPlotly({
isolate(compute_plot$result()$plotly_obj)
})
})
}
shinyApp(ui, server)
Please also check this related article.
本文标签: rHow to use futures to render each plot one by one rather than all at the same timeStack Overflow
版权声明:本文标题:r - How to use futures to render each plot one by one rather than all at the same time? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742393761a2466505.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论