✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
🧬 Learn how to build RNA-Seq data apps with Python & Dash. Register for the May 20 Webinar!

Update on both interval and Button? (or just make callback do nothing)

Hey everyone, sorry if this is apparent however I can’t seem to find a good way to make this work:

import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output
from dash.exceptions import PreventUpdate
import time

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
    html.Button('Click here to see the content', id='show-secret'),
    html.Div(id='body-div'),
    dcc.Interval(
        id='interval-component',
        interval=1 * 1000,
        n_intervals=0
    )
])

def clicker(n_clicks):
    time.sleep(2)
    return "Clicked {} times".format(n_clicks)

@app.callback(
    Output(component_id='body-div', component_property='children'),
    [dash.dependencies.Input(component_id='show-secret', component_property='n_clicks'),
     dash.dependencies.Input('interval-component', 'n_intervals')]
)
def update_output(n_clicks, n_intervals):
    ctx = dash.callback_context
    print(ctx.triggered[0])

    # Update by action
    if ctx.triggered[0]['prop_id'] == 'show-secret.n_clicks':
        return clicker(n_clicks)

    # Update by interval
    if ctx.triggered[0]['prop_id'] == 'interval-component.n_intervals':
        raise PreventUpdate

if __name__ == '__main__':
    app.run_server(debug=True)

It seems like no matter what I try, either the “no_update” or “PreventUpdate” solutions, dash is still being “updated” to a point where it “blocks” the update from the button.

The only solution I have working right now is having the callback return a variable every time and just having the button “update” the variable, but it seems a bit inefficient.

Just wondering if anyone has a better way around this, thanks!

Could you elaborate on your usecase? As i read your code, when you click the button, the sleep statement is executed synchronous, on the gui thread, i.e. your app will then freeze for two seconds (unless you run with mutiple threads). Is that intended?

hey! its running on multiple threads. Basically I have a graph component that takes awhile to update since it uses data from an api so the “sleep” simulates that time being waited.

For some reason, even if I do “no update” the div is still being “updated” when I go into devtools with chrome.

If I could somehow just completely abort the callback that would be great, seems no matter what I try though the Div is still being messed with on the frontend side of things.

@robswc - I would generally not recommended running long calculations in Dash directly. I would be better to,

  • Launch the calculation asynchronously, e.g. with Celery, on the button click
  • Poll for updates using the interval component and update the graph with the data arrives

I have also tried solutions similar to what you are talking about, i.e. chaning callback in just-the-right-way to get the frontend to behave, but it is a pain (and the behaviour might change depending on the environment, e.g. if you run threaded or not). With the above solution, the behaviour is consistent and predictable; it will work every time.