如何在Plotly Dash中基于用户选择的时间戳范围更新图表?
问题:在Dash中实现精确到时分秒的时间戳范围选择
我正在用Python的Plotly Dash开发交互式仪表盘,其中有个折线图需要根据用户选择的时间范围更新。目前已经实现了dcc.DatePickerRange组件来按日期范围更新图表,但找不到支持精确到时分秒的时间戳范围选择的选项,查文档和社区也没结果,想知道能不能在Dash里实现“从[时间戳]到[时间戳]”的范围选择来替代日期选择器。
数据集片段:
timestamp date id lat lon mode temperature 0 2022-04-01 13:48:38 2022-04-01 15 52.5170365 13.3888599 AUTO 33 1 2022-04-01 13:48:40 2022-04-01 15 52.5170365 13.3888599 AUTO 33 2 2022-04-01 13:48:42 2022-04-01 15 52.5170365 13.3888599 AUTO 33 3 2022-04-02 13:49:18 2022-04-02 15 52.5170375 13.3888605 AUTO 30 4 2022-04-02 13:49:34 2022-04-02 15 52.5170375 13.3888605 AUTO 30 5 2022-04-02 13:49:52 2022-04-02 15 52.5170375 13.3888605 AUTO 30 6 2022-04-03 13:50:10 2022-04-03 15 52.5170385 13.3888609 AUTO 31 7 2022-04-03 13:50:46 2022-04-03 15 52.5170385 13.3888609 AUTO 31 8 2022-04-04 13:51:24 2022-04-04 15 52.5170395 13.3888614 AUTO 34 9 2022-04-04 13:51:46 2022-04-04 15 52.5170395 13.3888614 AUTO 34
已实现的日期选择器代码:
import pandas as pd from datetime import datetime as dt from datetime import date import dash import dash_daq as daq from dash import dcc, html, Input, Output, State import dash_bootstrap_components as dbc from jupyter_dash import JupyterDash import plotly.express as px import plotly.graph_objects as go # df = # 上述数据集 app = JupyterDash(__name__) app.layout = html.Div( [ dcc.DatePickerRange( id="date_filter", initial_visible_month=dt(dt.today().year, 8, 1).date(), start_date=df['date'].min(), end_date=df['date'].max(), show_outside_days=True, day_size=32, display_format='DD/MM/YYYY', clearable=True, style={'text-align':'left', 'width': '6', 'font-size': '10'} ), dcc.Graph(id="graph"), ] ) @app.callback( Output("graph", "figure"), Input("date_filter", "start_date"), Input("date_filter", "end_date"), ) def updateGraph(start_date, end_date): if not start_date or not end_date: raise dash.exceptions.PreventUpdate else: return px.line( df.loc[ df["date"].between( pd.to_datetime(start_date), pd.to_datetime(end_date) ) ], x="date", y="temperature", ) # 在笔记本中运行并显示结果 app.run_server(mode="inline")
解决方案
Dash原生组件没有直接的“时间戳范围选择器”,但可以通过以下两种方式实现精确到时分秒的时间范围筛选:
方法1:使用两个dcc.Input组件(类型为datetime-local)
利用HTML5的datetime-local输入类型,让用户可以选择包含时分秒的时间戳,再通过回调实现范围筛选。
修改后的完整代码:
import pandas as pd from datetime import datetime as dt import dash from dash import dcc, html, Input, Output from jupyter_dash import JupyterDash import plotly.express as px # 加载数据集,确保timestamp列转为datetime类型 df = pd.read_csv("your_data.csv") # 替换为你的数据加载方式 df['timestamp'] = pd.to_datetime(df['timestamp']) app = JupyterDash(__name__) app.layout = html.Div( [ html.Div([ html.Label("开始时间戳:"), dcc.Input( id="start_timestamp", type="datetime-local", value=df['timestamp'].min().strftime('%Y-%m-%dT%H:%M:%S'), style={"margin-right": "20px"} ), html.Label("结束时间戳:"), dcc.Input( id="end_timestamp", type="datetime-local", value=df['timestamp'].max().strftime('%Y-%m-%dT%H:%M:%S') ) ], style={"margin-bottom": "20px"}), dcc.Graph(id="graph"), ] ) @app.callback( Output("graph", "figure"), Input("start_timestamp", "value"), Input("end_timestamp", "value"), ) def updateGraph(start_timestamp, end_timestamp): if not start_timestamp or not end_timestamp: raise dash.exceptions.PreventUpdate # 转换为datetime对象 start = pd.to_datetime(start_timestamp) end = pd.to_datetime(end_timestamp) # 筛选时间范围内的数据 filtered_df = df.loc[df["timestamp"].between(start, end)] return px.line(filtered_df, x="timestamp", y="temperature") app.run_server(mode="inline")
说明:
datetime-local类型的输入框会弹出带时间选择的日历,支持精确到分钟(部分浏览器支持秒级选择)- 需要将
timestamp列转为datetime类型,确保筛选逻辑正确 - 初始值通过
strftime('%Y-%m-%dT%H:%M:%S')格式化,符合datetime-local的输入格式要求
方法2:使用dash-bootstrap-components的DatePickerRange结合时间输入框
如果希望保留日历选择的交互,同时补充时间输入,可以将日期选择器和时间输入框组合,拼接成完整的时间戳。
示例代码片段:
import dash_bootstrap_components as dbc app.layout = html.Div( [ dbc.Row([ dbc.Col(dcc.DatePickerRange( id="date_range", start_date=df['date'].min(), end_date=df['date'].max(), display_format='DD/MM/YYYY' ), width=6), dbc.Col([ html.Div([ html.Label("开始时间:"), dcc.Input(id="start_time", type="time", value="00:00:00") ]), html.Div([ html.Label("结束时间:"), dcc.Input(id="end_time", type="time", value="23:59:59") ]) ], width=6) ], style={"margin-bottom": "20px"}), dcc.Graph(id="graph"), ] ) @app.callback( Output("graph", "figure"), Input("date_range", "start_date"), Input("date_range", "end_date"), Input("start_time", "value"), Input("end_time", "value"), ) def updateGraph(start_date, end_date, start_time, end_time): if not start_date or not end_date or not start_time or not end_time: raise dash.exceptions.PreventUpdate # 拼接日期和时间为完整时间戳 start_timestamp = pd.to_datetime(f"{start_date} {start_time}") end_timestamp = pd.to_datetime(f"{end_date} {end_time}") filtered_df = df.loc[df["timestamp"].between(start_timestamp, end_timestamp)] return px.line(filtered_df, x="timestamp", y="temperature")
说明:
- 这种方式兼顾了日期选择的便捷性和时间精度的需求
- 通过
dcc.Input(type="time")组件获取时分秒,和日期选择器的结果拼接成完整时间戳
内容的提问来源于stack exchange,提问作者ctrl_z
相关产品推荐
相关产品推荐

