Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Simultaneous change of inputs of a callback #779

Open
gcathelain opened this issue Jun 18, 2019 · 1 comment
Open

[BUG] Simultaneous change of inputs of a callback #779

gcathelain opened this issue Jun 18, 2019 · 1 comment

Comments

@gcathelain
Copy link

Dear community,

I want to separate a single callback into separate tasks for efficiency.
For example when :

  • input A outputs result1 and result2
  • input B outputs result2 and result3
    I prefer to have one callback for each task, so three callbacks with single outputs; instead of a single callback that takes A and B as inputs and outputs result 1, 2, 3, which should be significantly slower.
    Here is an illustration of the desired solution :
    Capture

When you click on button A, it is supposed to fire in the end twice the main callback. However it fires only once the callback, executing randomly either task1 either task2.

Anybody has the solution ? Thanks in advance

Here is the code, that runs without error:

import dash
from dash.dependencies import Input, Output,State
import dash_html_components as html
import dash_core_components as dcc
from dash import callback_context


app = dash.Dash(__name__)

app.layout = html.Div([
    html.Div(id='task1',children='Task1 : '),
    html.Div(id='task2',children='Task2 : '),
    html.Div(id='task3',children='Task3 : '),
    html.Button('ButtonA',id='A'),
    html.Button('ButtonB',id='B'),
    html.Div(id='main-result',children='')
])


@app.callback(
    Output('main-result', 'children'),
    [Input('task1', 'children'),
     Input('task2', 'children'),
     Input('task3', 'children')
     ],
     [State('main-result','children')]
     )
def main_callback(result1,result2,result3,mainResult):
    changedInputs = [prop['prop_id'] for prop in callback_context.triggered]
    if 'task1.children' in changedInputs:
        mainResult += 'task1, '
    if 'task2.children' in changedInputs:
        mainResult += 'task2, '
    if 'task3.children' in changedInputs:
        mainResult += 'task3, '
    return mainResult

@app.callback(
    Output('task1', 'children'),
    [Input('A', 'n_clicks')],
    [State('task1', 'children')]
     )
def task1(A,result1):
    result1 += 'click, '
    return result1

@app.callback(
    Output('task2', 'children'),
    [Input('A', 'n_clicks'),
    Input('B', 'n_clicks')
    ],
    [State('task2', 'children')]
     )
def task2(A,B,result2):
    result2 += 'click, '
    return result2

@app.callback(
    Output('task3', 'children'),
    [Input('B', 'n_clicks')],
    [State('task3', 'children')]
     )
def task3(B,result3):
    result3 += 'click, '
    return result3


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

@gcathelain
Copy link
Author

It seems like callback_context is not able to catch multiple triggers ...

The only (unsatisfying) solution that I found is to return all the inputs, but it means that you can't use state of the main-result in the main_callback ...

In the code below, I changed task div into store div:

import dash
from dash.dependencies import Input, Output,State
import dash_html_components as html
import dash_core_components as dcc
from dash import callback_context
import json
import time

app = dash.Dash(__name__)

app.layout = html.Div([
    dcc.Store(id='task1',data=dict(n_clicks=0,task='1')),
    dcc.Store(id='task2',data=dict(n_clicks=0,task='2')),
    dcc.Store(id='task3',data=dict(n_clicks=0,task='3')),
    html.Button('ButtonA',id='A'),
    html.Button('ButtonB',id='B'),
    html.Div(id='main-result',children='')
])

@app.callback(
    Output('main-result', 'children'),
     [
        Input('task1', 'data'),
        Input('task2', 'data'),
        Input('task3', 'data')]
     )
def main_callback(data1,data2,data3):
    return json.dumps([data1,data2,data3])

@app.callback(
    Output('task1', 'data'),
    [Input('A', 'n_clicks')],
    [State('task1', 'data')]
     )
def task1(A,data1):
    data1['n_clicks'] += 1
    return data1

@app.callback(
    Output('task2', 'data'),
    [Input('A', 'n_clicks'),
    Input('B', 'n_clicks')
    ],
    [State('task2', 'data')]
     )
def task2(A,B,data2):
    data2['n_clicks'] += 1
    return data2

@app.callback(
    Output('task3', 'data'),
    [Input('B', 'n_clicks')],
    [State('task3', 'data')]
     )
def task3(B,data3):
    data3['n_clicks'] += 1
    return data3



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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant