Skip to main content
 首页 » 编程设计

python之Matplotlib:在堆叠水平条形图的 x 轴上格式化时间

2025年05月04日7bluestorm

我正在尝试使用 matplotlib 在堆叠的水平条形图中绘制用户在不同任务上花费的时间。 x 轴是时间。条形的每个部分代表在任务上花费的时间量。但是,我收到格式不正确的意外图表。图表的格式要求我在图表上放大很多才能看到所有的条形。

该图确实符合我的需要,但起初它看起来像这样:original graph

我必须放大到很远才能得到这个:zoomed-in graph

除了第一个和最后一个数据点外,放大图的条形比例似乎正确。

我的数据是 timedelta 对象的列表,因此可以将它们加在一起。我正在将它们转换为 datetime 对象以绘制数据图表。

给我不想要的结果的代码是:

import matplotlib.pyplot as plt 
from datetime import datetime 
from datetime import timedelta 
import matplotlib.dates as dt 
 
def sum_times(data, N): 
    '''sums the first N datetime elements in a list 
       changes from timedelta object to datetime object 
    ''' 
    # initialize 
    summ = datetime(1900, 1, 1, 0, 0, 0) 
    for i in range(len(data[0:N])): 
        summ += data[i] 
    return summ 
 
start_date = datetime(1900, 1, 1, 0, 0, 0) 
times = [timedelta(0, 737),  
         timedelta(0, 110),  
         timedelta(0, 356),  
         timedelta(0, 171),  
         timedelta(0, 306)] 
 
fig, ax1 = plt.subplots(1,1, sharex=True, sharey=True) 
 
ax1.set_title("Bug being fixed") 
ax1.set_xlabel('time') 
ax1.xaxis_date() 
 
# the graph uses datetime objects 
ax1.barh(1, times[0] + start_date) 
ax1.barh(1, times[1] + start_date, left=sum_times(times, 1)) 
ax1.barh(1, times[2] + start_date, left=sum_times(times, 2)) 
ax1.barh(1, times[3] + start_date, left=sum_times(times, 3)) 
ax1.barh(1, times[4] + start_date, left=sum_times(times, 4)) 
 
ax1.set_xticks(range(1,10))   # arbitrary  
 
plt.show() 

如何更改格式?

我曾尝试将 ax1.set_xticklabels() 与 datetime 或 timedelta 对象一起使用,但出现异常:ValueError : 序号必须 >= 1。

当我使用

ax1.xaxis.set_major_locator(dt.MinuteLocator(interval=60)) 
ax1.xaxis.set_major_formatter(dt.DateFormatter('%M:%S')) 

格式仍然不正确。

我正在使用 python 3.6、matplotlib、PyDev IDE 和 Windows 8。

如果有任何库更适合显示此类数据或可以补充 matplotlib/pyplot,我将不胜感激使用其中之一的解决方案。

此外,我尝试使用循环来自动调用 ax1.barh(...),但图形窗口不显示并且变得无响应。由于我想绘制更大的数据集,我可以使用更优雅的解决方案。

请您参考如下方法:

根据@rvd 提供的建议,我想出了一个使用 pandas 的更好的解决方案。它在格式方面仍然不理想,但我不需要放大到离谱的远才能看到我的图表并且数据是成比例的。

这是使用 pandas 使其工作得更好的代码:

import pandas as pd 
import matplotlib.pyplot as plt 
from datetime import datetime 
from datetime import timedelta 
import matplotlib.dates as dt 
 
times = [timedelta(0, 737),  
         timedelta(0, 110),  
         timedelta(0, 356),  
         timedelta(0, 171),  
         timedelta(0, 306)] 
 
start_date = datetime(1900, 1, 1, 0, 0, 0) 
times_datetime = [start_date + times[i] for i in range(len(times))] 
# pandas requires numerical data on dependent axis 
times_num = dt.date2num(times_datetime) 
# to make times_num proportionally correct 
for i in range(len(times_num)): 
    times_num[i] -= dt.date2num(start_date) 
     
df = pd.DataFrame([times_num], index=['bugs']) 
fig, ax1 = plt.subplots(1,1, sharex=True, sharey=True) 
df.plot(kind='barh', ax=ax1, stacked=True) 
plt.show() 

这会产生:

x 轴刻度可能不是时间,但数据可视化更符合我正在寻找的内容。

谢谢!