如何在24小时X轴上绘制任务起止时间直方图并实现合理分箱?
问题描述
我有一个包含datetime类型数据的DataFrame,字段如下:
- Start_time:任务开始时间戳,示例:
2013-09-21 00:14:00 - End_time:任务结束时间戳,示例:
2013-09-22 11:04:00 - Time_diff:任务耗时,示例:
0 days 06:07:00
我想绘制仅按24小时制(忽略日期)统计的任务起止时间直方图,目标是X轴为24小时区间,Y轴为对应分箱内的起止时间分布数量。
尝试用df['Start_time'].dt.time提取时间后绘制直方图,但无法将这些时间对象正确划分为20个分箱。直接用原始datetime字段绘制的话,会因为日期不同导致X轴跨多天,不符合需求。
以下是我使用的代码:
from random import randrange import datetime import pandas as pd import plotly.express as px # 生成示例数据集 startDate = datetime.datetime(2013, 9, 20,13,00) start_lst = [] end_lst = [] for i in range(200): start_time= startDate + datetime.timedelta(hours=randrange(23), minutes= randrange(60)) end_time = start_time + datetime.timedelta(hours=randrange(2,7), minutes= randrange(60)) startDate = startDate + datetime.timedelta(days=randrange(4)) start_lst.append(start_time) end_lst.append(end_time) df = pd.DataFrame({'Start_time': start_lst, 'End_time': end_lst }) df['Time_diff'] = df['End_time']-df['Start_time'] # 尝试直接绘制,但日期不同导致X轴跨多天 fig = px.histogram(df, x=['Start_time', 'End_time'], nbins=20) fig.show() # 尝试提取时间部分,但无法正确分箱 df['Start_time_nodate'] = df['Start_time'].dt.time df['End_time_nodate'] = df['End_time'].dt.time fig = px.histogram(df, x=['Start_time_nodate', 'End_time_nodate'], nbins=20) fig.show()
解决方案
问题核心是dt.time返回的datetime.time对象无法被Plotly正常分箱。正确做法是将时间转换为一天内的数值型小时数,完成分箱后再将X轴标签转回时间格式。
修改后的代码如下:
from random import randrange import datetime import pandas as pd import plotly.express as px # 生成示例数据集 startDate = datetime.datetime(2013, 9, 20,13,00) start_lst = [] end_lst = [] for i in range(200): start_time= startDate + datetime.timedelta(hours=randrange(23), minutes= randrange(60)) end_time = start_time + datetime.timedelta(hours=randrange(2,7), minutes= randrange(60)) startDate = startDate + datetime.timedelta(days=randrange(4)) start_lst.append(start_time) end_lst.append(end_time) df = pd.DataFrame({'Start_time': start_lst, 'End_time': end_lst }) df['Time_diff'] = df['End_time']-df['Start_time'] # 将时间转换为一天内的小时数(数值型,支持均匀分箱) df['Start_hour'] = df['Start_time'].dt.hour + df['Start_time'].dt.minute/60 + df['Start_time'].dt.second/3600 df['End_hour'] = df['End_time'].dt.hour + df['End_time'].dt.minute/60 + df['End_time'].dt.second/3600 # 合并起止时间数据,方便分组绘制 melted_df = pd.melt(df, value_vars=['Start_hour', 'End_hour'], var_name='时间类型', value_name='一天中的小时数') # 绘制20个分箱的直方图 fig = px.histogram(melted_df, x='一天中的小时数', color='时间类型', nbins=20, barmode='overlay', opacity=0.7) # 将X轴刻度转为易读的时间格式 hour_ticks = [i for i in range(0,25,2)] tick_labels = [f"{h:02d}:00" for h in hour_ticks] fig.update_layout( xaxis=dict( title='一天中的时间', tickmode='array', tickvals=hour_ticks, ticktext=tick_labels ), yaxis_title='数量', title='任务起止时间24小时分布直方图' ) fig.show()
关键说明
- 时间转数值:把时间转换成带小数的小时数(如1点30分对应1.5),让Plotly可以对数值进行均匀分箱。
- 数据融合:用
pd.melt合并起止时间列,实现按“开始/结束”类型分组展示。 - X轴格式化:把数值刻度转回
HH:00的时间格式,保证X轴符合24小时制的直观展示。
内容的提问来源于stack exchange,提问作者Leo
相关产品推荐
相关产品推荐

