我正在尝试创建一个具有多个交互式下拉用户输入变量的时序Dash折线图。理想情况下,我希望每个下拉输入都可以进行多项选择。
虽然我可以成功创建下拉菜单,但是图表并没有按照我的意愿进行更新。当我允许下拉菜单有多个选择时,我得到一个错误,即数组的长度不同。当我将下拉列表限制为一个选项时,我得到一个错误,即['Vendor_Name']不在索引中。因此,这可能是两个单独的问题。
无效的图形:
导入到DF中的Excel数据片段
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd
#import plotly.graph_objs as go
df = pd.read_csv("Data.csv", sep = "\t")
df['YearMonth'] = pd.to_datetime(df['YearMonth'], format = '%Y-%m')
cols = ['Product_1', 'Product_2', 'Product_3']
vendor = df['Vendor'].unique()
app = dash.Dash('Data')
app.layout = html.Div([
html.Div([
html.Div([
html.Label('Product'),
dcc.Dropdown(
id = 'product',
options = [{
'label' : i,
'value' : i
} for i in cols],
multi = True,
value = 'Product_1'
),
]),
html.Div([
html.Label('Vendor'),
dcc.Dropdown(
id = 'vendor',
options = [{
'label' : i,
'value' : i
} for i in vendor],
multi = True,
value = 'ABC')
,
]),
]),
dcc.Graph(id = 'feature-graphic')
])
@app.callback(Output('feature-graphic', 'figure'),
[Input('product', 'value'),
Input('vendor', 'value')])
def update_graph(input_vendor, input_column):
df_filtered = df[df['Vendor'] == input_vendor]
##also tried setting an index because of the error I was getting. Not sure if necessary
df_filtered = df_filtered.set_index(['Vendor'])
traces = []
df_by_col = df_filtered[[input_column, 'YearMonth']]
traces.append({
'x' :pd.Series(df_by_col['YearMonth']),
'y' : df_by_col[input_column],
'mode' : 'lines',
'type' : 'scatter',
'name' :'XYZ'}
)
fig = {
'data': traces,
'layout': {'title': 'Title of Chart'}
}
return fig
if __name__ == '__main__':
app.run_server(debug=False)
提前感谢您的帮助!仍然是Python的新手,但对Dash的功能感到非常兴奋。我已经能够使用单个输入创建其他图形,并已阅读了文档。
答案 0 :(得分:1)
这是我遵循的方法:(用我的方法编辑google中可用的常见示例):
[1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
解决方法是::当父项下拉列表中存在单个输入时,该值将为字符串格式。但是对于多个值,它采用列表格式。
即使您单击交叉选项以删除任何选定的选项,此代码也可以完美工作并自动更新。
注意:我使用了“占位符”属性,而不是为其定义默认值,因为在这种情况下,它毫无意义。但是您也可以通过类似的方式动态更新该值。
答案 1 :(得分:0)
csv
中的数据很难循环。
我认为这是您的代码无法正常工作的主要原因,
因为您似乎了解基本的代码结构。
戴上我的SQL眼镜后,我认为您应该尝试使其像
Date, Vendor, ProductName, Value
multi
之所以棘手,是因为它改变了切换(在仅选择一项的情况下返回str
与在选择多项的情况下返回list
之间的切换)
您的代码返回了dict
,但回调函数声明了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()
如果您处理 1。问题,它将大大简化一切。
因此,我尝试将pd.DataFrame()
玩弄的东西从回调中分离出来,进入上层I / O部分。
1)不要在for循环中使用计数器
2)我的变量名也不是最好的
3)以下样式是穴居人的python和there must be a better way
:
traces = ['']
traces.append(this_and_that)
traces.pop(0)
使用print(input_variable)
和print(type(input_variable))
大部分时间使我的车轮脱离泥泞。
您应该注意,每个trace
都有其自己的名称,该名称将显示在图例中。单击图例中的名称将添加或删除trace
,而无需@app.callback()