You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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)
解决方案

问题根源在于:

  1. 初始化时创建的全局fig未传入图表组件,且回调未处理无日期选择的情况,导致页面加载时图表空白;
  2. 回调复用全局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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 23:33:21