Dash 根据用户的图形选择输出多个图形
Dash output multiple graph based on user's graph choice
几天来我一直在努力理解这一点。我要求用户输入 X_axis 数据、Y_axis 数据和他们想要显示的图表。
我的当前版本根据用户的选择只显示一个图表。我希望它能够同时显示多个图形(例如:饼图和折线图)。我添加了 'multi=True' 以选择多个图形(现在注释掉,因为它给出了错误:“回调错误更新 my_graph.figure”,UnboundLocalError:局部变量 'fig' 在赋值前引用 )。我知道我需要从回调函数创建多个输出,但我不知道如何做。有人可以帮帮我吗?谢谢!!
import dash
import dash_core_components as dcc
import dash_html_components as HTML
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
from dash.exceptions import PreventUpdate
df_data = pd.read_json("test.json")
app = dash.Dash(__name__)
app.layout = html.Div([
html.P("Choose data1:"),
dcc.Dropdown(
id='x_axis',
options=[{'value': x, 'label': x}
for x in df_data.keys()],
clearable=False,
style={'width':'40%'}
),
html.P("Choose data2:"),
dcc.Dropdown(
id='y_axis',
options=[{'value': x, 'label': x}
for x in df_data.keys()],
clearable=False,
style={'width':'40%'}
),
html.P("Choose a graph to display:"),
dcc.Dropdown(
id='graph',
options=[{'value': 'pie', 'label': 'Pie chart'},
{'value': 'line', 'label': 'Line chart'},
{'value': 'bar', 'label': 'Bar chart'},
{'value': 'scatter', 'label': 'Scatter chart'},
{'value': '2dhistogram', 'label': '2dhistogram chart'}],
clearable=False,
style={'width':'40%'},
#multi=True
),
dcc.Graph(id='my_graph', figure={}),
])
@app.callback(
Output("my_graph", "figure"),
[Input("x_axis", "value"),
Input("y_axis", "value"),
Input("graph", "value")])
def generate_chart(x_axis, y_axis, graph):
if not x_axis:
raise PreventUpdate
if not y_axis:
raise PreventUpdate
if not graph:
raise PreventUpdate
dff = df_data
if graph=="pie":
fig = px.pie(dff, values=y_axis, names=x_axis, title="Pie Chart")
elif graph=="line":
fig = px.line(dff, x=x_axis, y=y_axis, title="Line Chart")
elif graph=="bar":
fig = px.bar(dff, x=x_axis, y=y_axis, title="Bar Chart")
elif graph=="scatter":
fig = px.scatter(dff, x=x_axis, y=y_axis, title="Scatter Chart")
elif graph=="2dhistogram":
fig = px.density_heatmap(dff, x=x_axis, y=y_axis, nbinsx=20, nbinsy=20,
color_continuous_scale="Viridis", title="2D Histogram Chart")
else:
fig = px.pie(dff, values=y_axis, names=x_axis, title="Pie Chart")
return fig
app.run_server(debug=True)
示例 json 文件:
{
"Names": {
"0": "Alice",
"1": "Robert",
"2": "Garry",
"3": "Nate",
"4": "Karen",
"5": "Nick"
},
"Address": {
"0": "21 Main St",
"1": "19 Third St",
"2": "4 Church St",
"3": "5 High St",
"4": "9 Elm St",
"5": "06 Washingtom St"
},
"AreaCode": {
"0": "777",
"1": "421",
"2": "768",
"3": "345",
"4": "888",
"5": "123"
}}
您已添加 multi=True
以从用户那里获取多个输入,但它仍然不会改变函数只会 return 具有单个绘图的图形对象的事实。
我觉得子图是解决方案。
您可以像这样创建子图
fig = make_subplots(rows=1, cols=len(graph))
counter = 1
然后使用单独的 if 条件并通过使用计数器添加跟踪。
if "scatter" in graph:
fig.add_trace(
go.Scatter(x=dff['x_axis'], y=dff['y_axis']),
row=1, col=counter )
counter += 1
if "pie" in graph:
fig.add_trace(
go.Pie(labels=dff['x_axis'], values=dff['y_axis']),
row=1, col=counter )
counter += 1
...
...
...
好吧,你已经很接近了,你提供的代码工作得很好并且正确地设置了大部分需要的东西! (我首先在下面展示了一些小问题需要更正)
您的工作代码原样 — 一次绘制单个地块
import dash
from dash import dcc
from dash import html
import pandas as pd
import plotly.express as px
from dash.dependencies import Input
from dash.dependencies import Output
from dash.exceptions import PreventUpdate
df_data = pd.read_json("test.json")
app = dash.Dash(__name__)
app.layout = html.Div(
[
html.P("Choose data1:"),
dcc.Dropdown(
id="x_axis",
options=[{"value": x, "label": x} for x in df_data.keys()],
clearable=False,
style={"width": "40%"},
),
html.P("Choose data2:"),
dcc.Dropdown(
id="y_axis",
options=[{"value": x, "label": x} for x in df_data.keys()],
clearable=False,
style={"width": "40%"},
),
html.P("Choose a graph to display:"),
dcc.Dropdown(
id="graph",
options=[
{"value": "pie", "label": "Pie chart"},
{"value": "line", "label": "Line chart"},
{"value": "bar", "label": "Bar chart"},
{"value": "scatter", "label": "Scatter chart"},
{"value": "2dhistogram", "label": "2dhistogram chart"},
],
clearable=False,
style={"width": "40%"},
# multi=True
),
dcc.Graph(id="my_graph", figure={}),
]
)
@app.callback(
Output("my_graph", "figure"),
[
Input("x_axis", "value"),
Input("y_axis", "value"),
Input("graph", "value"),
],
)
def generate_chart(x_axis, y_axis, graph):
if not x_axis:
raise PreventUpdate
if not y_axis:
raise PreventUpdate
if not graph:
raise PreventUpdate
dff = df_data
if graph == "pie":
fig = px.pie(dff, values=y_axis, names=x_axis, title="Pie Chart")
elif graph == "line":
fig = px.line(dff, x=x_axis, y=y_axis, title="Line Chart")
elif graph == "bar":
fig = px.bar(dff, x=x_axis, y=y_axis, title="Bar Chart")
elif graph == "scatter":
fig = px.scatter(dff, x=x_axis, y=y_axis, title="Scatter Chart")
elif graph == "2dhistogram":
fig = px.density_heatmap(
dff,
x=x_axis,
y=y_axis,
nbinsx=20,
nbinsy=20,
color_continuous_scale="Viridis",
title="2D Histogram Chart",
)
else:
fig = px.pie(dff, values=y_axis, names=x_axis, title="Pie Chart")
return fig
app.run_server(debug=True, dev_tools_hot_reload=True)
Dropdown option change:
Dropdown option change & data x, y options change:
我所要做的就是改变几个缩进错误,导入 dash 组件库 html
(小写而不是大写),是的,否则它只需要一点点修复就可以正确缩进(这可能只是复制粘贴到 SO issue 上)——干得好!当然,显示区号饼图没有任何意义,因为它们是标称值,不是真正的定量测量,但就制作相当复杂的交互式 Dash 网络应用程序的原理证明而言,您已将其全部设置好正确的,在我看来。
但是现在对于同时显示多个图表...还需要进行一些更改。
修改代码以实现最多显示 5 个可能的总图
现在这不是 100% 理想(例如,如果不显示空白图表会更好)但希望它能帮助您走上正确的轨道并推进项目的定制
import sys
import dash
from dash import dcc
from dash import html
from dash import no_update
import pandas as pd
import plotly.express as px
from dash.dependencies import Input
from dash.dependencies import Output
from dash.exceptions import PreventUpdate
df_data = pd.read_json("test.json")
app = dash.Dash(__name__)
app.layout = html.Div(
[
html.P("Choose data1:"),
dcc.Dropdown(
id="x_axis",
options=[{"value": x, "label": x} for x in df_data.keys()],
clearable=False,
style={"width": "40%"},
),
html.P("Choose data2:"),
dcc.Dropdown(
id="y_axis",
options=[{"value": x, "label": x} for x in df_data.keys()],
clearable=False,
style={"width": "40%"},
),
html.P("Choose a graph to display:"),
dcc.Dropdown(
id="graph",
options=[
{"value": "pie", "label": "Pie chart"},
{"value": "line", "label": "Line chart"},
{"value": "bar", "label": "Bar chart"},
{"value": "scatter", "label": "Scatter chart"},
{"value": "2dhistogram", "label": "2dhistogram chart"},
],
clearable=True,
style={"width": "40%"},
multi=True,
),
dcc.Graph(id="my_graph_1", figure={}),
dcc.Graph(id="my_graph_2", figure={}),
dcc.Graph(id="my_graph_3", figure={}),
dcc.Graph(id="my_graph_4", figure={}),
dcc.Graph(id="my_graph_5", figure={}),
]
)
@app.callback(
[
Output("my_graph_1", "figure"),
Output("my_graph_2", "figure"),
Output("my_graph_3", "figure"),
Output("my_graph_4", "figure"),
Output("my_graph_5", "figure"),
],
[
Input("x_axis", "value"),
Input("y_axis", "value"),
Input("graph", "value"),
],
)
def generate_chart(x_axis, y_axis, graph):
if not all([x_axis, y_axis]):
raise PreventUpdate
if not graph:
return [{}] * 5
dff = df_data
graphs = []
print(graph, file=sys.stderr) # used for debugging help
if "pie" in graph:
fig = px.pie(dff, values=y_axis, names=x_axis, title="Pie Chart")
graphs.append(fig)
if "line" in graph:
fig = px.line(dff, x=x_axis, y=y_axis, title="Line Chart")
graphs.append(fig)
if "bar" in graph:
fig = px.bar(dff, x=x_axis, y=y_axis, title="Bar Chart")
graphs.append(fig)
if "scatter" in graph:
fig = px.scatter(dff, x=x_axis, y=y_axis, title="Scatter Chart")
graphs.append(fig)
if "2dhistogram" in graph:
fig = px.density_heatmap(
dff,
x=x_axis,
y=y_axis,
nbinsx=20,
nbinsy=20,
color_continuous_scale="Viridis",
title="2D Histogram Chart",
)
graphs.append(fig)
graphs += (5 - len(graphs)) * [{}] # or can use `[no_update]` here
g1, g2, g3, g4, g5 = graphs
return g1, g2, g3, g4, g5
app.run_server(debug=True, dev_tools_hot_reload=True)
如果您对我所做的有任何疑问,请告诉我 — 我认为从代码本身就很容易解释(我基本上只是在布局中再制作了四个图形对象,并且 return 5 个图形在回调中——如果用户没有选择所有五个选项,则所选下拉选项的数量与可能的图表总数(五个)之间的差异是 returned 为“no_update
” 。我将 dcc.Dropdown
的 clearable
参数切换为 true,这允许图形消失。在选择它之后仅删除一个选项不会删除该图形(它只会导致 no_update
被发送),但如果你用下拉列表中的“x”标记清除所有,那么你可以删除所有图表并从新选项开始。我相信你知道,并不是“data1”的所有可能选项和“data2”导致可能的图表。
→ 使用下图红色“x”清除所有:
导致能够尝试不同的选项+图形组合:
几天来我一直在努力理解这一点。我要求用户输入 X_axis 数据、Y_axis 数据和他们想要显示的图表。
我的当前版本根据用户的选择只显示一个图表。我希望它能够同时显示多个图形(例如:饼图和折线图)。我添加了 'multi=True' 以选择多个图形(现在注释掉,因为它给出了错误:“回调错误更新 my_graph.figure”,UnboundLocalError:局部变量 'fig' 在赋值前引用 )。我知道我需要从回调函数创建多个输出,但我不知道如何做。有人可以帮帮我吗?谢谢!!
import dash
import dash_core_components as dcc
import dash_html_components as HTML
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
from dash.exceptions import PreventUpdate
df_data = pd.read_json("test.json")
app = dash.Dash(__name__)
app.layout = html.Div([
html.P("Choose data1:"),
dcc.Dropdown(
id='x_axis',
options=[{'value': x, 'label': x}
for x in df_data.keys()],
clearable=False,
style={'width':'40%'}
),
html.P("Choose data2:"),
dcc.Dropdown(
id='y_axis',
options=[{'value': x, 'label': x}
for x in df_data.keys()],
clearable=False,
style={'width':'40%'}
),
html.P("Choose a graph to display:"),
dcc.Dropdown(
id='graph',
options=[{'value': 'pie', 'label': 'Pie chart'},
{'value': 'line', 'label': 'Line chart'},
{'value': 'bar', 'label': 'Bar chart'},
{'value': 'scatter', 'label': 'Scatter chart'},
{'value': '2dhistogram', 'label': '2dhistogram chart'}],
clearable=False,
style={'width':'40%'},
#multi=True
),
dcc.Graph(id='my_graph', figure={}),
])
@app.callback(
Output("my_graph", "figure"),
[Input("x_axis", "value"),
Input("y_axis", "value"),
Input("graph", "value")])
def generate_chart(x_axis, y_axis, graph):
if not x_axis:
raise PreventUpdate
if not y_axis:
raise PreventUpdate
if not graph:
raise PreventUpdate
dff = df_data
if graph=="pie":
fig = px.pie(dff, values=y_axis, names=x_axis, title="Pie Chart")
elif graph=="line":
fig = px.line(dff, x=x_axis, y=y_axis, title="Line Chart")
elif graph=="bar":
fig = px.bar(dff, x=x_axis, y=y_axis, title="Bar Chart")
elif graph=="scatter":
fig = px.scatter(dff, x=x_axis, y=y_axis, title="Scatter Chart")
elif graph=="2dhistogram":
fig = px.density_heatmap(dff, x=x_axis, y=y_axis, nbinsx=20, nbinsy=20,
color_continuous_scale="Viridis", title="2D Histogram Chart")
else:
fig = px.pie(dff, values=y_axis, names=x_axis, title="Pie Chart")
return fig
app.run_server(debug=True)
示例 json 文件:
{
"Names": {
"0": "Alice",
"1": "Robert",
"2": "Garry",
"3": "Nate",
"4": "Karen",
"5": "Nick"
},
"Address": {
"0": "21 Main St",
"1": "19 Third St",
"2": "4 Church St",
"3": "5 High St",
"4": "9 Elm St",
"5": "06 Washingtom St"
},
"AreaCode": {
"0": "777",
"1": "421",
"2": "768",
"3": "345",
"4": "888",
"5": "123"
}}
您已添加 multi=True
以从用户那里获取多个输入,但它仍然不会改变函数只会 return 具有单个绘图的图形对象的事实。
我觉得子图是解决方案。
您可以像这样创建子图
fig = make_subplots(rows=1, cols=len(graph))
counter = 1
然后使用单独的 if 条件并通过使用计数器添加跟踪。
if "scatter" in graph:
fig.add_trace(
go.Scatter(x=dff['x_axis'], y=dff['y_axis']),
row=1, col=counter )
counter += 1
if "pie" in graph:
fig.add_trace(
go.Pie(labels=dff['x_axis'], values=dff['y_axis']),
row=1, col=counter )
counter += 1
...
...
...
好吧,你已经很接近了,你提供的代码工作得很好并且正确地设置了大部分需要的东西! (我首先在下面展示了一些小问题需要更正)
您的工作代码原样 — 一次绘制单个地块
import dash
from dash import dcc
from dash import html
import pandas as pd
import plotly.express as px
from dash.dependencies import Input
from dash.dependencies import Output
from dash.exceptions import PreventUpdate
df_data = pd.read_json("test.json")
app = dash.Dash(__name__)
app.layout = html.Div(
[
html.P("Choose data1:"),
dcc.Dropdown(
id="x_axis",
options=[{"value": x, "label": x} for x in df_data.keys()],
clearable=False,
style={"width": "40%"},
),
html.P("Choose data2:"),
dcc.Dropdown(
id="y_axis",
options=[{"value": x, "label": x} for x in df_data.keys()],
clearable=False,
style={"width": "40%"},
),
html.P("Choose a graph to display:"),
dcc.Dropdown(
id="graph",
options=[
{"value": "pie", "label": "Pie chart"},
{"value": "line", "label": "Line chart"},
{"value": "bar", "label": "Bar chart"},
{"value": "scatter", "label": "Scatter chart"},
{"value": "2dhistogram", "label": "2dhistogram chart"},
],
clearable=False,
style={"width": "40%"},
# multi=True
),
dcc.Graph(id="my_graph", figure={}),
]
)
@app.callback(
Output("my_graph", "figure"),
[
Input("x_axis", "value"),
Input("y_axis", "value"),
Input("graph", "value"),
],
)
def generate_chart(x_axis, y_axis, graph):
if not x_axis:
raise PreventUpdate
if not y_axis:
raise PreventUpdate
if not graph:
raise PreventUpdate
dff = df_data
if graph == "pie":
fig = px.pie(dff, values=y_axis, names=x_axis, title="Pie Chart")
elif graph == "line":
fig = px.line(dff, x=x_axis, y=y_axis, title="Line Chart")
elif graph == "bar":
fig = px.bar(dff, x=x_axis, y=y_axis, title="Bar Chart")
elif graph == "scatter":
fig = px.scatter(dff, x=x_axis, y=y_axis, title="Scatter Chart")
elif graph == "2dhistogram":
fig = px.density_heatmap(
dff,
x=x_axis,
y=y_axis,
nbinsx=20,
nbinsy=20,
color_continuous_scale="Viridis",
title="2D Histogram Chart",
)
else:
fig = px.pie(dff, values=y_axis, names=x_axis, title="Pie Chart")
return fig
app.run_server(debug=True, dev_tools_hot_reload=True)
Dropdown option change:
Dropdown option change & data x, y options change:
我所要做的就是改变几个缩进错误,导入 dash 组件库 html
(小写而不是大写),是的,否则它只需要一点点修复就可以正确缩进(这可能只是复制粘贴到 SO issue 上)——干得好!当然,显示区号饼图没有任何意义,因为它们是标称值,不是真正的定量测量,但就制作相当复杂的交互式 Dash 网络应用程序的原理证明而言,您已将其全部设置好正确的,在我看来。
但是现在对于同时显示多个图表...还需要进行一些更改。
修改代码以实现最多显示 5 个可能的总图
现在这不是 100% 理想(例如,如果不显示空白图表会更好)但希望它能帮助您走上正确的轨道并推进项目的定制
import sys
import dash
from dash import dcc
from dash import html
from dash import no_update
import pandas as pd
import plotly.express as px
from dash.dependencies import Input
from dash.dependencies import Output
from dash.exceptions import PreventUpdate
df_data = pd.read_json("test.json")
app = dash.Dash(__name__)
app.layout = html.Div(
[
html.P("Choose data1:"),
dcc.Dropdown(
id="x_axis",
options=[{"value": x, "label": x} for x in df_data.keys()],
clearable=False,
style={"width": "40%"},
),
html.P("Choose data2:"),
dcc.Dropdown(
id="y_axis",
options=[{"value": x, "label": x} for x in df_data.keys()],
clearable=False,
style={"width": "40%"},
),
html.P("Choose a graph to display:"),
dcc.Dropdown(
id="graph",
options=[
{"value": "pie", "label": "Pie chart"},
{"value": "line", "label": "Line chart"},
{"value": "bar", "label": "Bar chart"},
{"value": "scatter", "label": "Scatter chart"},
{"value": "2dhistogram", "label": "2dhistogram chart"},
],
clearable=True,
style={"width": "40%"},
multi=True,
),
dcc.Graph(id="my_graph_1", figure={}),
dcc.Graph(id="my_graph_2", figure={}),
dcc.Graph(id="my_graph_3", figure={}),
dcc.Graph(id="my_graph_4", figure={}),
dcc.Graph(id="my_graph_5", figure={}),
]
)
@app.callback(
[
Output("my_graph_1", "figure"),
Output("my_graph_2", "figure"),
Output("my_graph_3", "figure"),
Output("my_graph_4", "figure"),
Output("my_graph_5", "figure"),
],
[
Input("x_axis", "value"),
Input("y_axis", "value"),
Input("graph", "value"),
],
)
def generate_chart(x_axis, y_axis, graph):
if not all([x_axis, y_axis]):
raise PreventUpdate
if not graph:
return [{}] * 5
dff = df_data
graphs = []
print(graph, file=sys.stderr) # used for debugging help
if "pie" in graph:
fig = px.pie(dff, values=y_axis, names=x_axis, title="Pie Chart")
graphs.append(fig)
if "line" in graph:
fig = px.line(dff, x=x_axis, y=y_axis, title="Line Chart")
graphs.append(fig)
if "bar" in graph:
fig = px.bar(dff, x=x_axis, y=y_axis, title="Bar Chart")
graphs.append(fig)
if "scatter" in graph:
fig = px.scatter(dff, x=x_axis, y=y_axis, title="Scatter Chart")
graphs.append(fig)
if "2dhistogram" in graph:
fig = px.density_heatmap(
dff,
x=x_axis,
y=y_axis,
nbinsx=20,
nbinsy=20,
color_continuous_scale="Viridis",
title="2D Histogram Chart",
)
graphs.append(fig)
graphs += (5 - len(graphs)) * [{}] # or can use `[no_update]` here
g1, g2, g3, g4, g5 = graphs
return g1, g2, g3, g4, g5
app.run_server(debug=True, dev_tools_hot_reload=True)
如果您对我所做的有任何疑问,请告诉我 — 我认为从代码本身就很容易解释(我基本上只是在布局中再制作了四个图形对象,并且 return 5 个图形在回调中——如果用户没有选择所有五个选项,则所选下拉选项的数量与可能的图表总数(五个)之间的差异是 returned 为“no_update
” 。我将 dcc.Dropdown
的 clearable
参数切换为 true,这允许图形消失。在选择它之后仅删除一个选项不会删除该图形(它只会导致 no_update
被发送),但如果你用下拉列表中的“x”标记清除所有,那么你可以删除所有图表并从新选项开始。我相信你知道,并不是“data1”的所有可能选项和“data2”导致可能的图表。