使用Dash与Plotly图形对象及日期选择器实现多轨迹图表默认全量加载与更新
问题描述
我是Dash新手,需要使用DatePickerRange组件在单个图表中绘制多条Plotly轨迹,需求如下:
- 未选择任何日期范围时,页面加载自动绘制全量数据;
- 选择日期范围后,更新图表中的两条轨迹。
目前日期选择器可正常工作,但存在两个问题:
- 未选择日期时图表为空白;
- 选择日期范围后,所选数据会叠加在全量数据之上。
附上当前代码:
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 import numpy as np # 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)
解决方案
问题根源在于:
- 初始化时创建的全局
fig未传入图表组件,且回调未处理无日期选择的情况,导致页面加载时图表空白; - 回调复用全局
fig并持续添加新轨迹,导致数据叠加。
修改后的代码如下:
import pandas as pd from dash import Dash, html, dcc import plotly.graph_objects as go from dash.dependencies import Input, Output from plotly.subplots import make_subplots import numpy as np 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] 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'), ] ) @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): # 无日期选择时使用全量数据 if not start_date or not end_date: filtered_df = test_df else: filtered_df = test_df.loc[(test_df.index >= start_date) & (test_df.index <= end_date), :] # 每次回调创建新图表,避免轨迹叠加 fig = make_subplots(specs=[[{"secondary_y": True}]]) # 添加第一条轨迹(左侧Y轴) fig.add_trace( go.Scatter(x=filtered_df.index, y=filtered_df['pop 1'], name="pop 1"), secondary_y=False ) # 添加第二条轨迹(右侧Y轴) fig.add_trace( go.Scatter(x=filtered_df.index, y=filtered_df['pop 2'], name="pop 2"), secondary_y=True ) # 优化图表布局 fig.update_layout(title='Population Trend', xaxis_title='Date') fig.update_yaxes(title_text='Population 1', secondary_y=False) fig.update_yaxes(title_text='Population 2', secondary_y=True) return fig if __name__=='__main__': app.run(debug=True)
关键修改点
- 移除全局
fig:每次回调生成新的图表对象,彻底解决轨迹叠加问题; - 处理默认场景:无日期选择时直接返回全量数据图表,页面加载自动显示完整内容;
- 简化组件初始化:图表组件无需预设空
figure,回调自动返回初始图表; - 优化布局可读性:添加轴标题和图表标题,提升用户体验。
内容的提问来源于stack exchange,提问作者BERNARD FIRANSKI
相关产品推荐
相关产品推荐

