使用 Dash 的新功能,需要使用日期选择器组件在单个图中绘制多个绘图轨迹。寻找展示如何执行以下操作的示例:
现在日期选择器可以工作,但在选择日期范围之前绘图是空白的。 此外,选择日期范围后,绘图将覆盖所选数据下方的完整数据。
import pandas as pd
from dash import Dash, html, dcc
from dash.exceptions import PreventUpdate
import plotly.graph_objects as go
from dash.dependencies import Input, Output
from plotly.subplots import make_subplots
# initialize the dash app as 'app'
app = Dash(__name__)
population_1=1e7+50*np.arange(61)
population_2=1e8+5*np.arange(61)**2
test_df=pd.DataFrame(data={'pop 1':population_1, 'pop 2': population_2})
test_df.index=pd.date_range(start='2000-01-01', end='2000-03-01')
# use specs parameter in make_subplots function
# to create secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
# plot a scatter chart by specifying the x and y values
# Use add_trace function to specify secondary_y axes.
fig.add_trace(
go.Scatter(x=test_df.index, y=test_df['pop 1'], name="pop 1"),
secondary_y=False)
# Use add_trace function and specify secondary_y axes = True.
fig.add_trace(
go.Scatter(x=test_df.index, y=test_df['pop 2'], name="pop 2"),
secondary_y=True,)
beginning_date=test_df.index[0]
ending_date=test_df.index[-1]
# set up the app layout
app.layout = html.Div(children=
[
html.H1(children=['Test Daframe Dashboard']),
html.Div(children=['Population plotting with year picker']),
dcc.DatePickerRange(
id='my-date-picker-range',
min_date_allowed=beginning_date,
max_date_allowed=ending_date
),
dcc.Graph(id='population-plot',figure={}),
]
)
@app.callback(
Output('population-plot', 'figure'),
Input('my-date-picker-range', 'start_date'),
Input('my-date-picker-range', 'end_date'))
def update_output(start_date, end_date):
print (start_date, end_date)
if not start_date or not end_date:
raise PreventUpdate
else:
output_selected_df=test_df.loc[(test_df.index>=start_date)&(test_df.index<=end_date),:]
fig.add_trace(
go.Scatter(x=output_selected_df.index, y=output_selected_df['pop 1'], name="pop 1"),
secondary_y=False)
# Use add_trace function and specify secondary_y axes = True.
fig.add_trace(
go.Scatter(x=output_selected_df.index, y=output_selected_df['pop 2'], name="pop 2"),
secondary_y=True,)
return fig
if __name__=='__main__':
app.run(debug=True)
解决此问题的一种方法是创建一个函数来管理图形创建,然后将其用于初始加载和回调。您可以在函数外部按日期过滤数据帧,也可以将日期参数传递到函数并在内部进行过滤。
我创建了
create_figure
来演示这个解决方案。在您的示例中,您正在过滤回调内的 test_df
,因此该函数只需将数据帧作为参数即可。
def create_figure(df):
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(
go.Scatter(x=df.index, y=df["pop 1"], name="pop 1"), secondary_y=False
)
fig.add_trace(
go.Scatter(x=df.index, y=df["pop 2"], name="pop 2"),
secondary_y=True,
)
return fig
当您最初创建 dcc.Graph 时,您可以使用该函数创建图形并将完整的数据帧传递给该函数。
dcc.Graph(id="population-plot", figure=create_figure(test_df)),
布局初始化时,图形将接收图形。要防止回调在页面加载时触发,请将
prevent_initial_call=True
添加到回调参数中。
最后,在回调中调用
create_figure(output_selected_df)
来创建过滤后的图表。
完整代码如下:
import pandas as pd
import numpy as np
from dash import Dash, html, dcc
from dash.exceptions import PreventUpdate
import plotly.graph_objects as go
from dash.dependencies import Input, Output
from plotly.subplots import make_subplots
# initialize the dash app as 'app'
app = Dash(__name__)
population_1 = 1e7 + 50 * np.arange(61)
population_2 = 1e8 + 5 * np.arange(61) ** 2
test_df = pd.DataFrame(data={"pop 1": population_1, "pop 2": population_2})
test_df.index = pd.date_range(start="2000-01-01", end="2000-03-01")
beginning_date = test_df.index[0]
ending_date = test_df.index[-1]
def create_figure(df):
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(
go.Scatter(x=df.index, y=df["pop 1"], name="pop 1"), secondary_y=False
)
fig.add_trace(
go.Scatter(x=df.index, y=df["pop 2"], name="pop 2"), secondary_y=True,
)
return fig
# set up the app layout
app.layout = html.Div(
children=[
html.H1(children=["Test Dataframe Dashboard"]),
html.Div(children=["Population plotting with year picker"]),
dcc.DatePickerRange(
id="my-date-picker-range",
min_date_allowed=beginning_date,
max_date_allowed=ending_date,
),
dcc.Graph(id="population-plot", figure=create_figure(test_df)),
]
)
@app.callback(
Output("population-plot", "figure"),
Input("my-date-picker-range", "start_date"),
Input("my-date-picker-range", "end_date"),
prevent_initial_call=True
)
def update_output(start_date, end_date):
print(start_date, end_date)
if not start_date or not end_date:
raise PreventUpdate
else:
output_selected_df = test_df.loc[
(test_df.index >= start_date) & (test_df.index <= end_date), :
]
return create_figure(output_selected_df)
if __name__ == "__main__":
app.run(debug=True)