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

Callback with multiple inputs

I have an app, that have dependencies across a few filters (dropdown, datepicker), and the value from it was used as input again.
It works perfectly, if I were just to a single input in the callback, however, issues arises when there are multiple inputs in the callback.

Below is a small example, illustrating this.

import dash
from dash.dependencies import Input, Output, State
import dash_html_components as html
import dash_core_components as dcc
import pandas as pd
from datetime import datetime as dt
import datetime

app = dash.Dash()
app.config['suppress_callback_exceptions'] = True

d= {'X': list('ABCABC'), 'Y':list('dddeee'), 'Z': [dt.today() + datetime.timedelta(days = i) for i in range(6)]}
data = pd.DataFrame(d)
filter_options = {i:[j for j in data[data.X == i].Y.unique()] for i in data.X.unique()}

app.layout = html.Div([
    html.Div([
            dcc.RadioItems(
                    id ='filter1',
                    options = [{'label': i, 'value': i} for i in data.X.unique()]
            ), 
            dcc.Dropdown(id ='filter2'),
            html.Div(id = 'filter-ph'), 
            html.Div(id = "output-div")
    ])
])

@app.callback(Output('filter2','options'), [Input('filter1','value')])
def get_f2_options(selected_f1_value):
    return [{'label':i, 'value': i} for i in filter_options[selected_f1_value]]

@app.callback(Output('filter-ph','children'), [Input('filter2','value')])
def get_date_value(selected_f2_value):
    if selected_f2_value:
        df = data[data.Y == selected_f2_value]
        return dcc.DatePickerSingle(
            id='filter3',
            date=df.Z.max(),
            max_date_allowed=df.Z.max(),
            min_date_allowed=df.Z.min()
        )

@app.callback(Output('output-div','children'), [Input('filter3','date')])
def update_output_div(v1):
    return "Selected date: {}".format(v1)

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

The code above works fine, as there is only one input in the update_output_div.
However, it shows “error loading dependencies” error if I were to use additional input of value from filter2 in update_output_div

import dash
from dash.dependencies import Input, Output, State
import dash_html_components as html
import dash_core_components as dcc
import pandas as pd
from datetime import datetime as dt
import datetime

app = dash.Dash()
app.config['suppress_callback_exceptions'] = True

d= {'X': list('ABCABC'), 'Y':list('dddeee'), 'Z': [dt.today() + datetime.timedelta(days = i) for i in range(6)]}
data = pd.DataFrame(d)
filter_options = {i:[j for j in data[data.X == i].Y.unique()] for i in data.X.unique()}

app.layout = html.Div([
    html.Div([
            dcc.RadioItems(
                    id ='filter1',
                    options = [{'label': i, 'value': i} for i in data.X.unique()]
            ), 
            dcc.Dropdown(id ='filter2'),
            html.Div(id = 'filter-ph'), 
            html.Div(id = "output-div")
    ])
])

@app.callback(Output('filter2','options'), [Input('filter1','value')])
def get_f2_options(selected_f1_value):
    return [{'label':i, 'value': i} for i in filter_options[selected_f1_value]]

@app.callback(Output('filter-ph','children'), [Input('filter2','value')])
def get_date_value(selected_f2_value):
    if selected_f2_value:
        df = data[data.Y == selected_f2_value]
        return dcc.DatePickerSingle(
            id='filter3',
            date=df.Z.max(),
            max_date_allowed=df.Z.max(),
            min_date_allowed=df.Z.min()
        )

@app.callback(Output('output-div','children'), [Input('filter3','date'), Input('filter2', 'value')])
def update_output_div(v1,v2):
    return "Selected date: {}".format(v1)

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

update_output_div has both filter3 and filter2 as Inputs, however when you first load the page, only filter2 appears in your layout. You can of course defined callbacks for Inputs that are not yet in the layout, however I it looks like you can’t define callbacks for which a partial number of Inputs are in the layout. When I test it, removing filter2 from the callback makes it happy.

Yep, it works perfectly if I only use filter3 in the input.
But in my actual app, I actually need both inputs to do computations, not sure if there is any workaround out there fix it.

The behaviour I described is specific to Inputs, as opposed to States. So assuming that you only want this callback to be triggered by filter3, and just want the value of of filter2, then I think the answer is straightforward: make filter2 a State rather than an Input.

1 Like

Thanks for the advise. It works after changing input of filter2 to state of filter2

1 Like