Fork me on GitHub

Often a Shiny app will contain a visualisation or other element that takes a long time to load. It’s useful to provide a visual aid to your users that content is being loaded (or something else is being done). This template provides a bare bones Shiny app with pulsating text that reads “loading data…” while a chart is being generated.

This template was uses the shinyjs library and an StackOverflow Answer both written by deanattali.com.

shinyJS

The magic behind this template is provided by two simple functions from the shinyjs library:

The shinyjs library is thoroughly documented at http://deanattali.com/shinyjs/, it provides many commonly used JavaScript operations directly from R that you may easily use in your Shiny applications. Many of these should be considered “advanced” for most Shiny users, as the main benefit of Shiny is the ability to make interactive content directly from R. However, it’s useful to know you can do the following:

How this template works

This template relies on three steps:

useShinyjs()

In order to use shinyjs you must do the following:

  • Include library(shinyjs) in both the ui.R and server.R files
  • Include useShinyjs() within the your UI, it should appear in the very first fluidPage in your app:
## ui.R
shinyUI(
  navbarPage(
  "Pulsating loading data",
  tabPanel(
    "Visualisation",
    fluidPage(
      useShinyjs(),
      includeCSS("www/animate.min.css"),

There is slight finesse required if using shinyjs outside of what might be considered a “traditional” two-file Shiny app. Consult the documentation here if necessary.

show/hide(“loading-content”)

When the server function calls renderPlot to generate output$chart the shinyjs function show is called. This includes when the app is first loaded and when the actionButton(inputID = "reload") button is pressed, as it results in input$reload being updated and therefore renderPlot is re-evaluated.

## server.R
output$chart <- renderPlot({
      
      input$reload # trigger a reload
      
      show("loading-content") # make the loading pane appear
      
      ...
})

This triggers the div element in ui.R with the corresponding id to be displayed, which in this instance is h2 formatted text.

fluidPage(...,
          div(id = "loading-content",
              class = "loading-content",
              h2(class = "animated infinite pulse", "Loading data...")),
          plotOutput("chart", height = "200px"),
          ...)

The loading pane in this app is designed to then cover the entirety of the screen, see the next section for details. Note that the empty space shown in the app is due to the height argument of plotOutput.

When the assignment of g has finished, the hide function is triggered; this hides the div element with the corresponding id, making our loading pane invisible. After the loading pane has been hidden, it’s necessary to call g so that the plot is returned by output$chart

output$chart <- renderPlot({
  ...
  g <- ggplot(iris, aes(x = Sepal.Width, y = Sepal.Length)) + geom_point()
  
  hide("loading-content") # make the loading pane disappear
  
  g # display the output after hiding it
  
})

animate.min.css and loading-content.css

CSS should be considered the “design language” of the web - it’s used for laying out content in grids, styling text, images and much more. It is not necessary to understand CSS to use this template, but if you’re interested there’s a great Code Academy course on CSS.

This template uses the excellent CSS library animate.css to provide a pulsating effect for the text in the loading pane. There are many choices about how to include CSS in Shiny apps, one of the key decisions comes down to the following:

  • Should I use a remote CSS file, via a Content Delivery Network (CDN)?
  • Should I use a local copy of the CSS file?

In these templates we almost always use a local copy, as sometimes the developers require Shiny apps to work without an internet connection. We’re therefore able to include CSS very easily with includeCSS

## ui.R
shinyUI(
  fluidPage(
    useShinyjs(),
    includeCSS("www/animate.min.css"),
    ...
)

The pulsating effect is added to the loading pane by setting the class of the text "animated infinite pulse"

## ui.R
h2(class = "animated infinite pulse", "Loading data..."))

Finally, the styling for the loading pane is provided by “loading-content.css” - any element with class="loading-content" has the following style applied:

.loading-content {
position: absolute;
background: #FFFFFF;
opacity: 0.9;
z-index: 100;
left: 0;
right: 0;
height: 100%;
text-align: center;
color: #000000;
}