Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

plotly dash: create multiple callbacks (with loop?)

Tags:

plotly-dash

Say I have a model with 20 parameters and I made one input component for each param.

[dcc.Input(type = 'number', id = 'input %i'%i) for i in range(20)]

I want to have one button html.Button('populate parameters', id = 'button populate') that is supposed to populate best pre-fitted value for all the inputs.

Code should look like below, except it doesn't work.

for i in range(20):
    @app.callback(
        dash.dependencies.Output('input %i'%i, 'value'),
        [dash.dependencies.Input('button populate', 'n_clicks')]
    )
    def update(ignore):
        return np.random.uniform()

Do I have to write 20 callbacks for each output with identical functionality? I can't find a way to make them in one go (loop?)

like image 481
jf328 Avatar asked Dec 24 '18 20:12

jf328


People also ask

Can Dash have multiple callbacks?

If a Dash app has multiple callbacks, the dash-renderer requests callbacks to be executed based on whether or not they can be immediately executed with the newly changed inputs. If several inputs change simultaneously, then requests are made to execute them all.

What is Suppress_callback_exceptions?

suppress_callback_exceptions: check callbacks to ensure referenced IDs exist and props are valid. Set to True if your layout is dynamic, to bypass these checks. So there isn't really a difference in the examples you linked on their own.

Is a dash asynchronous?

dash-devices is another async port based on quart . It's capable of using websockets even for callbacks, which makes it way faster than either of dash or async-dash .


2 Answers

I have dealt with the same issue and found a solution. What you do is bypass the decorator and call the app.callback function directly:

def update(ignore):
    return np.random.uniform()

for i in range(20):
    app.callback(
        dash.dependencies.Output('input %i' % i, 'value'),
        [dash.dependencies.Input('button populate', 'n_clicks')]
    )(update)
like image 77
Shovalt Avatar answered Nov 10 '22 06:11

Shovalt


In dash >= 1.11.0 you may use Pattern-Matching Callbacks. No loops needed when defining the callback(s).

Example

1. Import callback selectors

  • Import dash.dependecies.ALL:
from dash.dependencies import Input, Output, State, ALL
  • Other available callback selectors are MATCH and ALLSMALLER.

2. Use dictionaries as the id

  • Define your components with a id that is a dictionary. You may choose any keys but for example type and id are quite reasonable choices. So, instead of
[dcc.Input(type = 'number', id = 'input %i'%i) for i in range(20)]

use

[
    dcc.Input(type='number',
              id={
                  'type': 'my-input-type',
                  'id': 'input %i' % i
              }) for i in range(20)
]

3. Use a callback selector with @app.callback

  • Use the ALL callback selector when defining the callback:
@app.callback(
    dash.dependencies.Output({
        'type': 'my-input-type',
        'id': ALL
    }, 'value'), [dash.dependencies.Input('button populate', 'n_clicks')])
def update(ignore):
    return np.random.uniform()
like image 23
np8 Avatar answered Nov 10 '22 06:11

np8