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

时间:2017-05-30 22:41:10

标签: python python-3.x datetime matplotlib graph

我正在尝试使用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()用于datetimetimedelta个对象,但我得到例外:ValueError: ordinal must be >= 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(...),但图形窗口不显示并且无响应。由于我想绘制更大的数据集,我可以使用更优雅的解决方案。

2 个答案:

答案 0 :(得分:0)

基于@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()

这会产生:better graph

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

谢谢!

答案 1 :(得分:-1)

在Python中使用pandas库可能会派上用场,因为对时间序列分析和绘图的支持比matplotlib(它构建在它上面)更加原生和直观。如果您的数据采用CSV文件格式,请使用df = pandas.read_csv(FILEPATH)将数据加载到数据框中,并使用df.plot()进行绘图。如果您正在寻找更复杂或更具响应性的绘图,请务必查看Plotly - 您只需将库导入python并为时间序列制作响应式图表,并且更加轻松。