我想在 plotly 中创建一个双下拉列表。我应该可以选择预测的年份和条件。
这里是数据集:Collisions和Forecast
我的数据集是这样的:
第一:碰撞
我从 2013 年到 2022 年按年、月和日分组的地方
然后预测
我已经能够用一年做到这一点,但是我不能用 2 个 dropdwon 列表做到这一点,我无法理解为什么我的代码不起作用背后的逻辑。
基本上我想添加另一个下拉列表,我可以在其中选择年份。
这是我创建一个有效下拉列表的代码:
fig = make_subplots(rows=6, cols=2, specs=[[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
])
# condition = "snow"
colors = {"Collisions": "#FFA07A",
"tempmax": "#FF0000",
"tempmin": "#00FF00",
"temp": "#7EC0EE",
"humidity": "#808080",
"precip": "#FFC0CB",
"snow": "#800080",
"visibility": "#FFA500",
}
forecast = list(df_brook_fore.columns[1:])
months = list(range(1,13))
for i, mon in enumerate(months):
for j, condition in enumerate(forecast):
column_idx = 1 if i%2==0 else 2
row_idx = i//2+1
days = list(range(1, len(df_brook_fil_group[1]) + 1))
fig.add_trace(go.Bar(x=days, y=df_brook_fil_group[mon], marker_color=colors["Collisions"], visible=(j == 0),
name='Collisions' if i == 0 else '', showlegend=True if i == 0 else False),
row=row_idx, col=column_idx)
fig.add_trace(go.Scatter(x=days, y=df_brook_fore[condition][mon], visible=(j == 0),
marker_color=colors[condition], name=condition if i == 0 else '',
showlegend=True if i == 0 else False), row=row_idx, col=column_idx, secondary_y=True)
fig.update_yaxes(title_text="Collisions", row=row_idx, col=column_idx, secondary_y=False, showgrid=False)
fig.update_yaxes(title_text="Visibility", row=row_idx, col=column_idx, secondary_y=True, showgrid=False)
fig.update_layout(width=1000, height=1200, coloraxis=dict(colorscale='Bluered_r'), showlegend=True)
fig.update_layout(
updatemenus=[
dict(
active=0,
buttons=list([
dict(label=condition, method="update", args=[{"visible": [((j == i*2) or (j == i*2+1)) for j in range(
len(forecast)*2)]}, {"title": "Normalized Collision Count by Hour for " + condition}])
for i, condition in enumerate(forecast)
]),
x=0.05, y=1.1, xanchor="left", yanchor="top"
)
],
title_text="Normalized Collision Count by Hour for " + forecast[0],
title_x=0.5
)
fig.show()
这是我尝试创建 2 个下拉列表的代码。我很确定问题出在下拉按钮的可见选项中,但我现在不知道如何解决它。
fig = make_subplots(rows=6, cols=2, specs=[[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
])
# condition = "snow"
colors = {"Collisions": "#FFA07A",
"tempmax": "#FF0000",
"tempmin": "#00FF00",
"temp": "#7EC0EE",
"humidity": "#808080",
"precip": "#FFC0CB",
"snow": "#800080",
"visibility": "#FFA500",
}
forecast = list(df_brook_fore.columns[1:])
months = list(range(1,13))
years = list(df_brook_fore.index.get_level_values(0).unique())
for i, mon in enumerate(months):
for k, year in enumerate(years):
for j, condition in enumerate(forecast):
column_idx = 1 if i%2==0 else 2
row_idx = i//2+1
days = list(range(1, len(df_brook_fil_group[year][mon]) + 1))
fig.add_trace(go.Bar(x=days, y=df_brook_fil_group[year][mon], marker_color=colors["Collisions"], visible=(j == 0) and (k==0),
name='Collisions' if i == 0 else '', showlegend=True if i == 0 else False),
row=row_idx, col=column_idx)
fig.add_trace(go.Scatter(x=days, y=df_brook_fore.loc[year, mon][condition], visible=(j == 0),
marker_color=colors[condition], name=condition if i == 0 else '',
showlegend=True if i == 0 else False), row=row_idx, col=column_idx, secondary_y=True)
fig.update_yaxes(title_text="Collisions", row=row_idx, col=column_idx, secondary_y=False, showgrid=False)
fig.update_yaxes(title_text="Visibility", row=row_idx, col=column_idx, secondary_y=True, showgrid=False)
fig.update_layout(width=1000, height=1200, coloraxis=dict(colorscale='Bluered_r'), showlegend=True)
fig.update_layout(
updatemenus=[
dict(
active=0,
buttons=list([
dict(label=condition, method="update", args=[{"visible": [((j == i*2) or (j == i*2+1)) for j in range(
len(forecast)*2)]}, {"title": "Normalized Collision Count by Hour for " + condition}])
for i, condition in enumerate(forecast)
]),
x=0.2, y=1.1, xanchor="left", yanchor="top"
),
dict(
active=0,
buttons=list([
dict(label=str(year), method="update", args=[{"visible": [((j == i*2) or (j == i*2+1)) for j in range(
len(years)*2)]}, {"title": "Normalized Collision Count by Hour for " + str(years)}])
for i, year in enumerate(years)
]),
x=0.05, y=1.1, xanchor="left", yanchor="top"
)
],
title_text="Normalized Collision Count by Hour for " + str(years[0]),
title_x=0.5
)
fig.show()
感谢您的帮助!
看完你的代码后,我认为使用
Dash
会完成几件事:(1)它允许两个下拉菜单同时响应,(2)通过使用回调函数,你可以选择数据你需要实时绘制。不需要在开始时绘制所有轨迹,然后根据下拉选择找出哪些应该或不应该可见(我相信你注意到了,这变得非常复杂并且很难跟踪您何时需要处理年、月和不同的预测列)。
下面是一个示例,说明您可以使用 Dash 和回调函数来处理来自两个下拉菜单的输入:
import pandas as pd
from plotly.subplots import make_subplots
import plotly.express as px
import plotly.graph_objects as go
from dash import Dash, dcc, html, Input, Output
df_brook_fil_group = pd.read_csv('colisions.csv')
df_brook_fil_group = df_brook_fil_group.set_index(['Year','Month','Day'])
df_brook_fore = pd.read_csv('forecast.csv')
df_brook_fore = df_brook_fore.set_index(['Year','Month','Day'])
forecast = list(df_brook_fore.columns[1:])
fig = make_subplots(rows=6, cols=2, specs=[[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
])
# condition = "snow"
colors = {"Collisions": "#FFA07A",
"tempmax": "#FF0000",
"tempmin": "#00FF00",
"temp": "#7EC0EE",
"humidity": "#808080",
"precip": "#FFC0CB",
"snow": "#800080",
"visibility": "#FFA500",
}
app = Dash(__name__)
app.layout = html.Div(
[
html.Div(
[
dcc.Dropdown(
id="year-dropdown",
options=[2014, 2015],
value=2014,
placeholder="Select year",
style={"display": "inline-block", "width": "180px"},
),
dcc.Dropdown(
id="forecast-dropdown",
options=forecast,
value="tempmin",
placeholder="Select your forecast column",
style={"display": "inline-block", "width": "180px"},
),
],
style={"padding": "80px"},
),
dcc.Graph(figure=fig, id='scatter-bar-chart')
]
)
@app.callback(
Output('scatter-bar-chart', 'figure'),
Input('year-dropdown', 'value'),
Input('forecast-dropdown', 'value'),
)
def update_output(year, forecast):
df_brook_fil_group_subset = df_brook_fil_group.loc[year,:,:]
df_brook_fore_subset = df_brook_fore.loc[year,:,:]
months = list(range(1,13))
## create subplots based on how many months there are
fig = make_subplots(rows=6, cols=2, specs=[[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
])
row, col = 1, 1
for i, mon in enumerate(months):
df_brook_fil_group_month = df_brook_fil_group_subset.loc[mon,:]
df_brook_fore_month = df_brook_fore_subset.loc[mon,:]
df_brook_fil_group_days = df_brook_fil_group_month.index.get_level_values('Day')
df_brook_fore_month_days = df_brook_fore_month.index.get_level_values('Day')
## use legendgroups to ensure entries only show up once
fig.add_trace(go.Bar(x=df_brook_fil_group_days, y=df_brook_fil_group_month['COLLISION_ID'],
marker_color=colors["Collisions"],
showlegend=True if i == 0 else False,
name='Collisions', legendgroup='Collisions'),
row=row, col=col)
fig.add_trace(go.Scatter(x=df_brook_fore_month_days, y=df_brook_fore_month[forecast],
marker_color=colors[forecast], name=forecast if i == 0 else '',
showlegend=True if i == 0 else False,
legendgroup=forecast),
row=row, col=col, secondary_y=True)
fig.update_yaxes(title_text="Collisions", row=row, col=col, secondary_y=False, showgrid=False)
fig.update_yaxes(title_text="Visibility", row=row, col=col, secondary_y=True, showgrid=False)
fig.update_layout(
width=1000, height=1200,
coloraxis=dict(colorscale='Bluered_r'), showlegend=True,
title_text="Normalized Collision Count by Hour for " + str(year),
title_x=0.5
)
# iterate through (1,1),(1,2),(2,1),(2,2),(3,1),(3,2), ... to place the bar + scatter traces
if i % 2 == 0:
col += 1
else:
row += 1
if col == 1:
col = 2
if col == 2:
col = 1
return fig
if __name__ == '__main__':
app.run_server(debug=True)
破折号应用程序响应年份和预测类型的下拉列表:
注意:由于文件大小,我无法显示应用程序的所有 6 行