Dash Python中的动态输入

Dynamic Inputs In Dash Python

提问人:piacobelli 提问时间:10/16/2023 最后编辑:Dmitrypiacobelli 更新时间:11/16/2023 访问量:43

问:

此 Dash 回调从 JSON 文件中读取组件 ID 作为输入组件。当列表是静态的时,回调本身可以正常工作,但如果在列表中添加或删除 id,应用程序会崩溃并给出“缺少输入组件”错误。JSON 文件正在按预期更新,但输入组件未根据 JSON 更改重新定义。我该如何解决这个问题?

@dash.callback(
    Output('selectedPatientsStoreBeta1', 'data'),
    [Input(value, 'value') for value in safetyCheckInfoReadout()[1]],
    prevent_initial_call=True,
)
def patientSelection(*args):
    selectionValues = []
    for i in args:
        if str(i) == 'None' or i is None:
            iVal = ''
        else:
            iVal = str(i).translate(str.maketrans('', '', '"\'[]'))
        selectionValues.append(iVal)

    selectedPatients = []
    for index, value in enumerate(safetyCheckInfoReadout()[1]):
        if str(value.split('-')[-1]) in selectionValues[index]:
            selectedPatients.append(str(value.split('-')[-1]))
    if len(selectedPatients) > 0:
        selectedPatients = str(selectedPatients).translate(
            str.maketrans('', '', '"\' []'))
    else:
        selectedPatients = ''

    return selectedPatients
python json 输入 回调 plotly-dash

评论


答:

0赞 Dmitry 11/16/2023 #1

TL;博士

使用模式匹配回调可以解决这个问题。提供动态组件字典 ID:

...
dcc.Input(id={'type': 'my_form_field', index: 1}),
dcc.Input(id={'type': 'my_form_field', index: 2}),
...

一次处理它们的所有值:

from dash import ALL

@dash.callback(
    Output('some_output_component_id', 'data'),
    Input({'type': 'my_form_field', 'index': ALL}, 'value'),
    prevent_initial_call=True)
def on_my_form_field_change(values: list):
    for value in values:
        ...

并非所有组件都支持此功能!例如,(来自 dash 核心组件)有,但(来自 dash 引导组件)没有。dcc.Inputdbc.Input

笔记

还值得注意的是,以显示的方式传递输入将无法按预期工作。是的,可以将装饰器的参数绑定到可调用的结果。但是,在这种情况下,传递的是列表推导的结果,一旦计算出来,就永远不会再改变。此外,实际上解析装饰器的参数并与一些其他属性一起填充。因此,这不是更改回调签名的方法。举例说明:Dashcallbackcallback_map

app.layout = html.Div([
    dcc.Store(id='test0', data='test0'),
    dcc.Store(id='test1', data='test1'),
    dbc.Button('Click!', id='button', n_clicks=0),
    dbc.Input(id='output')])

def get_state(tick: int = 0):
    # switches between test0 and test1
    return State(f'test{tick % 2}', 'data')

# initialize with test1
state = get_state(-1)

@dash.callback(
    Output('output', 'value'),
    Input('button', 'n_clicks'),
    state)
def testing(clicks, value):
    global state
    print(f"clicks={clicks}, argument={value}, variable={state.component_id}")
    state = get_state(clicks)
    return value

点击时的示例输出:

clicks=0, argument=test1, variable=test1
clicks=1, argument=test1, variable=test0
clicks=2, argument=test1, variable=test1
clicks=3, argument=test1, variable=test0

使用的状态保持不变:

print(app.callback_map['output.value'])
# ...
# {
#   "state": [
#    {
#      "id": "test1",
#      "property": "data"
#    }
#  ],
# ...