Обратный вызов сопоставления с шаблоном в plotly-dash

#python #plotly-dash

#python #plotly-dash

Вопрос:

Работая с plotly dash, я пытаюсь, чтобы элементы ListGroup функционировали как кнопки, которые будут обновлять свою метку при нажатии. Вот код, который работает по назначению, но я вручную создал обратный вызов для каждой кнопки.

 import dash
import dash_bootstrap_components as dbc
import dash_html_components as html
from dash.dependencies import Input, Output

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

app.layout = (
    html.Div([
        dbc.ListGroup([
            dbc.ListGroupItem(id="button1", n_clicks=0, action=True),
            dbc.ListGroupItem(id="button2", n_clicks=0, action=True),
            dbc.ListGroupItem(id="button3", n_clicks=0, action=True),
        ])
    ])
)

@app.callback(Output("button1", "children"), [Input("button1", "n_clicks")])
def clicked1(n_clicks):
    return f"Button 1: clicked {n_clicks} times"

@app.callback(Output("button2", "children"), [Input("button2", "n_clicks")])
def clicked2(n_clicks):
    return f"Button 2: clicked {n_clicks} times"

@app.callback(Output("button3", "children"), [Input("button3", "n_clicks")])
def clicked3(n_clicks):
    return f"Button 3: clicked {n_clicks} times"

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

Кнопки появляются и обновляются при нажатии. График обратного вызова в меню отладки выглядит так, как я ожидаю.
рабочая панель мониторинга

Теперь я хочу заменить три функции обратного вызова только одной, используя сопоставление с образцом. Идея в том, что у меня может быть динамический список из произвольного количества элементов, и все они будут обновляться, как и ожидалось. Следуя тому, как это описано в документации, я изменяю код, чтобы использовать словари для идентификаторов в элементах и в обратном вызове.

 import dash
import dash_bootstrap_components as dbc
import dash_html_components as html
from dash.dependencies import Input, Output, MATCH

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

app.layout = (
    html.Div([
        dbc.ListGroup([
            dbc.ListGroupItem(id={"type": "button", "index": 0}, n_clicks=0, action=True),
            dbc.ListGroupItem(id={"type": "button", "index": 1}, n_clicks=0, action=True),
            dbc.ListGroupItem(id={"type": "button", "index": 2}, n_clicks=0, action=True),
        ])
    ])
)

@app.callback(Output({"type": "button", "index": MATCH}, "children"), [Input({"type": "button", "index": MATCH}, "n_clicks")])
def clicked(n_clicks):
    return f"Button clicked {n_clicks} times"


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

Теперь кнопки ничего не показывают (предполагая, что обратные вызовы не выполнялись), они доступны для просмотра, но при нажатии на них ничего не происходит, а график обратного вызова — беспорядок.

панель инструментов с обратным вызовом сопоставления с образцом

Насколько я могу судить, я следовал инструкциям. Я не получаю никаких ошибок, это просто не работает. Чего мне не хватает?

Комментарии:

1. Не уверен, но есть две идеи: вы пытались установить явное значение для начала children prop? Четный children='' . Кроме того, вы пробовали разделить компоненты на кнопку и текстовый компонент?

2. Я попытался сначала явно установить дочерние элементы, это не имело никакого значения. Если выполняется обратный вызов, это устанавливает дочерние элементы, если нет, это то, на что я его установил. Я не пробовал разделять компоненты, но, поскольку мой первый пример работает, похоже, что соответствие шаблону нарушено, поэтому я тоже не вижу, чтобы это помогло.

Ответ №1:

Я счастлив, что вы решили свою проблему.

Я просто хотел бы предложить улучшение кода:

 def group_item(index, click=None, action=False):
    return dbc.ListGroupItem(id={"type": "button", "index": index}, n_clicks=click, action=action)

app.layout = (
    html.Div([
        dbc.ListGroup(
            [group_item(i, click=0, action=True) for i in range(3)]
        )
    ])
)
  

Надеюсь, что это может быть полезно для вас.

Ответ №2:

Оказывается, проблема была в управлении версиями.

Я установил dash с помощью anaconda, а в главном репозитории anaconda есть очень старые версии зависимостей dash. Итак, несмотря на то, что у меня была версия dash 1.16.3, а сопоставление с образцом в обратных вызовах было введено в 1.11, для сопоставления с образцом также требуется средство визуализации dash версии 1.4 или выше, и у меня был 1.1.2.

Решением для меня было установить dash из conda-forge, который имеет обновленные версии всех зависимостей dash.

conda install -c conda-forge dash