đź“Ł Loading states and Loading component

Hello Dash community :wave:

Update! This is now released in 0.39.0: đź“Ł Dash 0.39.0 released

We’ve released a new version of the previously announced Loading component (in this thread here and we would love your feedback! In this new version, you have two ways of displaying a spinner when a component is busy loading. The first option is the Loading component in dash_core_components, which acts as a wrapper that looks at its children components to see if any are loading. Here’s a small example:

# -*- coding: utf-8 -*-
import dash
import dash_html_components as html
import dash_core_components as dcc
import plotly.graph_objs as go
import time

from dash.dependencies import Input, Output, State

app = dash.Dash(__name__)

app.scripts.config.serve_locally = True

app.layout = html.Div(
    children=[
        dcc.Loading(id="loading-1", children=[html.Div(id="output-1")], type="default"),
        dcc.Input(id="input-1", value='Input triggers local spinner'),
        html.Div(
            [
                dcc.Loading(
                    id="loading-2",
                    children=[html.Div([html.Div(id="output-2")])],
                    type="circle",
                ),
                dcc.Input(id="input-2", value='Input triggers nested spinner'),
            ]
        ),
    ],
)

@app.callback(Output("output-1", "children"), [Input("input-1", "value")])
def input_triggers_spinner(value):
    time.sleep(1)
    return value


@app.callback(Output("output-2", "children"), [Input("input-2", "value")])
def input_triggers_nested(value):
    time.sleep(1)
    return value


if __name__ == "__main__":
    app.run_server(debug=False)

The other way is to target a new HTML data attribute that we now set on all of our components (including dash_html_components). You won’t need to use the Loading component this way, but you would need to supply your own CSS. Your layout could look like this:

# -*- coding: utf-8 -*-
import dash
import dash_html_components as html
import dash_core_components as dcc
import plotly.graph_objs as go
import time

from dash.dependencies import Input, Output, State

app = dash.Dash(__name__)

app.scripts.config.serve_locally = True

app.layout = html.Div(
    children=[
        html.Div(id="output-1"),
        dcc.Input(id="input-1", value="Input triggers local spinner"),
        html.Div(
            [
                html.Div(id="output-2"),
                dcc.Input(id="input-2", value="Input triggers nested spinner"),
            ]
        ),
    ]
)


@app.callback(Output("output-1", "children"), [Input("input-1", "value")])
def input_triggers_spinner(value):
    time.sleep(1)
    return value


@app.callback(Output("output-2", "children"), [Input("input-2", "value")])
def input_triggers_nested(value):
    time.sleep(1)
    return value


if __name__ == "__main__":
    app.run_server(debug=False)

And you can target the new data-dash-is-loading["true"] data attribute in a custom CSS file (here are the docs on how to do that ) like so:

*[data-dash-is-loading="true"]{
    visibility: hidden;
}
*[data-dash-is-loading="true"]::before{
    content: "Loading...";
    display: inline-block;
    color: magenta;
    visibility: visible;
}

You can start using this with Dash 0.39.0:

pip install dash==0.39.0

As always, your feedback is greatly appreciated!

10 Likes

I’m a big fan of this new dcc.Loading!

Coming to Dash as mostly a Python back-end developer any time I can prototype something and not worry about CSS until later it really reduces the cognitive burden of starting.

Quick question though, once comfortable with it will I be able to provide custom styles of the loading via the props of the dcc.Loading? I suspect not but just curious.

Thanks! You could definitely style the spinners the way you want, since they have CSS classes on them - so targeting those in a CSS file would override the default styles. Definitely something we’ll add to the documentation. In the future, it would also definitely be cool if a user could supply their own spinners to be used by the Loading component!

2 Likes

Hi there seems to be a problem installing the dash==0.37.0rc2 due to a missing dependency:

Could not find a version that satisfies the requirement dash-core-components==0.44.0rc3

Would gladly try this out if this gets resolved. Thanks.

@c_f Seems like the latest dash-core-components release candidate was released under 0.43.0rc3, not 0.44.0rc3. Uploaded the correct version of dcc. There’s another problem in the renderer that will prevent this RC to work when serve_locally=true is not set.

Can you try again? Sorry for the inconvenience!

Thanks I’ll try again soon. I usually have serve_locally=true set.

Sorry about that - the correct version is uploaded now as @Marc-Andre mentioned (thanks!). The other problem mentioned above wasn’t actually a problem - it should all work as expected, regardless of serve_locally=true.

I’m on Windows and I’ve installed:

dash==0.37.0rc2
dash-core-components==0.43.0rc3
dash-html-components==0.14.0rc21
dash-renderer==0.18.0rc4

This installed plotly 3.6.1

However, when I try to run the example, I get a file not found error:

FileNotFoundError: [WinError 2] The system cannot find the file specified 'C:\\Users\\....\\lib\\site-packages\\dash_core_components\\plotly-1.44.1.min.js'

Do I still not have the correct versions installed or am I running into something else?

(I’m using virtualenv to create my virtual environment.)

Nevermind. I re-read the thread and now see that I misunderstood the above post. Loading states requires dash-core-components==0.44.0rc3 .

So for anyone new to this, the required components are:

dash==0.37.0rc2
dash_html_components==0.14.0rc21
dash-core-components==0.44.0rc3

Very nice job with this! It is enhancements like this that give Dash a huge edge over some of the other vendors like Tableau, Qlik, PowerBI, etc.

2 Likes

Hi there.

Great job!

Now, how can we create new “loading components” that would be render inside the dcc.Loading wrapper? I don’t mean just styling them with css, but display our own defined html, or eventually even react/js in case we want to. The react option is not so important for us, but the html one it is.

Hello!
I am trying to use the Loading components while a graph is updating this way:

html.Div(children=[dcc.Loading(id='loading-1',
                                           children=html.Div(dcc.Graph(id=dcc_ids['cumulative_performance']),
                                                             className='chart_div'),
                                           type='spinner')]),

With the corresponding callback being:

@dash_app.callback(
    Output('cumulative_performance', "children"),
    [Input('param1', 'value'),
     Input('param2', 'value'),
     Input('param3', 'value'),
     ])
def my_function(param1, param2, param3):

I do see the spinner and that is so great but my chart never displays… I am probably doing something wrong…

Could you assist please??

NB: I am a huge Dash fan and take the opportunity to thank you for this framework !!

Cheers

Hi!

It is pretty! Thank you!

Is there a way to use loading_state property as callback input?
Problem:
I have a custom spinner (similar to the one here. I would like to show it depending on loading_state.is_loading and the state of the background task at the same time.

Cheers

2 Likes

Loading component does not render on first load if using dcc.Location.
See https://github.com/plotly/dash-core-components/issues/488

Hi all, trying to use the loading component for the first time, but I haven’t quite got it working yet. my layout and callback are as follows:

dcc.Loading(
    id="loading-1",
    children=[html.Div([dcc.Graph(id='themes-plot',
                                  figure = data_plots.empty_plot())
                                ],
                                style ={'width': '84%'}
                                )],
    type="default"),


@app.callback(Output("themes-plot", "children"), [Input('submit-button', "value")])
def input_triggers_spinner(value):
    time.sleep(1)
    return value

When you click the submit-button data a callback runs to filter and process the data which is then displayed in the themes-plot graph. Initially the graph displays and empty plot until updated by the callback, which takes a few seconds.

The above appears to display everything correctly and the graph updates correctly, but no spinner appears.

Could this be related to the fact that there is already a call back outputting to the themes-plot component?

Thanks!

1 Like

Hi,

After trying again and re-writing the code it finally works for me:
The div below includes the chart and a parameter for the chart.
The other parameters are inherited from a tab component.

html.Div([
            dcc.Loading(id='loading-1',
                        children=[html.Div(dcc.Graph(id='chart_id'),
                                           className='chart_div') #custom css class
                                  ],
                        type='spinner'),
            dcc.RadioItems(
                options=[
                    {'label': 'l1', 'value': 'v1'},
                    {'label': 'l2', 'value': 'v2'},
                    {'label': 'l3', 'value': 'v3'},
                    {'label': 'l4', 'value': 'v4'},
                    {'label': 'l5', 'value': 'v5'},
                    {'label': 'l6', 'value': 'v6'},
                    {'label': 'l7', 'value': 'v7'}],
                value='v7',
                id='input3',
            ),
        ],
            className='seven columns',
            style={"padding-left": '20'}
        ),], 
           className='row', 
)

