Search code examples
rbslibshinycssloaders

How to use shinycssloaders withSpinner with a plot output in a bslib card?


I would like to use a spinner with a plotlyoutput and I would also like for that plot to fill the container, but when I use a spinner, the plot does not resize. I've spent a lot of time trying to figure it out with the documentation on the bslib package https://rstudio.github.io/bslib/reference/as_fill_carrier.html but I'm missing something. Here is an example of the behavior. The plot will resize when there is no spinner. Any ideas?

library(ggplot2)
library(shiny)
library(bslib)
library(shinycssloaders)
data(penguins, package = "palmerpenguins")

ui <- page_sidebar(
  title = "Penguins dashboard",
  sidebar = sidebar(
    title = "Histogram controls",
    varSelectInput(
      "var", "Select variable",
      dplyr::select_if(penguins, is.numeric)
    ),
    numericInput("bins", "Number of bins", 30)
  ),
  card(max_height = 200,
       full_screen = T,
    card_header("Histogram"),
    plotOutput("p") |> withSpinner()
  )
)

server <- function(input, output) {
  output$p <- renderPlot({
    ggplot(penguins) +
      geom_histogram(aes(!!input$var), bins = input$bins) +
      theme_bw(base_size = 20)
  })
}

shinyApp(ui, server)

Solution

  • The issue is that withSpinner() wraps the output in a div. For the plots potential to grow/shrink to fit their container to be activated, the immediate parent needs to be a fillable container. See https://rstudio.github.io/bslib/articles/filling/index.html

    In this case its not quite as simple as piping bslib::as_fill_carrier() onto the output because of the structure that withSpinner returns, but it is possible to target the correct element.

    library(ggplot2)
    library(shiny)
    library(bslib)
    library(shinycssloaders)
    data(penguins, package = "palmerpenguins")
    
    ui <- page_sidebar(
      title = "Penguins dashboard",
      sidebar = sidebar(
        title = "Histogram controls",
        varSelectInput(
          "var", "Select variable",
          dplyr::select_if(penguins, is.numeric)
        ),
        numericInput("bins", "Number of bins", 30)
      ),
      card(max_height = 200,
           full_screen = T,
           card_header("Histogram"),
           plotOutput("p") |> withSpinner() |> (\(x) {
             x[[4]] <- x[[4]] |> bslib::as_fill_carrier() 
             x})()
           
      )
    )
    
    server <- function(input, output) {
      output$p <- renderPlot({
        ggplot(penguins) +
          geom_histogram(aes(!!input$var), bins = input$bins) +
          theme_bw(base_size = 20)
      })
    }
    
    shinyApp(ui, server)