Is there a way to only update on a button press for apps where updates are slow?

Is there a nice way to do this now?

I think I could associate a callback with an html button or something, but wondering if I’m missing something.

Thanks,
-Pete

3 Likes

Update - See the answer below. The n_clicks property has been added to HTML components


There are a couple of abstractions that will help you out here and a couple more additions that will be made in the near future for this exact use case. Here are your options:

1 - There are two different dependencies besides dash.dependencies.Input and dash.dependencies.Output: dash.dependencies.State and dash.dependencies.Event. Event just fires the callback, but it doesn’t include any values. It can be used for “click” events like on a button. State is just like an input except that it doesn’t fire the callback. You can combine State and Event in your case to populate inputs without firing the callbacks until the user clicks on a button through an Event. Event may be phased out in the future. For now, use the `n_clicks_ property.

Here’s a quick example: https://gist.github.com/chriddyp/e546a2a2c05df29c868e4cef57fb2105. In this example, the Dropdowns don’t fire when they change, they only fire when the Button is clicked. You can swap out the Dropdown with an Input or any other component instead.

2 - I’m planning on adding a n_clicks parameter to every html element that increments itself when a user clicks on the item. This will allow you to use a html.Button as a dash.dependencies.Input like:

@app.callback(Output('my-graph', 'figure'), [
    dash.dependencies.Input('my-input', 'value'),
    dash.dependencies.Input('my-button', 'n_clicks')])
def update_figure(input_value, number_of_times_button_was_clicked):
    [...]

When this is implemented, I’ll probably phase out the Event concept. The Event concept doesn’t fit well into the reactive paradigm, and will make things like ‘undo/redo’ and ‘saved views’ more difficult or impossible to implement. You are free to use Event in the meantime, and I’ll keep this thread updated when changes are made.

3 Likes

@PeterS thanks for asking the questions and @chriddyp many many thanks for sharing this solutions.

one fix: import plotly.graph_objs as go is missing from the gist.

1 Like

This will allow us to have multiple button drive one output!
+1 for dash.dependencies.Input('my-button', 'n_clicks')

1 Like

My app queries a random selection of datasets from an API. I just need a button to trigger a new set of random datasets to be queried and loaded into the app, while it is running. Is this kind of usage going to be covered in your future updates? I am not too familiar with the reactive paradigm, but from your description it sounds like this is the kind of functionality you are planning to remove? I would think that having a simple button to trigger an arbitrary action or callback function in the app would be a basic use case.

Yes it will. It will just have a slightly different syntax.

n_clicks has been shipped with the latest release of dash-html-components. Please refrain from using Events now!

Here is a simple example:

import dash
from dash.dependencies import Input, Output, State
import dash_html_components as html
import dash_core_components as dcc

app = dash.Dash()

app.layout = html.Div([
    html.Button('Click Me', id='button'),
    html.H3(id='button-clicks'),

    html.Hr(),

    html.Label('Input 1'),
    dcc.Input(id='input-1'),

    html.Label('Input 2'),
    dcc.Input(id='input-2'),

    html.Label('Slider 1'),
    dcc.Slider(id='slider-1'),

    html.Button(id='button-2'),

    html.Div(id='output')
])

@app.callback(
    Output('button-clicks', 'children'),
    [Input('button', 'n_clicks')])
def clicks(n_clicks):
    return 'Button has been clicked {} times'.format(n_clicks)

@app.callback(
    Output('output', 'children'),
    [Input('button-2', 'n_clicks')],
    state=[State('input-1', 'value'),
     State('input-2', 'value'),
     State('slider-1', 'value')])
def compute(n_clicks, input1, input2, slider1):
    return 'A computation based off of {}, {}, and {}'.format(
        input1, input2, slider1
    )

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

2 Likes

what if the input value is from a selected dropdown list on the same HTML page and not from dash?