Hi,
I wanted to share an effective solution to showing a spinner (or similar loading animation) while the app is starting up, and then removing it.
This is relevant for an app with lots of callbacks causing noticeable start-up time, where no single component or callback is the culprit.
TL;DR:
- Add a new div to the app, alongside the main layout div, which has the loading spinner component as its only child.
- Use a callback that takes as Input the main layout div’s loading state, and outputs None to the loading spinner div’s children.
Also read the State of the loading spinner div’s children to raise PreventUpdate if the spinner has already been removed.
example
This example uses the very cool new dash-loading-spinners library:
layout:
from dash import html
import dash_loading_spinners
app.layout = html.Div(
children=[
html.Div(
id="div-loading",
children=[
dash_loading_spinners.Pacman(
fullscreen=True,
id="loading-whole-app"
)
]
),
html.Div(
className="div-app",
id="div-app",
children = [ # app layout here
]
)
]
)
callback:
@app.callback(
Output("div-loading", "children"),
[
Input("div-app", "loading_state")
],
[
State("div-loading", "children"),
]
)
def hide_loading_after_startup(
loading_state,
children
):
if children:
print("remove loading spinner!")
return None
print("spinner already gone!")
raise PreventUpdate
More detail:
There are some excellent component (libraries) out there for showing a spinner:
- Loading | Dash for Python Documentation | Plotly
- Spinner - dbc docs
- dash-loading-spinners
- Stratodem Material UI
And two main ways to use them:
- Set up a spinner without children components, and use a callback to change its behavior or remove it
- Pass components to the spinner as children and the spinner will show while the child’s loading state shows it is loading.
The problems I encountered were mainly:
- How to monitor the whole app
- How to get a smooth loading spinner animation that doesn’t flicker as loading state switches back and forth during startup?
- How to get rid of the spinner after initial load (or calibrate it so it doesn’t fire every time a callback runs)
When using approach 2 of passing children components, dcc.Loading was the only component to show a smooth continuous animation, but doesn’t offer any obvious ways to calibrate or remove the spinner. The other libraries show a flickering spinner on startup, and have more (but limited) options for calibrating the spinner after start up (e.g. adding a delay to avoid triggering spinner on every callback).
Depending on the app’s CSS, it may be necessary to add some styling to make sure that the spinner and its backdrop (if desired) cover other components, e.g. through the z-index
CSS property.
The solution here worked well for me, hope others can use it.