I have a question regarding R shiny and more especially about the way to improve performance of my shiny app. I'm using some SQL queries that take quite long to run as well as some plot which take time to show up. I know that it is possible to use future
and promises
but I can't figure out how to use them in a reactive expressions.
I show you below a really simple example:
library(shiny)
library(ggplot2)
library(plotly)
library(dplyr)
ui <- fluidPage(
selectInput("id1", "Choose:", choices = unique(as.character(iris$Species))),
dataTableOutput("my_data"),
plotlyOutput("my_plot")
)
server <- function(input, output, session) {
output$my_data <- renderDataTable({
iris %>% filter(Species == input$id1)
})
data_to_plot <- reactive({
Sys.sleep(10)
res <- ggplot(iris %>% filter(Species == input$id1), aes(x=Sepal.Length)) + geom_histogram()
return(res)
})
output$my_plot <- renderPlotly({
ggplotly(data_to_plot())
})
}
shinyApp(ui, server)
In this case, we can see that the app waits for the plot part to end computation before showing the whole app. However I'd like the datatable to show even if the part with the plot hasn't finish its computation.
Thanks a lot in advance for your help !
Edit: by now shiny::ExtendedTask is available to address this issue. Please check my related answer here.
Original answer:
Officially shiny doesn't support intra-session non-blocking promises.
Please read this carefully.
Here is how to apply the above workaround to your code:
library(shiny)
library(ggplot2)
library(plotly)
library(dplyr)
library(promises)
library(future)
plan(multisession)
ui <- fluidPage(
selectInput("id1", "Choose:", choices = unique(as.character(iris$Species))),
dataTableOutput("my_data"),
plotlyOutput("my_plot")
)
server <- function(input, output, session) {
output$my_data <- renderDataTable({
iris %>% filter(Species == input$id1)
})
data_to_plot <- reactiveVal()
observe({
# see: https://cran.r-project.org/web/packages/promises/vignettes/shiny.html
# Shiny-specific caveats and limitations
idVar <- input$id1
# see https://github.com/rstudio/promises/issues/23#issuecomment-386687705
future_promise({
Sys.sleep(10)
ggplot(iris %>% filter(Species == idVar), aes(x=Sepal.Length)) + geom_histogram()
}) %...>%
data_to_plot() %...!% # Assign to data
(function(e) {
data(NULL)
warning(e)
session$close()
}) # error handling
# Hide the async operation from Shiny by not having the promise be
# the last expression.
NULL
})
output$my_plot <- renderPlotly({
req(data_to_plot())
ggplotly(data_to_plot())
})
}
shinyApp(ui, server)