如何在Dash应用中同时添加日期与时间范围选择器
解决方案:为Dash应用添加日期+时间范围选择功能
步骤1:添加时间范围选择组件
在原日期选择器的容器中,新增dcc.TimePickerRange组件,实现时间范围的选择功能:
html.Div( className='date-picker-container', children=[ dcc.DatePickerRange( id='date-picker', start_date=df['date_time'].min().date(), end_date=df['date_time'].max().date(), min_date_allowed=df['date_time'].min().date(), max_date_allowed=df['date_time'].max().date(), initial_visible_month=df['date_time'].max().date(), display_format='YYYY-MM-DD', ), # 新增时间范围选择器 dcc.TimePickerRange( id='time-picker', start_time=df['date_time'].min().time(), end_time=df['date_time'].max().time(), display_format='HH:mm:ss' ) ] )
步骤2:修改回调函数的输入与逻辑
更新回调的输入参数,加入时间选择器的返回值,同时调整日期时间的拼接与查询逻辑:
@app.callback( [Output('card', 'children'), Output('card1', 'children'), Output('card2', 'children')], [Input('table-selection', 'value'), Input('date-picker', 'start_date'), Input('date-picker', 'end_date'), Input('time-picker', 'start_time'), Input('time-picker', 'end_time')] ) def update_card(table_name, start_date, end_date, start_time, end_time): # 校验所有必填参数 if not table_name or not start_date or not end_date or not start_time or not end_time: return '', '', '' # 拼接日期与时间,生成完整的datetime对象 start_datetime = datetime.strptime(f"{start_date} {start_time}", '%Y-%m-%d %H:%M:%S') end_datetime = datetime.strptime(f"{end_date} {end_time}", '%Y-%m-%d %H:%M:%S') # 构造精确到秒的查询语句 query = f"SELECT * FROM {table_name} WHERE date_time >= '{start_datetime}' AND date_time <= '{end_datetime}'" cursor.execute(query) data = cursor.fetchall() df = pd.DataFrame(data, columns=[col[0] for col in cursor.description]) # 原有业务逻辑(统计IGN状态切换次数) cycle_count = 0 previous_state = None for _, row in df.iterrows(): current_state = row["IGN"] if previous_state == "On" and current_state == "Off": cycle_count += 1 previous_state = current_state cycle_count1 = 0 previous_state1 = None for _, row in df.iterrows(): current_state1 = row["IGN"] if previous_state1 == "Off" and current_state1 == "On": cycle_count1 += 1 previous_state1 = current_state1 # 原有业务逻辑(计算日均里程) df = df[(df['IGN'] == 'On') & (df['GPS'] == 'On')] df2 = df.drop_duplicates(subset=['Odometer']) df1 = df2[df2['Odometer'] != 0] df1["Odometer"] = df1["Odometer"].diff() df3 = df1.groupby(df1.date_time.dt.date)['Odometer'].sum() result = df3.sum() / len(df3) * 0.001 if len(df3) > 0 else 0 formatted_num = "{:.2f}".format(result) # 构造三个卡片的内容 card_content = html.Div( className="result-card", children=[ html.H4("Average Km/day", className="card-title"), html.H3(formatted_num, className="card-value") ] ) card1_content = html.Div( className="result-card", children=[ html.H4("IGN Off Cycles", className="card-title"), html.H3(cycle_count, className="card-value") ] ) card2_content = html.Div( className="result-card", children=[ html.H4("IGN On Cycles", className="card-title"), html.H3(cycle_count1, className="card-value") ] ) return card_content, card1_content, card2_content
关键细节说明
- 默认值设置:时间选择器的初始值直接取数据集里最早/最晚记录的时间部分,确保初始状态覆盖全量数据。
- 日期时间拼接:将日期选择器的字符串与时间选择器的字符串组合,转换为精确到秒的
datetime对象,保证查询条件的准确性。 - 查询条件优化:原逻辑中对结束日期的无意义调整(加0天)被移除,直接使用拼接后的结束时间作为查询上限,确保包含结束时刻的数据。
- 返回值补全:原回调声明了三个输出,但仅返回一个值,这里补充了另外两个卡片的内容,避免Dash回调报错。
内容的提问来源于stack exchange,提问作者appu
相关产品推荐
相关产品推荐