@dash_app.callback(
Output('chart_id', "figure"),
[Input('input1', 'value'),
 Input('input2', 'value'),
 Input('input3', 'value'),
 ])
 def func(input1, input2, input3):

Hope this will help you,

Cheers

2 Likes

Hi,

Really like the feature! Awesome stuff. I was wondering if you could help me with an issue I’m having.

I’m currently working on a multi-page app. Here’s an example of the index page:

index.py

html.Div(
            [
                dcc.Location(id='url', refresh=False),
                html.Div(id="navigation_bar"),
                dcc.Dropdown(id = "options"), # users pick options which edit the query
                dcc.Loading(id="loading",children=[html.Div(id='page-content')])
            ]
        )

@app.callback(
    Output('page-content', 'children'),
    [Input('url', 'pathname')]
def update_page(pathname):
     if pathname == "dashboard":
            return dashboard_layout
     else:
            display another layout

The page-content div sets a new layout every time the url changes. Each layout has its own dropdowns, graphs, tabs, etc which are populated by data from a SQL query. The query is based on the option a user picks in the options dropdown. The data from the query is then stored in a flask-cache on Redis so that all the pages can access it.

When the layout first loads, it takes a long time because the query is expensive. Subsequent steps are very quick because the queried data comes from a cache.

My issue right now is that the spinner appears for inexpensive processes (like changing a tab or clicking a dropdown) after the first data load. I would prefer if the spinner displayed only on the first time the query is run as stored in the cache.

Is there a way for me to set a “spinner on first load” option? Or do you see a better way for me to do this?

Please let me know.
Thanks!

2 Likes

Hi @mdylan2

you could use the decorator @app.first_callback that is alread available above your expensive first callbacks.

Cheers,

1 Like

Hi @PNhd

I’m a little unsure what you mean by @app.first_callback. Is that a Dash function?

1 Like

@PNhd @mdylan2
Im facing the same issue… I want the load component only to be triggered by one input, and not whenever a change is being made on the page.

The thing is in the documentation (https://dash.plot.ly/dash-core-components/loading_component), load 1 is triggered by input one, and not both inputs… thats what id expect…

The question is, is it meant to be triggered whenever a change is made or is this some sort of bug?

1 Like