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.
The magic behind this template is provided by two simple functions from the shinyjs
library:
show("content")
hide("content")
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:
This template relies on three steps:
In order to use shinyjs
you must do the following:
library(shinyjs)
in both the ui.R and server.R filesuseShinyjs()
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.
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
})
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:
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;
}