Black Lives Matter. Please consider donating to Black Girls Code today.
Dash HoloViews is now available! Check out the docs.

Dash return None does not trigger callback function

I’ve put together a simple Dash application that contains a few Dropdown components and a callback function update_graph() that updates a bar graph ( id="plot-graph" ). For the purpose of this question, the resulting graph is not of importance, merely the callback function. Here is my sample application:

import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import pandas as pd, os, re, sys
import numpy as np

print(dcc.__version__)

cluster_options = ['Cluster1','Cluster2','Cluster3']

group_options = ['Group1','Group2','Group3','Group4']

category_options = ['Category1','Category2','Category3','Category4']

app = dash.Dash()

app.layout = html.Div([

    html.H2("Viewer"),
    html.Div(
        [
            dcc.Dropdown(
                id="Cluster",
                options=[{
                    'label': i,
                    'value': i
                } for i in cluster_options],
                placeholder='Select a cluster...'),
        ],
        style={'width': '15%',
               'display': 'inline-block'}),
    html.Div(
        [
            dcc.Dropdown(
                id="Group",
                options=[{
                    'label': i,
                    'value': i
                } for i in group_options],
                placeholder='Select a group...'),
        ],
        style={'width': '15%',
               'display': 'inline-block'}),
    html.Div(
        [
            dcc.Dropdown(
                id="Category",
                options=[{
                    'label': i,
                    'value': i
                } for i in category_options],
                placeholder='Select a category...',
                value='Overall'),
        ],
        style={'width': '15%',
               'display': 'inline-block'}),
    dcc.Graph(id='plot-graph'),

])

def clear_selected_group(Options):

    return None

def set_group_options(Cluster):

    return [{'label': i, 'value': i} for i in ['Group1','Group2']]

def update_graph(Cluster, Group, Category):

    if any(i is None for i in [Cluster, Group, Category]): print(Cluster, Group, Category)

    print(Cluster, Group, Category)

app.callback(
    Output('Group', 'value'),
    [Input('Group', 'options')]
)(clear_selected_group)

app.callback(
    Output('plot-graph', 'figure'),
    [Input('Cluster', 'value'), Input('Group', 'value'), Input('Category', 'value')]
)(update_graph)

app.callback(
    Output('Group', 'options'),
    [Input('Cluster', 'value')]
)(set_group_options)

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

My main question (and potentially a bug) is why the print statement is not triggered when the Dropdown value for id="Cluster" is changed? The Dropdown with id="Cluster" is listed as an Input to the update_graph() callback function, so it should be triggered, correct?

Right of the bat, I’m noticing two syntax errors:

  1. app.callback is a decorator, which means it should start with a ‘@
  2. You need a function definition that immediately follows the callback.

You should read the documentation on callbacks, but as for your question, I think the solution is to use the following instead:

@app.callback(Output('Group', 'options'),
    [Input('Cluster', 'value')])
def set_group_options(value):
    return [{'label': i, 'value': i} for i in ... ]