【问题标题】:Create a bar diagram with matplotlib with x-axis date and width is a time-delta使用 matplotlib 创建条形图,x 轴日期和宽度是时间增量
【发布时间】:2018-05-20 18:24:30
【问题描述】:

我有一个简单的数据集,我想将它显示在与在不同时间收集的重量相对应的条形图中。我希望它与我之前估计的误差条累积。由于权重对应于一定时间段内的累积,所以我希望条形为它所代表的时间的宽度。

入口文件格式为:

Date    Weight  Deviation
2017-05-04  500 100
2017-05-08  7.4 0.3
2017-05-13  6.4 0.3
2017-05-21  8.7 0.27
2017-06-06  16.8    0.7
2017-06-07  14.4    0.6
2017-06-18  13.7    0.6
2017-06-25  16.3    0.7
2017-07-02  17  0
2017-07-09  17  0
2017-07-26  20  0
2017-08-11  19  0
2017-08-23  12  0
2017-09-03  27  0
2017-09-11  15  0
2017-09-16  60  0

代码如下:

import os, sys, datetime
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

DATA  = np.genfromtxt(Path_to_File, dtype=[('Date','datetime64[D]'),('Weight', 'float32'), ('Deviation', 'float32')], delimiter ='\t', skip_header = 1)
Days  = np.zeros(len(DATA)-1, dtype = 'datetime64[D]')
Duration = np.zeros(len(DATA)-1, dtype = 'timedelta64[D]')
for i in range(1, len(DATA)):
    DayOut = DATA[i][0]
    DayIn  = DATA[i-1][0]
    Duration[i-1] = DayOut - DayIn
    Days[i-1] = DayIn + Duration[i-1]/2


fig2 = plt.figure()
ax = fig2.add_subplot(111)
fig2.suptitle('FigureTitle', fontsize=16)
ax.xaxis_date()
ax.xaxis.set_major_formatter(mdates.DateFormatter('%d/%m'))
ax.xaxis.set_major_locator(mdates.DayLocator(interval=7))
ax.bar(Days, DATA['Weight'].cumsum()[1:], width=Duration, yerr = DATA['Deviation'][1:])
ax.set_ylabel('Cumulative weight (kg)')
ax.set_xlabel('Date')
plt.show()

我收到此错误消息

Cannot cast ufunc less input from dtype('<m8[D]') to dtype('<m8') with casting rule 'same_kind'

这很棘手,因为我认为它会在日期(datetime64)、Days 数组和宽度的持续时间(timedelta64)、Duration 数组之间感到恼火。 我有点卡住了,我想我必须只做一个持续时间轴?有什么经验或建议吗? 提前致谢

【问题讨论】:

  • 恐怕这是不可能的,因为 matplotlib 现在是如何工作的。它将日期时间转换为数字以生成 x 轴。一种解决方法是使用自开始以来的天数作为 x 轴,然后手动添加刻度。 ax.bar((Days-min(Days)).astype(int), DATA['Weight'].cumsum()[1:], width=Duration.astype(int), yerr = DATA['Deviation'][1:])
  • @HaochenWu 我不知道这里应该有什么不可能,但是根据日历手动设置标签可能不是一个好主意。

标签: python date numpy datetime matplotlib


【解决方案1】:

Matplotlib 目前无法处理 numpy.datetime64。它将依赖 pandas 转换为 datetime 对象。由于在这里您无论如何都希望以天为单位设置条形的宽度,因此不使用 pandas 的简单解决方案是将日期转换为datetime(通过.tolist() 在下面完成)。可以通过首先将日期时间转换为数字并取其差来计算持续时间。

Days  = [x.tolist() for x in DATA["Date"]]
Duration = np.diff(mdates.date2num(Days))

我想其余的代码可以保持不变,虽然我不明白你为什么要省略第一个元素,所以我将其更改为省略最后一个元素 ([:-1])。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

DATA  = np.genfromtxt("data/datetabdelim.txt", dtype=[('Date','datetime64[D]'),('Weight', 'float32'), ('Deviation', 'float32')], 
                                                      delimiter ='\t', skip_header = 1)
Days  = [x.tolist() for x in DATA["Date"]]
Duration = np.diff(mdates.date2num(Days))

fig2 = plt.figure()
ax = fig2.add_subplot(111)
fig2.suptitle('FigureTitle', fontsize=16)
ax.xaxis_date()
ax.xaxis.set_major_formatter(mdates.DateFormatter('%d/%m'))
ax.xaxis.set_major_locator(mdates.DayLocator(interval=7))
bars = ax.bar(Days[:-1], DATA['Weight'].cumsum()[:-1], width=Duration, 
              yerr = DATA['Deviation'][:-1], edgecolor="k", alpha=0.5, align="edge")
ax.set_ylabel('Cumulative weight (kg)')
ax.set_xlabel('Date')
fig2.autofmt_xdate()
plt.show()

【讨论】:

  • 我只是想在持续时间的中间获取天数,因为这对我的数据更有意义,但这与我的问题无关。谢谢您的帮助!我对 Panda 不太熟悉,但这是探索这个库的另一个动力。
  • 请注意,pandas 确实是一个很棒的工具,但不幸的是,在这种特殊情况下它并没有太大帮助,这就是为什么我完全没有使用它就给出了解决方案。
【解决方案2】:

感谢@ImportanceOfBeingErnest,我设法得到了我想要的确切结果,并使代码更“pythonesque”。连续日期的天数存在问题,因此我将持续时间格式切换为小时,并在这里和那里进行了一些调整。我还切换到累积错误,它在我的情况下更具代表性。

DATA  = np.genfromtxt(WorkingDir+os.sep+File, dtype=[('Date','datetime64[D]'),('Weight', 'float32'), ('Deviation', 'float32')], delimiter ='\t', skip_header = 1)

Duration = np.diff(DATA['Date']).astype('timedelta64[h]')
Days = DATA['Date'][:-1] + Duration/2
### Trick: transform the np array 'datetime64[h]' to a list datetime.datetime
Days = [x.tolist() for x in Days]

fig2 = plt.figure()
ax = fig2.add_subplot(111)
fig2.suptitle('Cumulative weight', fontsize=16)
ax.xaxis_date()
ax.xaxis.set_major_formatter(mdates.DateFormatter('%d/%m'))
ax.xaxis.set_major_locator(mdates.DayLocator(interval=7))
ax.bar(Days, DATA['Weight'].cumsum()[1:], width=Duration.astype(float)/24, yerr = DATA['Deviation'].cumsum()[1:], align="center", color= 'grey')
ax.set_ylabel('Cumulative weight (kg)')
ax.set_xlabel('Date')
fig2.autofmt_xdate()
plt.show()

谢谢

【讨论】:

    猜你喜欢
    • 2020-03-24
    • 1970-01-01
    • 1970-01-01
    • 2020-09-11
    • 1970-01-01
    • 2016-12-03
    • 2018-09-20
    • 2015-05-02
    • 2016-06-25
    相关资源
    最近更新 更多