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 值为 url
的 Location
组件。因此,由于 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"
我有一个简单的破折号应用程序,带有折线图和用作过滤器的单选按钮。
我创建了 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 值为 url
的 Location
组件。因此,由于 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"