dash
dash copied to clipboard
[BUG] dcc.Loading appears/disappears if used with app.long_callback
Describe your context
dash 2.0.0
dash-bootstrap-components 0.13.0
dash-core-components 2.0.0
dash-extensions 0.0.60
dash-html-components 2.0.0
dash-table 5.0.0
- OS: Windows 10
- Browser Chrome
- Version 93.0.4577.82 (Official Build) (64-bit)
Describe the bug
dcc.Loading is "jittery" i.e. appears/disappears when it has children that are called from @app.long_callback. This was initially noticed when using dbc.Spinner (dash-bootstrap-components) but same holds for dcc.Loading as mentioned in reply to the x-ref issue on DBC
X-REF https://github.com/facultyai/dash-bootstrap-components/issues/706
Expected behavior
dcc.Loading should not appear/disappear or be "jittery" when used with @app.long_callback
Code
from app import app
import dash_bootstrap_components as dbc
from dash import html
from dash.dependencies import Input, Output
from dash.exceptions import PreventUpdate
from dash.long_callback import DiskcacheLongCallbackManager
import diskcache
from time import sleep
cache = diskcache.Cache("./cache")
long_callback_manager = DiskcacheLongCallbackManager(cache)
layout = dbc.Container(
[
html.Hr(),
dbc.Row([
dbc.Col([dbc.Spinner([
html.H1('TEST', id="raw-data-store"),
],
id='main-spinner',
size='lg',
fullscreen=True,
color='primary',
fullscreen_style={'backgroundColor': 'transparent'},
spinner_style={"width": "10rem", "height": "10rem"})]),
dbc.Col([
dbc.Button("TEST BUTTON",
id='get-data-button',
color="primary",
block=True,
disabled=False,
outline=True,
size='lg',
style={'marginTop': '22px'},
),
]),
]),
],
fluid=True,
)
"""
LONG CALLBACK
"""
@app.long_callback(
output=[Output("raw-data-store", "children")],
inputs=[Input("get-data-button", "n_clicks")],
manager=long_callback_manager,
prevent_initial_call=True)
def get_data_from_sql(n_clicks):
"""
Callback to show jittery spinner behavior when used with @app.long_callback
"""
if n_clicks:
print('Button Clicked - Going to Sleep')
sleep(10)
return ['DONT BE JITTERY SPINNER']
raise PreventUpdate
Uses dbc.Spinner but same holds for dcc.Loading
Any ideas when this is will be fixed? I am also having issues with this, it seems to happen as the callback is constantly being called so the loading thinks it's a refresh each time.
I am having the same issue
@devopsquantance @mayurpande @uns1 Maybe you can try this code. I don't expect if this meets your expectation, but hopefully, it will help. i just modified from official web here
import time
import dash
from dash import html
from dash.long_callback import DiskcacheLongCallbackManager
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import diskcache
cache = diskcache.Cache("./cache")
long_callback_manager = DiskcacheLongCallbackManager(cache)
app = dash.Dash(__name__,
long_callback_manager=long_callback_manager,
external_stylesheets=[dbc.themes.DARKLY])
app.layout = html.Div(
[
html.Div(
[
html.P(id="paragraph_id", children=["Button not clicked"], style={'margin': '5px'}),
html.Div([
html.P(id="paragraph_id2", children=["Job Status : Not Yet Started"], style={'margin': '5px'}),
dbc.Spinner(id="progress_bar", spinner_style={'visibility': 'hidden'})]),
]
),
html.Button(id="button_id", children="Run Job!"),
html.Button(id="cancel_button_id", children="Cancel Running Job!"),
]
)
@app.long_callback(
output=Output("paragraph_id", "children"),
inputs=Input("button_id", "n_clicks"),
running=[
(Output("button_id", "disabled"), True, False),
(Output("cancel_button_id", "disabled"), False, True),
(
Output("paragraph_id", "style"),
{"visibility": "hidden", "margin": "5px"},
{"visibility": "visible", "margin": "5px"},
),
(Output("paragraph_id2", "children"), 'Job Status : on progress', 'Job Status : Done'),
(
Output("progress_bar", "spinner_style"),
{"visibility": "visible"},
{"visibility": "hidden"},
),
],
cancel=[Input("cancel_button_id", "n_clicks")],
progress=[Output("progress_bar", "children")],
prevent_initial_call=True
)
def callback(set_progress, n_clicks):
print(n_clicks)
time.sleep(3)
return [f"Clicked {n_clicks} times"]
if __name__ == "__main__":
app.run_server(debug=True, port=8054)
Using progress only works if you know when the operation will complete. The loading component is better for use cases where task progress cannot be measured. It would be really nice to get this fixed. In my case it isn't even jittery, I just can't even see loading component at all, the screen just flashes a couple times and the results show up once they come back.
Has anyone found a way to have a dcc.Loading or dbc.Spinner component work with a long_callback? I have an app that has a long running background process (approximately 1.5 min) and it would be very beneficial to have a loading spinner running on the page while this happens. Almost crucial really.
I am having the same issue as @lucasmlofaro where I cannot even get the spinner to activate at all. I have another spinner on the page for a much faster process that works just fine. But I cannot get a dcc.loading or dbc.spinner component to work with the long_callback.
Not sure if this is the solution you are looking for, but I have discovered a method that works using the dbc.Spinner in conjunction with the running keyword argument of the long_callback.
First, create a div where you want the spinner to appear, give it a unique id name and set its children equal to None. For me, I used a dbc.Row(dbc.Col()) instead of a div, but it should work the same. Then you will need to set the running keyword argument of the long_callback to output a dbc.Spinner. The following code is currently working for me. I have removed a lot of code, so ignore the inputs, ouputs and lack of layout components. Pay attention to the running kwarg.
app.layout = dbc.Container(dbc.Row(dbc.Col(id='fs_spinner', children=None)))
@app.long_callback(
output=(
Output("full_search_predictions", "data"),
Output("full_results_query", "data"),
),
inputs=[
Input("submit_button", "n_clicks"),
Input("search_query", "value"),
],
running=[
(Output('fs_spinner', 'children'), dbc.Spinner(size='md'), None)
],
interval=20000,
prevent_initial_call=True,
)
Here is what is happening. When the the long_callback begins, it returns a dbc.Spinner() to the children component of the fs_spinner. Once the callback is complete, it then returns None to the children component of the fs_spinner, which removes the spinner from the screen.
Hope this helps!