Hi @jlfsjunior,
I have the same problem with my code.
To replicate that problem:
- I picked code from the official documentation on page Long Callbacks | Dash for Python Documentation | Plotly, section Example 5: Progress Bar Chart Graph.
- I extended the code to run longer (total=1000)
- Set Network Throttling on Google my Chrome to “Slow 3G”
Using PyCharm I am able to set a breakpoint to the line following Why am I here?
Because my callback was triggered by _long_callback_interval_1.n_intervals component, calculations restarts. And this is exactly what I am trying to avoid.
Note - I tried to raise PreventUpdate - after detecting this unexpected callback - that didn’t help
Thanks in advance
Here is my code:
- requirements.txt
dash==2.2.0
dash_bootstrap_components==1.0.3
dash-core-components==2.0.0
dash-html-components==2.0.0
dash-table==5.0.0
diskcache==5.4.0
dash_tabulator==0.4.2
...
-
I am using Python 3.9
-
Output in the console
2022-03-10 21:14:20,758 INFO dash.py:2030 - Dash is running on http://127.0.0.1:8050/
* Serving Flask app 'sample_long_callback' (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: on
Optimisation.Calculate. 1 - Button Click callback.
Optimisation.Calculate. 2 - Triggers: {'prop_id': 'button_id.n_clicks', 'value': 1}
Optimisation.Calculate. 3 - Button clicked 1 times
Optimisation.Calculate. 1 - Button Click callback.
Optimisation.Calculate. 2 - Triggers: {'prop_id': '_long_callback_interval_1.n_intervals', 'value': 130}
Optimisation.Calculate. 3 - Button clicked 1 times
- Code
import time
import dash
from dash import html, dcc
from dash.long_callback import DiskcacheLongCallbackManager
from dash.dependencies import Input, Output
import plotly.graph_objects as go
import diskcache
cache = diskcache.Cache("./cache")
long_callback_manager = DiskcacheLongCallbackManager(cache)
def make_progress_graph(progress, total):
progress_graph = (
go.Figure(data=[go.Bar(x=[progress])])
.update_xaxes(range=[0, total])
.update_yaxes(
showticklabels=False,
)
.update_layout(height=100, margin=dict(t=20, b=40))
)
return progress_graph
app = dash.Dash(__name__, long_callback_manager=long_callback_manager)
app.layout = html.Div(
[
html.Div(
[
html.P(id="paragraph_id", children=["Button not clicked"]),
dcc.Graph(id="progress_bar_graph", figure=make_progress_graph(0, 10)),
]
),
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"},
{"visibility": "visible"},
),
(
Output("progress_bar_graph", "style"),
{"visibility": "visible"},
{"visibility": "hidden"},
),
],
cancel=[Input("cancel_button_id", "n_clicks")],
progress=Output("progress_bar_graph", "figure"),
progress_default=make_progress_graph(0, 10),
interval=1000,
prevent_initial_call=True,
)
def callback(set_progress, n_clicks):
print("Optimisation.Calculate. 1 - Button Click callback.")
ctx = dash.callback_context
print(f"Optimisation.Calculate. 2 - Triggers: {ctx.triggered[0]}")
print(f"Optimisation.Calculate. 3 - Button clicked {n_clicks} times")
if str(ctx.triggered[0]["prop_id"]).startswith("_long_callback_interval"):
# Why am I here ???
pass
total = 1000
for i in range(total):
time.sleep(0.1)
set_progress(make_progress_graph(i, 1000))
return [f"Clicked {n_clicks} times"]
if __name__ == "__main__":
app.run_server(debug=True)