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

如何将datetime.time类型数据绘制在Matplotlib的X轴上

问题:按时段汇总步数后无法用Matplotlib绘图

我想对比设备在不同时段的使用情况,数据集提供了YYYY/MM/D HH:MM:SS格式的日期时间数据,我把它拆分为time和date两列,然后按time列分组得到每小时的步数汇总数据。

import pandas as pd
import matplotlib.pyplot as plt

# 示例数据集
data = {'Id': [1503960366, 1503960366, 1503960366, 1503960366, 1503960366],
        'ActivityHour': ['2016-04-12 00:00:00', '2016-04-12 01:00:00', '2016-04-12 02:00:00', '2016-04-12 03:00:00', '2016-04-12 04:00:00'],
        'Calories': [81, 61, 59, 47, 48],
        'TotalIntensity': [20, 8, 7, 0, 0],
        'AverageIntensity': [0.333333, 0.133333, 0.116667, 0.0, 0.0],
        'StepTotal': [373, 160, 151, 0, 0]}
hourly_activity = pd.DataFrame(data)

hourly_activity['time'] = [d.time() for d in hourly_activity['ActivityHour']]
hourly_activity['date'] = [d.date() for d in hourly_activity['ActivityHour']]
hours_vs_steps = hourly_activity.copy()
hours_vs_steps = hours_vs_steps[['time', 'StepTotal', 'Calories']]
hours_vs_steps = hours_vs_steps.groupby(['time']).sum()
hours_vs_steps.reset_index(inplace=True)

初始DataFrame

Id         ActivityHour  Calories  TotalIntensity  AverageIntensity  StepTotal
0  1503960366  2016-04-12 00:00:00        81              20          0.333333        373
1  1503960366  2016-04-12 01:00:00        61               8          0.133333        160
2  1503960366  2016-04-12 02:00:00        59               7          0.116667        151
3  1503960366  2016-04-12 03:00:00        47               0          0.000000          0
4  1503960366  2016-04-12 04:00:00        48               0          0.000000          0

分组汇总后的数据

time    StepTotal   Calories
0   00:00:00    39404   67066
1   01:00:00    21555   65464
2   02:00:00    15964   64551
3   03:00:00    5996    63013
4   04:00:00    11836   63620

我尝试用Matplotlib或Seaborn把StepTotal作为Y轴、time作为X轴绘图,不管是直接用列还是把time设为索引都失败了。执行plt.plot(hours_vs_steps.time, hours_vs_steps.StepTotal)时抛出如下错误:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[28], line 1
----> 1 plt.plot(hours_vs_steps.time, hours_vs_steps.StepTotal)

File ~\anaconda3\envs\py11\Lib\site-packages\matplotlib\pyplot.py:2812, in plot(scalex, scaley, data, *args, **kwargs)
   2810 @_copy_docstring_and_deprecators(Axes.plot)
   2811 def plot(*args, scalex=True, scaley=True, data=None, **kwargs):
-> 2812     return gca().plot(
   2813         *args, scalex=scalex, scaley=scaley,
   2814         **({"data": data} if data is not None else {}), **kwargs)

File ~\anaconda3\envs\py11\Lib\site-packages\matplotlib\axes\_axes.py:1690, in Axes.plot(self, scalex, scaley, data, *args, **kwargs)
   1688 lines = [*self._get_lines(*args, data=data, **kwargs)]
   1689 for line in lines:
-> 1690     self.add_line(line)
   1691 if scalex:
   1692     self._request_autoscale_view("x")

File ~\anaconda3\envs\py11\Lib\site-packages\matplotlib\axes\_base.py:2304, in _AxesBase.add_line(self, line)
   2301 if line.get_clip_path() is None:
   2302     line.set_clip_path(self.patch)
-> 2304 self._update_line_limits(line)
   2305 if not line.get_label():
   2306     line.set_label(f'_child{len(self._children)}')

File ~\anaconda3\envs\py11\Lib\site-packages\matplotlib\axes\_base.py:2327, in _AxesBase._update_line_limits(self, line)
   2323 def _update_line_limits(self, line):
   2324     """
   2325     Figures out the data limit of the given line, updating self.dataLim.
   2326     """
-> 2327     path = line.get_path()
   2328     if path.vertices.size == 0:
   2329         return

File ~\anaconda3\envs\py11\Lib\site-packages\matplotlib\lines.py:1029, in Line2D.get_path(self)
   1027 """Return the `~matplotlib.path.Path` associated with this line."""
   1028 if self._invalidy or self._invalidx:
-> 1029     self.recache()
   1030 return self._path

File ~\anaconda3\envs\py11\Lib\site-packages\matplotlib\lines.py:657, in Line2D.recache(self, always)
    655 if always or self._invalidx:
    656     xconv = self.convert_xunits(self._xorig)
-> 657     x = _to_unmasked_float_array(xconv).ravel()
    658 else:
    659     x = self._x

File ~\anaconda3\envs\py11\Lib\site-packages\matplotlib\cbook\__init__.py:1335, in _to_unmasked_float_array(x)
   1333     return np.ma.asarray(x, float).filled(np.nan)
   1334 else:
-> 1335     return np.asarray(x, float)

TypeError: float() argument must be a string or a real number, not 'datetime.time'
解决方案

错误根源是Matplotlib无法直接处理datetime.time类型的X轴数据,需要把时间转换成字符串/数值格式,或者改用pandas的绘图接口(它能更好地处理时间类型)。

方法1:用pandas内置绘图接口(最简单)

pandas的plot()方法可以自动识别时间格式,直接调用即可:

hours_vs_steps.plot(x='time', y='StepTotal', kind='line')
plt.show()

方法2:将time列转为字符串

把datetime.time对象转换成字符串,Matplotlib就能正常识别:

# 转换time列为字符串
hours_vs_steps['time_str'] = hours_vs_steps['time'].astype(str)
# 绘图
plt.plot(hours_vs_steps['time_str'], hours_vs_steps['StepTotal'])
plt.xlabel('时段')
plt.ylabel('总步数')
plt.title('不同时段步数汇总')
plt.xticks(rotation=45)  # 旋转X轴标签避免重叠
plt.show()

方法3:优化数据处理流程(从源头避免问题)

在拆分日期时间时,先把ActivityHour转为datetime类型(你的原始代码漏了这一步,实际运行会报错),再提取格式化的时间字符串或小时数值:

# 先转换为datetime类型
hourly_activity['ActivityHour'] = pd.to_datetime(hourly_activity['ActivityHour'])
# 提取小时字符串,比如"00:00"
hourly_activity['time'] = hourly_activity['ActivityHour'].dt.strftime('%H:%M')
# 也可以直接提取小时数值(0-23)
# hourly_activity['hour'] = hourly_activity['ActivityHour'].dt.hour

# 后续分组汇总
hours_vs_steps = hourly_activity[['time', 'StepTotal', 'Calories']].groupby(['time']).sum().reset_index()

# 直接绘图
plt.plot(hours_vs_steps['time'], hours_vs_steps['StepTotal'])
plt.show()

内容的提问来源于stack exchange,提问作者dbeltranor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 09:29:57