具有多个下拉输入的 Plotly Dash 图不起作用

osh*_*ira 6 python-3.x plotly-dash

I\xe2\x80\x99m 尝试创建一个具有多个交互式下拉用户输入变量的时间序列虚线图。理想情况下,我希望每个下拉输入都允许进行多项选择。

\n\n

虽然 I\xe2\x80\x99m 能够成功创建下拉菜单,但图表 \xe2\x80\x99t 不会像 I\xe2\x80\x99d 那样更新。当我允许下拉菜单有多个选择时,出现数组长度不同的错误。当我将下拉列表限制为一个选择时,我收到一条错误,指出 [\xe2\x80\x98Vendor_Name\xe2\x80\x99] 不在索引中。所以这可能是两个不同的问题。

\n\n

不起作用的图表\xe2\x80\x99:

\n\n

\n\n

导入 DF 的 Excel 数据片段

\n\n

\n\n
import dash\nimport dash_core_components as dcc\nimport dash_html_components as html\nfrom dash.dependencies import Input, Output\nimport pandas as pd\n#import plotly.graph_objs as go \ndf = pd.read_csv("Data.csv", sep = "\\t")\ndf[\'YearMonth\'] = pd.to_datetime(df[\'YearMonth\'], format = \'%Y-%m\')\ncols = [\'Product_1\', \'Product_2\', \'Product_3\']\nvendor = df[\'Vendor\'].unique()\n\napp = dash.Dash(\'Data\')\n\napp.layout = html.Div([\n    html.Div([\n        html.Div([\n\n            html.Label(\'Product\'),\n            dcc.Dropdown(\n                 id = \'product\',\n                 options = [{\n                         \'label\' : i, \n                         \'value\' : i\n                 } for i in cols],\n                multi = True,\n                value = \'Product_1\'\n\n                 ),\n                ]),\n\n        html.Div([\n\n            html.Label(\'Vendor\'),\n            dcc.Dropdown(\n             id = \'vendor\',\n             options = [{\n                     \'label\' : i, \n                     \'value\' : i\n             } for i in vendor],\n            multi = True,\n             value = \'ABC\')\n             ,\n        ]),\n            ]),\n\n    dcc.Graph(id = \'feature-graphic\')\n    ])\n\n\n@app.callback(Output(\'feature-graphic\', \'figure\'),\n    [Input(\'product\', \'value\'),\n     Input(\'vendor\', \'value\')])\n\n\ndef update_graph(input_vendor, input_column):\n\n\n    df_filtered = df[df[\'Vendor\'] == input_vendor]\n\n##also tried setting an index because of the error I was getting. Not sure if necessary\n    df_filtered = df_filtered.set_index([\'Vendor\']) \n\n    traces = []\n\n    df_by_col = df_filtered[[input_column, \'YearMonth\']]\n\n    traces.append({\n\n        \'x\' :pd.Series(df_by_col[\'YearMonth\']),\n        \'y\' : df_by_col[input_column],\n        \'mode\' : \'lines\',\n        \'type\' : \'scatter\',\n        \'name\' :\'XYZ\'}\n        )\n\n    fig = {\n                    \'data\': traces,\n                    \'layout\': {\'title\': \'Title of Chart\'}\n                    }\n    return fig\n\n\nif __name__ == \'__main__\':\n    app.run_server(debug=False)\n
Run Code Online (Sandbox Code Playgroud)\n\n

预先感谢您的帮助!对于 Python 来说还是个新手,但对 Dash\xe2\x80\x99s 功能非常兴奋。我\xe2\x80\x99已经能够使用单个输入创建其他图形,并且已经阅读了文档。

\n

erk*_*dem 2

1 输入数据

中的数据csv很难循环。我认为这是你的代码不起作用的主要原因,因为你似乎了解基本的代码结构。戴上我的 SQL 眼镜后,我认为你应该尝试让它达到类似的效果

Date, Vendor, ProductName, Value
Run Code Online (Sandbox Code Playgroud)

2 回调输入类型变化

multi很棘手,因为它会改变str在仅选择 1 项时返回 a 和list选择多项时返回 a 之间的切换

3 回调返回类型

您的代码返回 adict但回调声明figure为返回类型

但这里是带有调试痕迹的代码print()sleep()

import pandas as pd
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objs as go
import time

df = pd.read_csv("Data.csv", sep="\t")
df['YearMonth'] = pd.to_datetime(df['YearMonth'], format='%Y-%m')
products = ['Product_1', 'Product_2', 'Product_3']
vendors = df['Vendor'].unique()

app = dash.Dash('Data')

app.layout = html.Div([
    html.Div([
        html.Div([
            html.Label('Product'),
            dcc.Dropdown(
                id='product',
                options=[{'label' : p, 'value' : p} for p in products],
                multi=True,
                value='Product_1'
            ),
        ]),
        html.Div([
            html.Label('Vendor'),
            dcc.Dropdown(
                id='vendor',
                options=[{'label': v, 'value': v} for v in vendors],
                multi=True,
                value='ABC'
            ),
        ]),
    ]),
    dcc.Graph(id='feature-graphic', figure=go.Figure())
])


@app.callback(
    Output('feature-graphic', 'figure'),
    [Input('product', 'value'),
     Input('vendor', 'value')])
def update_graph(input_product, input_vendor):
    # df_filtered[['Product_1', 'YearMonth']]
    if type(input_product) == str:
        input_product = [input_product]
    if type(input_vendor) == str:
        input_vendor= [input_vendor]

    datasets = ['']
    i = 1
    for vendor in input_vendor:
        df_filtered = df[df['Vendor'] == vendor]
        for product in input_product:
            datasets.append((df_filtered[['YearMonth', 'Vendor', product]]).copy())
            datasets[i]['ProductName'] = product
            datasets[i].rename(columns={product: 'Value'}, inplace=True)
            i += 1
    datasets.pop(0)
    print(datasets)

    traces = ['']
    for dataset in datasets:
        print(dataset)
        time.sleep(1)
        traces.append(
            go.Scatter({
                'x': dataset['YearMonth'],
                'y': dataset['Value'],
                'mode': 'lines',
                'name': f"Vendor: {dataset['Vendor'].iloc[0]} Product: {dataset['ProductName'].iloc[0]}"
        }))
    traces.pop(0)
    layout = {'title': 'Title of Chart'}

    fig = {'data': traces, 'layout': go.Layout(layout)}
    return go.Figure(fig)


if __name__ == '__main__':
    app.run_server()
Run Code Online (Sandbox Code Playgroud)

快速而肮脏的披露:

如果你处理了第一个问题,一切都会大大简化。因此,我尝试将pd.DataFrame()回调与上部 I/O 部分隔离。

1)不要在for循环中使用计数器

2)我的变量名也不是最好的

3)以下风格是穴居人的Python和there must be a better way

traces = ['']
traces.append(this_and_that)
traces.pop(0)
Run Code Online (Sandbox Code Playgroud)

一般来说:

使用print(input_variable)print(type(input_variable)) 让我的轮子大部分时间脱离泥浆。

毕竟

您应该注意到,每个trace都有其单独的名称,该名称将显示在图例中。单击图例中的名称将添加或删除,trace无需@app.callback()