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

Additional parameters for callbacks

I tried to generate dynamic callbacks like this:

y_axe = [None, 'n_trips']
debug = ['debug1', 'debug2', 'debug3', 'debug4', 'debug5']
x_time = [
    ('x-time-series-df-tc-all', 'x-time-filter-df-tc-all', 0, 3, 0), ('x-time-series-df-tc-1', 'x-time-dropdown-df-tc-1', 0, 3, 1),
    ('x-time-series-1', 'x-time-filter-1', 1, 2, 2), ('x-time-series-2', 'x-time-filter-2', 1, 2, 3), ('x-time-series-3', 'x-time-filter-3', 1, 2, 4),  
]

for (graph, fname, y, i, d) in x_time:
    @app.callback(
        [Output(graph, 'figure'), Output(debug[d], 'children'),],
        [Input('date-picker-range', 'start_date'),
         Input('date-picker-range', 'end_date'),
         Input(fname, 'value')])
    def update_graphs1(start, stop, cfilter):
        start = int(start.split("T")[0].replace("-", ""))
        stop = int(stop.split("T")[0].replace("-", ""))
        dff = None
        dff = df[i].loc[(start <= df[i]['day']) & (df[i]['day'] <= stop)]
        if cfilter is '': cfilter = '*'
        if y_axe[y] is None: y_axe[y] = cfilter
        val = debug[d]
        return generate_time_series_figure(dff, cfilter, y_axe[y]), val

But this isn’t working, and my the Output of my debug children always looked like this:

  • debug5
  • debug5
  • debug5
  • debug5
  • debug5

But they should look like this:

  • debug1
  • debug2
  • debug3
  • debug4
  • debug5

Is there a way to use additional parameters for the function of the callback like this:

for (graph, fname, y, i, d) in x_time:
    @app.callback(
        [Output(graph, 'figure'), Output(debug[d], 'children'),],
        [Input('date-picker-range', 'start_date'),
         Input('date-picker-range', 'end_date'),
         Input(fname, 'value'),
         y, i, d
    ])
    def update_graphs1(start, stop, cfilter, y, i, d):

I want to choose my DataFrame, y_axe with an list of tuples, my first try rather looked like this but had the same issues:

x_time = [
    ('x-time-series-df-tc-all', 'x-time-filter-df-tc-all', None, 3), ('x-time-series-df-tc-1', 'x-time-dropdown-df-tc-1', None, 3),
    ('x-time-series-1', 'x-time-filter-1', 'n_trips', 2), ('x-time-series-2', 'x-time-filter-2', 'n_trips', 2), ('x-time-series-3', 'x-time-filter-3', 'n_trips', 2),  
]
for (graph, fname, y_axe, i) in x_time:
    @app.callback(
        Output(graph, 'figure'),
        [Input('date-picker-range', 'start_date'),
         Input('date-picker-range', 'end_date'),
         Input(fname, 'value')])
    def update_graphs2(start, stop, cfilter):
        start = int(start.split("T")[0].replace("-", ""))
        stop = int(stop.split("T")[0].replace("-", ""))
        y = y_axe
        dff = None
        dff = df[i].loc[(start <= df[i]['day']) & (df[i]['day'] <= stop)]
        if cfilter is '': cfilter = '*'
        if y is None: y = cfilter
        return generate_time_series_figure(dff, cfilter, y)
for (graph, fname, y, i, d) in x_time:

could be

for x in x_time:
  graph - x[0]
  fname = x[1]
  y = x[2]
  i = x[3]
  d = x[4]

…if I interpret your intentions correctly…

I try to explain it more deeply:

    html.Div([html.H3(id='debug1', children='Debug1:'),]),
    html.Div([html.H3(id='debug2', children='Debug2:'),]),
    html.Div([html.H3(id='debug3', children='Debug3:'),]),
    html.Div([html.H3(id='debug4', children='Debug4:'),]),
    html.Div([html.H3(id='debug5', children='Debug5:'),]),

Is my Debug-Layout to see if the dynamic callback allocation works.

I use a list to assign those and the Graphs:

x_time = [
    ('x-time-series-df-tc-all', 'x-time-filter-df-tc-all', None, 3, 'debug1'), ('x-time-series-df-tc-1', 'x-time-dropdown-df-tc-1', None, 3, 'debug2'),
    ('x-time-series-1', 'x-time-filter-1', 'n_trips', 2, 'debug3'), ('x-time-series-2', 'x-time-filter-2', 'n_trips', 2, 'debug4'), ('x-time-series-3', 'x-time-filter-3', 'n_trips', 2, 'debug5'),  
]

for (graph, fname, y_axe, i, d) in x_time:
    print(graph, fname, y_axe, i, d)

Output:
x-time-series-df-tc-all x-time-filter-df-tc-all None 3 debug1
x-time-series-df-tc-1 x-time-dropdown-df-tc-1 None 3 debug2
x-time-series-1 x-time-filter-1 n_trips 2 debug3
x-time-series-2 x-time-filter-2 n_trips 2 debug4
x-time-series-3 x-time-filter-3 n_trips 2 debug5

So the test output is totally fine.
At the beginning when I don’t assign a callback my dash looks like this:

1

Now when I assign this callback:

x_time = [
    ('x-time-series-df-tc-all', 'x-time-filter-df-tc-all', None, 3, 'debug1'), ('x-time-series-df-tc-1', 'x-time-dropdown-df-tc-1', None, 3, 'debug2'),
    ('x-time-series-1', 'x-time-filter-1', 'n_trips', 2, 'debug3'), ('x-time-series-2', 'x-time-filter-2', 'n_trips', 2, 'debug4'), ('x-time-series-3', 'x-time-filter-3', 'n_trips', 2, 'debug5'),  
]
for (graph, fname, y_axe, i, d) in x_time:
    @app.callback(
        [Output(graph, 'figure'), Output(d, 'children'),],
        [Input('date-picker-range', 'start_date'),
         Input('date-picker-range', 'end_date'),
         Input(fname, 'value')])
    def update_graphs2(start, stop, cfilter):
        start = int(start.split("T")[0].replace("-", ""))
        stop = int(stop.split("T")[0].replace("-", ""))
        y = y_axe
        dff = None
        dff = df[i].loc[(start <= df[i]['day']) & (df[i]['day'] <= stop)]
        if cfilter is '': cfilter = '*'
        if y is None: y = cfilter
        return generate_time_series_figure(dff, cfilter, y), d

My Output looks like this:


This is not the correct Output if i compare it with the for loop.

I tried to use a smaller list:

x_time = [
    ('x-time-series-df-tc-all', 'x-time-filter-df-tc-all', None, 3, 'debug1'), ('x-time-series-df-tc-1', 'x-time-dropdown-df-tc-1', None, 3, 'debug2'),
#   #('x-time-series-1', 'x-time-filter-1', 'n_trips', 2, 'debug3'), ('x-time-series-2', 'x-time-filter-2', 'n_trips', 2, 'debug4'), ('x-time-series-3', 'x-time-filter-3', 'n_trips', 2, 'debug5'),  
]

But with kinda the same effect:

The Output Graphs and Debug got assigned correctly , but the value which got assigned is false.

I just tried to Change the order of the list to:

x_time = [
    ('debug1', 'x-time-filter-df-tc-all', None, 3, 'x-time-series-df-tc-all'), ('debug2', 'x-time-dropdown-df-tc-1', None, 3, 'x-time-series-df-tc-1'),
]

But it had the same effect.

So the Problem is the function which gets assigned to the callbacks!

All values which weren’t Parameters of the function got a false value at the end and only used the value which got assigned to it at the last instance like ‘debug2’ or ‘debug5’.

That’s why I’m asking how I can use additional Parameters for the function of the callback like:

for (graph, fname, y_axe, i, d) in x_time:
    @app.callback(
        [Output(graph, 'figure'), Output(d, 'children'),],
        [Input('date-picker-range', 'start_date'),
         Input('date-picker-range', 'end_date'),
         Input(fname, 'value'), 
         y, i, d])
    def update_graphs2(start, stop, cfilter, y, i, d):

How can I use an Input Argument that is not the type ‘dash.Input’:

I tried to reassign the values within the function but this had the same effect.

x_time = [
    ('x-time-series-df-tc-all', 'x-time-filter-df-tc-all', None, 3, 'debug1'), ('x-time-series-df-tc-1', 'x-time-dropdown-df-tc-1', None, 3, 'debug2'),
    ('x-time-series-1', 'x-time-filter-1', 'n_trips', 2, 'debug3'), ('x-time-series-2', 'x-time-filter-2', 'n_trips', 2, 'debug4'), ('x-time-series-3', 'x-time-filter-3', 'n_trips', 2, 'debug5'),  
]

def update_graphs2(start, stop, cfilter):
    start = int(start.split("T")[0].replace("-", ""))
    stop = int(stop.split("T")[0].replace("-", ""))
    if cfilter is '': cfilter = '*'
    y = 'n_trips'
    val = 'debug7'
    i = 0
    for (a, b, c, d, e) in x_time:
        if b == cfilter: 
            y = c
            val = e
            i = d
    dff = df[i].loc[(start <= df[i]['day']) & (df[i]['day'] <= stop)]
    if y is None: y = cfilter
    return generate_time_series_figure(dff, cfilter, y), val

for (graph, fname, y_axe, index, debug) in x_time:
    app.callback([Output(graph, 'figure'), Output(debug, 'children'),],
                 [Input('date-picker-range', 'start_date'), Input('date-picker-range', 'end_date'), Input(fname, 'value')])(
        update_graphs2)
    

I haven’t tried it out yet, but looks like the django-plotly-dash library might have the functionality you’re looking for. It allows you to add keyword arguments to your functions after all the positional input and state arguments from your callback decorator.