s

Notebook following Part 3 Basic Callbacks of the Dash tutorial



Making the app interactive

Basic Dash Callbacks

See part 2 of the tutorial at https://dash.plotly.com/basic-callbacks

Inputs and Outputs

from dash.dependencies import Input, Output

The “inputs” and “outputs” of the application’s interface are described declaratively as the arguments of the @app.callback decorator. The “inputs” and “outputs” are properties of a particular component. For example the input is the “value” property of a component with a specified id while the “output” is the “children” property of a component with a specified id.

Reactive programming: whenever an input changes, everything that depends on that input gets automatically updated.

Whenever an input property changes, the function that the callback decorator wraps is automatically called. The new value of the input property is provided as an input argument to the function. Dash updates the property of the output component with whatever was returned by the function.

  • component_id and component_property are optional keywords

  • There is no need to specify a value for the children property of the output ( html.Div(id='my-output') in the app below) component in the layout because when the app starts up, all of the callbacks are automatically called with the initial values of the input components to populate the initial state of the output components. Any value specified would be overwritten when the app starts.

Component Id and Property

The component_id and component_property are optional and are usually excluded.

@app.callback(
    Output(component_id='my-output', component_property='children'),
    Input(component_id='my-input', component_property='value')
)

Text box

A simple text box where you just change the value of the text box and the output changes as a result

  • the Layout
# here the input is the value property of the component with id "my-input"
dcc.Input(id='my-input', value='initial value', type='text')
  • The Callback function

component_id, component_property

# callback for the simple text box
@app.callback(
    # the output is the "children" property  of the component with id "my-output"
    Output(component_id='my-output', component_property='children'),
     # here the input is the value property of the component with id "my-input"
    Input(component_id='my-input', component_property='value')
)
def update_output_div(input_value):
    return 'Output: {}'.format(input_value)

Slider and Graph

The dcc.slider here updates the dcc.Graph.

  • the layout
  html.Br(),
    html.Div([
    dcc.Graph(id='graph-with-slider'),
    dcc.Slider(
        id='year-slider',
        min=df['year'].min(),
        max=df['year'].max(),
        value=df['year'].min(),
        marks={str(year): str(year) for year in df['year'].unique()},
        step=None
        )
    ]),
  • The Callback function

The value property from the slider component (id ‘year-slider’) is the input of the app and used to update the output of the app - the ‘figure’ property of the graph component (with id ‘graph-with-slider’). Whenever the value of the slider changes, the update_figure callback function is called with this new value. The function filters the dataframe with the new value and creates a figure object which is returned to the app.

# callback for the graph with slider
@app.callback(
    # `component_id`, `component_property`
    Output('graph-with-slider', 'figure'),
    Input('year-slider', 'value'))
def update_figure(selected_year):
    filtered_df = df[df.year == selected_year]

    fig = px.scatter(filtered_df, x="gdpPercap", y="lifeExp",
                     size="pop", color="continent", hover_name="country",
                     log_x=True, size_max=55)

    fig.update_layout(transition_duration=500)

    return fig
Dash app running on http://127.0.0.1:8051/

Loading the pandas DataFrame

The pandas DataFrame is loaded at the start of the app and is in the global state of the app, therefore it can be read inside the callback functions. The dataframe is only loaded at the start and therefore the data is already in memory when the user visits or interacts with the app. It is recommended to always download or query data (or any other expensive initialisation) in the global scope and not within the scope of the callback functions.

A copy of the dataframe is created by the callback function - the original data variable should never be mutated outside of it’s scope. Otherwise one user’s session might affect the next user’s session.

layout.transition

  • layout.transistion can be used to show how a dataset evolves over time.
  • allows a chart to update from one state to the next smoothly.

Multiple Inputs and Outputs

  • A dash app can have multiple inputs.

  • Any “Output” can have multiple “Input” components.

  • More than one “Output” components can be updated at once.

  • Avoid combining outputs:

    • if the Outputs depend on some but not all of the same Inputs to avoid unnecessary updates
    • if independent computations are performed on these inputs - keep them separate allows them to be run in parallel.

The app below from https://dash.plotly.com/basic-callbacks tutorial binds several inputs to a single Output component (the figure property of the Graph component.

The Input’s are the value property of various dcc components (including dcc.Dropdown, dcc.RadioItems, dcc.Slider etc).


@app.callback(
    Output('indicator-graphic', 'figure'),
    Input('xaxis-column', 'value'),
    Input('yaxis-column', 'value'),
    Input('xaxis-type', 'value'),
    Input('yaxis-type', 'value'),
    Input('year--slider', 'value'))

The callback here executes whenever the ‘value’ property of any of these components change. The input arguments of the callback are the new or current value of each of the Input properties in the order they are specified in the callback function. As you can only update one input in a particular moment, Dash will take the current state of all the specified Input properties and passes them into the function. This means if you just move the slider or select some other value from the dropdown or select a different radio item, the moment you change one value the output will be updated.

Chaining Callbacks

Outputs and inputs can also be chained together with the output one callback function being the input of another callback function. This allows for dynamic user interfaces where one input component updates the available options of the next input component.

In the app below there are 3 callback functions. The first callback handles a user clicking on another country using a set of radio buttons. It then updates the available cities to choose from in the cities radio button. Dash waits for the value of the cities component to be updated before calling the final function to which outputs that the selected city is in the correct country. This prevents the callbacks from being updated with inconsistent state.

Dash app with State

Sometimes if you have something like a form in the app, you will only want the value of the input component to only be read when the user has finished entering all the information in the form. The first callback below is fired whenever any of the attributes described by the Input changes. The second callback illustrates using State which allows you to pass along extra values without firing the callbacks.

The callback is triggered in the above example by listening to the n_clicks property of the button component.

  • n_clicks is a property that get incremented everytime the component is clicked on and is available in every component in the dash_html_components library.

Summary of Basic Callbacks tutorial from

Declarative UI’s are customisable through reactive and functional Python callbacks. Every element attribute of the declarative components can be updated through a callback. A subset of the attributes such as the value properties of a dropdown component can be edited by the users in the user interface.


Tech used:
  • Python
  • Dash
  • HTML