'Using withSpinner with an interactive uiOutput in R Shiny

I have recently written a Shiny app that takes user data input, does some analysis on it, and then displays the results, including graphs. These graphs take a while to render, so I am using withSpinner to inform the users that Shiny is busy and to be patient and wait for the graphs to appear. The graphs are displayed within boxes that have titles informing the users what the graphs show.

What gets displayed to the users depends on the data they provide to the app (how many items of data are provided in their input file) and also which options they choose from within the app (using checkboxes).

The withSpinner function works well for the graphs when wrapped around plotOutput and called from within ui (see line 38 of the example code below).

However, to use this approach for all graphs would require me to know how many items of data the users are likely to provide and then want to view. I would like to just automatically produce a graph, with a spinner, for each data item, without knowing how many there are in advance.

Placing withSpinner within the server doesn’t work at all (lines 58-65), which makes sense. However, if I use it in the ui around the uiOutput object for all of the boxes and graphs (line 29), the spinner only shows until the boxes are rendered – the graphs then appear about a minute later…

Please can you help me to work out how to get the spinners to show until the graphs are rendered? Thank you for any help you can give!

library(shiny)
library(shinydashboard)
library(shinyjs)
library(shinycssloaders)
library(survival)

ui <- dashboardPage(
  skin = "blue",
  dashboardHeader(title = "My App"),
  dashboardSidebar(
    sidebarMenu(
      useShinyjs(),
      id = "tabs",
      menuItem("User Choice", tabName = "uChoice", icon = icon("sliders-h"))
    )
  ),
  dashboardBody(
    id = "dashboardBody",
    tabItems(
      tabItem(
        tabName = "uChoice",
        h2("You have a choice"),
        # Check boxes to select choice
        fluidRow(
          uiOutput("userChoiceCheckbox")
        ),
        fluidRow(
          # Only show the data graphs that the user has chosen to look at
          withSpinner(uiOutput('chosenGraphs'), type=4)
          # this spinner only shows until the box containing the graph is rendered
        ),
        fluidRow(
          # Always show lung graph
          box(
            title = paste("Here's the lung graph"),
            width = 12,
            height="50px",
            withSpinner(plotOutput("lungGraph"), type=4)
            # This spinner shows until the graph is plotted
          )   
        )
      )
    )
  )
)

server <- function(input, output, session) {
  output$userChoiceCheckbox <- renderUI({
      column(6, checkboxGroupInput(inputId = "choices", label = "Which graph(s) would you like to view?", choices = c("Lung", "PBC")))
  })
  
  output$chosenGraphs <- renderUI({
    lapply(input$choices, function(x) {
      box(
        title = paste("Graph for", x,"cancer"),
        width = 12,
        renderPlot({
          withSpinner( 
            # This spinner doesn't seem to work at all
            plotOutput({
              Sys.sleep(2)
              plot(survfit(Surv(time, status) ~ 1, data = eval(as.symbol(tolower(x)))), 
                   xlab = "Days", 
                   ylab = "Overall survival probability")
            })
          )
        })
      )
    })
  })
  output$lungGraph <- renderPlot(
    plot(survfit(Surv(time, status) ~ 1, data = lung), 
         xlab = "Days", 
         ylab = "Overall survival probability")
    )
}

shinyApp(ui, server)


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source