简体   繁体   English

根据用户的图形选择,Dash 输出多个图形

[英]Dash output multiple graph based on user's graph choice

I've been trying to understand this for days.几天来我一直试图理解这一点。 I'm asking a user to input X_axis data, Y_axis data, and a graph they want to display.我要求用户输入 X_axis 数据、Y_axis 数据和他们想要显示的图形。

My current version displays only one graph based on the user's choice.我当前的版本仅根据用户的选择显示一张图表。 I want it to be able to display multiple graphs simultaneously(ex: pie and line charts).我希望它能够同时显示多个图形(例如:饼图和折线图)。 I added 'multi=True' to have an option to choose multiple graphs(commented out right now as it gives the error: "Callback error updating my_graph.figure", UnboundLocalError: local variable 'fig' referenced before assignment ).我添加了 'multi=True' 来选择多个图形(现在注释掉,因为它给出了错误: “回调错误更新 my_graph.figure”,UnboundLocalError:分配之前引用的局部变量 'fig' )。 I know I need to create multiple Outputs from the callback functions but I can't figure out how.我知道我需要从回调函数创建多个输出,但我不知道如何。 Can someone please help me out?有人可以帮我吗? Thanks!!谢谢!!

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)

Sample json file:示例 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"
}}

You have added multi=True to get multiple inputs from the user, it still doesn't change the fact that the function will only return a figure object with a single plot.您已经添加了multi=True来从用户那里获得多个输入,它仍然没有改变这个函数只会返回一个带有单个绘图的图形对象的事实。

I feel subplots is the solution.我觉得子图是解决方案。

You can create subplots like this你可以像这样创建子图

fig = make_subplots(rows=1, cols=len(graph))
counter = 1

Then use individual if conditions and add traces, by using a counter.然后使用单独的 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
         ...
         ...
         ...

You were super close.你非常接近。 I got the following code to work, making just a few minor changes to what you provided:我得到了以下代码,对您提供的内容进行了一些小的更改:

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)

饼图名称区号 分散姓名区号 热图地址区号

All I had to change were a couple indentation mistakes, the importing of the dash component library html (lower case not upper), and yeah otherwise it just needed a little fixing as far as proper indentation — great job!我只需要改变几个缩进错误,导入破折号组件库html (小写而不是大写),是的,否则它只需要稍微修复一下适当的缩进 - 太棒了! Of course it doesn't really make any sense to display pie charts for area codes because they are nominal values, not truly quantitative measurements, but as far as proof of principle you set it up all correctly, it seems to me.当然,显示区域代码的饼图并没有任何意义,因为它们是名义值,不是真正的定量测量,但就原理证明而言,您设置的一切正确,在我看来。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM