Dash 多个独立回调

Dash multiple independent callbacks

我有一个简单的破折号应用程序,带有折线图和用作过滤器的单选按钮。

我创建了 2 个回调 - 第一个用于 url,第二个用于过滤器。但是,当我 运行 应用程序时,它一直在不断更新(我想在循环中调用第二个回调)。似乎这两个回调在某种程度上相互依赖,但我希望它们是独立的——我需要 运行 仅当单选按钮(过滤器)更改时才需要第二个回调。

没有第一次回调一切正常。

@app.callback(
    Output('page-content', 'children'),
    [Input('url', 'pathname')]
)
def display_page(pathname):
    if pathname == '/':
        return '404'
    elif pathname == '/something/my-dashboard':
        return app.layout
    else:
        return '404'

@app.callback(
    Output("main-chart", "figure"), 
    Input("category", "value")
)
def update_graph(category):
    dff = melted[melted["category"] == category]
    fig = create_chart(dff)
    set_style(fig, category)
    return fig

编辑: 添加布局

app.layout = html.Div(
    [   dcc.Location(id='url', refresh=False),
        html.Div(
            [
                html.Div(
                    [
                        html.H1(children="My dashboard"),
                        html.Div([dcc.Graph(id="main-chart", figure=fig)]),
                    ],
                    className="column1",
                ),
                html.Div(
                    [
                        dbc.Label("Filter", style={'fontWeight':'bold'}),
                        dcc.RadioItems(
                            id="category",
                            options=[{"label": i, "value": i} for i in categories],
                            value="Product A",
                            labelStyle={"display": "block"},
                        ),
                    ],
                    className="column2",
                ),
            ],
            className="row",
            id='page-content'
        ),
    ]
)

在@BasvanderLinden 建议后编辑 2:

fig = create_chart(df)
set_style(fig, "Marketing")

app.layout = html.Div(
    [   dcc.Location(id='url', refresh=False),
        html.Div(
            className="row",
            id='page-content'
        ),
    ]
)

dashboard_layout = html.Div(
    [
                html.Div(
                    [
                        html.H1(children="My dashboard"),
                        html.Div([dcc.Graph(id="main-chart", figure=fig)]),
                    ],
                    className="column1",
                ),
                html.Div(
                    [
                        dbc.Label("Category", style={'fontWeight':'bold'}),
                        dcc.RadioItems(
                            id="category",
                            options=[{"label": i, "value": i} for i in categories],
                            value="Marketing",
                            labelStyle={"display": "block"},
                        ),
                    ],
                    className="column2",
                ),
            ],
)


@app.callback(Output("page-content", "children"), [Input("url", "pathname")])
def display_page(pathname):
    print(pathname)
    if pathname == "/":
        return "404"
    elif pathname == "/my-dashboard":
        return dashboard_layout
    else:
        return "404"

@app.callback(
    Output("main-chart", "figure"), 
    Input("category", "value")
)
def update_graph(category):
    dff = df[df["Category"] == category]
    fig = create_chart(dff)
    set_style(fig, category)
    return fig


if __name__ == "__main__":
    app.run_server(debug=True, host="0.0.0.0")

其实问题出在你的第一个回调:

@app.callback(
    Output('page-content', 'children'),
    [Input('url', 'pathname')]
)
def display_page(pathname):
    if pathname == '/':
        return '404'
    elif pathname == '/something/my-dashboard':
        return app.layout
    else:
        return '404'

问题是你returnapp.layout这里

这里发生的事情真的很有趣。由于 app.layout 覆盖了整个布局,这意味着它将包含 ID 值为 urlLocation 组件。因此,由于 app.layout 附加到 page-content div,这意味着在将 app.layout 附加到 page-content div 之后,现在有两个 Location 个具有相同 ID 的组件 (url)。事实上,有一个新的 Location 组件注册了 id url 导致回调被再次触发。这一切都会导致第一个回调被递归触发并将元素附加到 dom。如果您检查浏览器中的元素,您可以看到这种情况。

因此,解决方案是不要在回调中 return app.layout,而是在回调中抽象部分布局和 return。这是一个在其定义中不包含 Location 组件的组件。

因此您可以在其自己的组件中抽象仪表板,如下所示:

dashboard_layout = html.Div(
    [
        html.Div(
            [
                html.H1(children="My dashboard"),
                html.Div([dcc.Graph(id="main-chart", figure=fig)]),
            ],
            className="column1",
        ),
        html.Div(
            [
                dbc.Label("Filter", style={"fontWeight": "bold"}),
                dcc.RadioItems(
                    id="category",
                    options=[{"label": i, "value": i} for i in categories],
                    value="Product A",
                    labelStyle={"display": "block"},
                ),
            ],
            className="column2",
        ),
    ]
)

app.layout = html.Div(
    [
        dcc.Location(id="url", refresh=False),
        html.Div(
            className="row",
            id="page-content",
        ),
    ]
)

@app.callback(Output("page-content", "children"), [Input("url", "pathname")])
def display_page(pathname):
    print(pathname)
    if pathname == "/":
        return "404"
    elif pathname == "/something/my-dashboard":
        return dashboard_layout
    else:
        return "404"