Black Lives Matter. Please consider donating to Black Girls Code today.

Creating an output using dynamic callbacks by creating a callback per unique combination

Hey guys, I got an issue when trying to create dynamic callbacks. I’m trying to follow the example provided here:


But i can’t seem to get it work, although I do believe I’m close! (just a heads up, I’m very new in this environment)

So i added my code below. The idea here is to have 3 different graphs, which can each be customized by a set of parameters unique to the country. The extra paramters you can choose are the borders of the country specified using the tabs. So for example looking at NL, you get the choice between NO, UK, CWE.

As you can see the tabs work, the dynamic controller works as well, but i can’t seem to get the output i want (in id=output-container). The output should be: ‘-’.join(borders), country but nothing is showing. If you check the link i added above, the example i followed, i really don’t see any huge differences so I have no clue why mine is not working. If you go into generate_output_callacbk (using pdb.set_trace()) the parameter borders does contain the correct borders, its just that the output is not showing!

Any help here will be very much appreciated!
Thanks in advance,
Nick

import dash
import dash_core_components as dcc
import dash_html_components as html

CWE_borders = {'NL' : ['UK', 'NO', 'CWE'],
               'FR' : ['ES', 'UK', 'IT_NORTH', 'CH', 'CWE'],
               'DE' : ['CH', 'CZ', 'HU', 'SI', 'IT_NORTH', 'DK', 'PL',
                       'SE_4'],}


app = dash.Dash()
app.layout = html.Div([
    html.H1('Model Results'),
    dcc.Tabs(
            tabs=[{'label': i, 'value': i} for i in ['NL', 'FR', 'DE']],
            value='NL',
            id='tabs',
        ),
        html.Div(id='tab-output'),
    html.Div(id='Dynamic Controls'),
    html.Div('OUTPUT'),
    html.Div(id='output-container'),
    html.Div('damnit'),
])


def generate_control_id(value):
    return '{} control'.format(value)
def generate_output_id(value):
    return '{} container'.format(value)

@app.callback(
    dash.dependencies.Output('Dynamic Controls', 'children'),
    [dash.dependencies.Input('tabs', 'value'),])
def display_controls(c):
    return dcc.Checklist(
        id=generate_control_id(c),
        options=[{'label': i, 'value': i} for i in CWE_borders[c]],
        values=CWE_borders[c])

def generate_output_callback(country):
    def output_callback(borders):
        return '-'.join(borders), country
    return output_callback

app.config.supress_callback_exceptions = True


for country in CWE_borders.keys():
    app.callback(
        dash.dependencies.Output(generate_output_id(country), 'childeren'),
        [dash.dependencies.Input(generate_control_id(country), 'values')])(
        generate_output_callback(country))

@app.callback(
    dash.dependencies.Output('flows', 'children'),
     [dash.dependencies.Input('tabs', 'value'),])
def update_figure5(country):
    return html.Div(id=generate_output_id(country))

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

It looks like the underlying issue is that your generated output IDs weren’t actually winding up in your layout, so the callbacks didn’t have anywhere to put them.

Looking at your code, I don’t actually think you need to use dynamic callbacks. Since you only have the one Checkbox Input for each tab, you can just use a single callback that targets it. Does this do the job:

app = dash.Dash()
app.layout = html.Div([
    html.H1('Model Results'),
    dcc.Tabs(
        tabs=[{'label': i, 'value': i} for i in ['NL', 'FR', 'DE']],
        value='NL',
        id='tabs',
        ),
    html.Div(id='dynamic-controls'),
    html.Div('OUTPUT'),
    html.Div(id='output-container'),
])


app.config.supress_callback_exceptions = True

@app.callback(Output('dynamic-controls', 'children'), [Input('tabs', 'value')])
def display_controls(c):
    return dcc.Checklist(
        id='control',
        options=[{'label': i, 'value': i} for i in CWE_borders[c]],
        values=CWE_borders[c]
    )

@app.callback(Output('output-container', 'children'), [Input('control', 'values')])
def output_callback(borders):
    return '-'.join(borders)
1 Like

This works perfectly fine, thanks a lot for the fast response!

1 Like