如何使用不同的下拉菜单更新绘图破折号
Posted
技术标签:
【中文标题】如何使用不同的下拉菜单更新绘图破折号【英文标题】:How to update a plotly graph dash with different dropdowns 【发布时间】:2020-07-22 16:59:34 【问题描述】:我正在尝试使用两个不同的下拉菜单作为输入来更新绘图破折号。
这是我的示例数据框:
import pandas as pd
df1 = 'category' : ['A','A','A','B','B','B'],'subcategory' : ['x', 'y', 'z', 'x1','y1','z1'],
'x_coord' : [1, 2,3,2,2,2],'y_coord' : [1,3,2,1,3,2]
df_test = pd.DataFrame(df1)
df_test
我假装做的是,如果我选择类别 A,将所有对应点绘制成散点图,但如果我也选择了一个子类别,它会修改图形,仅绘制对应的类别子类别点数据框。
代码如下,如果我只添加第一个下拉菜单的回调,它可以工作,但是当我将第二个回调添加到子类别时它不起作用。 我正在遵循破折号情节教程中的建议:
A word of caution: it's not always a good idea to combine Outputs, even if you can: If the Outputs depend on some but not all of the same Inputs, keeping them separate can avoid unnecessary updates. If they have the same Inputs but do independent computations with these inputs, keeping the callbacks separate can allow them to run in parallel.
Dash documentation callbacks
但无论如何,如果我将输出放在单独的回调中或放在同一个回调中,我无法使其工作,这是我正在尝试的代码(使用 jupyter notebook):
import dash
import plotly as py
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objects as go
from jupyter_plotly_dash import JupyterDash
py.offline.init_notebook_mode(connected = True)
app = JupyterDash('Test')
app.layout = html.Div([
dcc.Dropdown(id='dropdown1',
options=['label':i, 'value':i for i in df_test['category'].unique()]),
dcc.Dropdown(id='dropdown2',
options=['label':i, 'value':i for i in df_test['subcategory'].unique()]),
dcc.Graph(id='graphic')
])
@app.callback(
Output('dropdown2', 'options'),
[Input('dropdown1', 'value')])
def update_drop2(selected_drop):
filtered_df = df_test[(df_test.category == selected_drop)]
return ['label':i, 'value':i for i in filtered_df['subcategory'].unique()]
@app.callback(
Output('graphic', 'figure'),
[Input('dropdown1', 'value')])
def update_figure(selected_drop):
filtered_df = df_test[(df_test.category == selected_drop)]
fig = go.Figure()
fig.add_trace(go.Scatter(x=filtered_df.x_coord,y=filtered_df.y_coord, marker = dict(size=15, color='green'), mode='markers'))
return fig
@app.callback(
Output('graphic', 'figure'),
[Input('dropdown2', 'value')])
def update_figure(selected_drop):
filtered_df = df_test[(df_test.subcategory == selected_drop)]
fig = go.Figure()
fig.add_trace(go.Scatter(x=filtered_df.x_coord,y=filtered_df.y_coord, marker = dict(size=15, color='green'), mode='markers'))
return fig
app
如果我像这样在回调中使用多个输入:
@app.callback(
Output('graphic', 'figure'),
[Input('dropdown1', 'value'), Input('dropdown2', 'value')])
def update_figure(selected_drop1, selected_drop2):
if not selected_drop2:
filtered_df = df_test[(df_test.category == selected_drop1)]
else:
filtered_df = df_test[(df_test.category == selected_drop1) &
(df_test.subcategory == selected_drop2)]
fig = go.Figure()
fig.add_trace(go.Scatter(x=filtered_df.x_coord,y=filtered_df.y_coord,
marker = dict(size=15, color='green'), mode='markers'))
return fig
效果更好(或者更接近我假装的效果),但是当我在类别之间切换时,我看不到任何数据。
提前感谢您的帮助和推荐。
【问题讨论】:
【参考方案1】:我遇到了类似的问题,诀窍是在第二个下拉列表中添加一个选项all
。然后我想在第二个下拉列表中只显示给定类别中的子类别。所以我实际上对下拉菜单使用了 2 个回调,对绘图使用了 1 个回调。
app.py
import pandas as pd
import os
import plotly.graph_objs as go
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
df = pd.DataFrame('category' : ['A','A','A','B','B','B'],
'subcategory' : ['x', 'y', 'z', 'x1','y1','z1'],
'x_coord' : [1, 2,3,2,2,2],
'y_coord' : [1,3,2,1,3,2])
# lists of categories
options1 = sorted(df["category"].unique().tolist())
# dictionary of category - subcategories
all_options = df.groupby("category")["subcategory"].unique()\
.apply(list).to_dict()
# we add as first subcategory for each category `all`
for k, v in all_options.items():
all_options[k].insert(0, 'all')
app = dash.Dash()
app.layout = html.Div([
dcc.Dropdown(
id='first-dropdown',
options=['label': k, 'value': k for k in all_options.keys()],
value=options1[0]
),
html.Hr(),
dcc.Dropdown(id='second-dropdown'),
html.Hr(),
dcc.Graph(id='display-selected-values')
])
# the following two callbacks generate a dynamic 2 option
@app.callback(
dash.dependencies.Output('second-dropdown', 'options'),
[dash.dependencies.Input('first-dropdown', 'value')])
def set_2_options(first_option):
return ['label': i, 'value': i for i in all_options[first_option]]
@app.callback(
dash.dependencies.Output('second-dropdown', 'value'),
[dash.dependencies.Input('second-dropdown', 'options')])
def set_2_value(available_options):
return available_options[0]['value']
@app.callback(
dash.dependencies.Output('display-selected-values', 'figure'),
[dash.dependencies.Input('first-dropdown', 'value'),
dash.dependencies.Input('second-dropdown', 'value')])
def update_graph(selected_first, selected_second):
if selected_second == 'all':
ddf = df[df["category"]==selected_first]
else:
ddf = df[(df["category"]==selected_first) &
(df["subcategory"]==selected_second)]
fig = go.Figure()
fig.add_trace(
go.Scatter(x=ddf["x_coord"],
y=ddf["y_coord"],
marker = dict(size=15, color='green'),
mode='markers'))
return fig
if __name__ == '__main__':
app.run_server(debug=True, port=8051)
【讨论】:
在这种情况下 set_2_value 函数在做什么?不清楚...您介意详细说明吗?以上是关于如何使用不同的下拉菜单更新绘图破折号的主要内容,如果未能解决你的问题,请参考以下文章
如何返回由 2 个下拉列表更新的数据表作为 Plotly Python 中的输入