绘制python日期时间的累积图

绘制python日期时间的累积图,python,datetime,graph,matplotlib,Python,Datetime,Graph,Matplotlib,假设我有一个datetime列表,我们知道每个datetime都是事件发生的记录时间 在matplotlib中,是否可以在不预处理此列表的情况下,绘制随时间发生此事件的频率,以累积图的形式显示此数据(以便每个点都大于或等于之前的所有点)?(例如,将datetime对象直接传递给一些出色的matplotlib函数) 或者我需要将此日期时间列表转换为字典项列表,例如: {"year": 1998, "month": 12, "date": 15, "events": 92} 然后从这个列表中生成一

假设我有一个datetime列表,我们知道每个datetime都是事件发生的记录时间

在matplotlib中,是否可以在不预处理此列表的情况下,绘制随时间发生此事件的频率,以累积图的形式显示此数据(以便每个点都大于或等于之前的所有点)?(例如,将datetime对象直接传递给一些出色的matplotlib函数)

或者我需要将此日期时间列表转换为字典项列表,例如:

{"year": 1998, "month": 12, "date": 15, "events": 92}

然后从这个列表中生成一个图表?

我只是使用高级软件工程的chart director。非常容易处理,尤其是约会。他们在python中也有很多示例。

这应该适合您:

counts = arange(0, len(list_of_dates))
plot(list_of_dates, counts)
当然,您可以为
plot
调用提供任何常用选项,以使图形看起来符合您的需要。(我要指出,matplotlib非常擅长处理日期和时间。)

另一个选项是-它有一个可能有用的选项“cumulative=True”。您可以创建一个累积柱状图,显示截至任何给定日期发生的事件数,如下所示:

from pyplot import hist
from matplotlib.dates import date2num
hist(date2num(list_of_dates), cumulative=True)
grouped_dates = [[d, len(list(g))] for d,g in itertools.groupby(list_of_dates, lambda k: k.date())]
dates, counts = grouped_dates.transpose()
counts = counts.cumsum()
step(dates, counts)
但是这会产生一个条形图,这可能不是你想要的,而且在任何情况下,在水平轴上正确显示日期标签都可能需要一些修改

编辑:我感觉到你真正想要的是每个日期一个点(或条),相应的y值是截至(包括?)该日期发生的事件数。在这种情况下,我建议这样做:

from pyplot import hist
from matplotlib.dates import date2num
hist(date2num(list_of_dates), cumulative=True)
grouped_dates = [[d, len(list(g))] for d,g in itertools.groupby(list_of_dates, lambda k: k.date())]
dates, counts = grouped_dates.transpose()
counts = counts.cumsum()
step(dates, counts)
itertools
模块中的
groupby
函数将生成您要查找的数据类型:每个日期只有一个实例,并附带一个包含该日期的所有
datetime
对象的列表(实际上是一个迭代器)。正如Jouni在评论中所建议的那样,
步骤
函数将给出一个在事件发生的每一天递增的图表,因此我建议使用它来代替
绘图

(提醒我有关cumsum)的EOL礼帽提示

如果您希望每天都有一个积分,无论当天是否发生任何事件,您都需要稍微修改上述代码:

from matplotlib.dates import drange, num2date
date_dict = dict((d, len(list(g))) for d,g in itertools.groupby(list_of_dates, lambda k: k.date()))
dates = num2date(drange(min(list_of_dates).date(), max(list_of_dates).date() + timedelta(1), timedelta(1)))
counts = asarray([date_dict.get(d.date(), 0) for d in dates]).cumsum()
step(dates, counts)

不过,我认为这不会对
步骤
函数生成的绘图产生任何影响。

因此,您可以从一个日期列表开始:

from datetime import  datetime
list_of_datetime_datetime_objects = [datetime(2010, 6, 14), datetime(1974, 2, 8), datetime(1974, 2, 8)]
bin_size = histo[1][1]-histo[1][0]
pyplot.bar(histo[1][:-1], cumulative_histo_counts, width=bin_size)
# pyplot.plot(histo[1][1:], cumulative_histo_counts)
Matplotlib允许您将
datetime.datetime
对象转换为简单的数字,如David所述:

from matplotlib.dates import date2num, num2date
num_dates = [date2num(d) for d in list_of_datetime_datetime_objects]
然后,您可以计算数据的直方图(查看):

由于需要累积直方图,因此需要将各个计数相加:

cumulative_histo_counts = histo[0].cumsum()
柱状图将需要箱子大小:

from matplotlib import pyplot
然后可以绘制累积直方图:

from datetime import  datetime
list_of_datetime_datetime_objects = [datetime(2010, 6, 14), datetime(1974, 2, 8), datetime(1974, 2, 8)]
bin_size = histo[1][1]-histo[1][0]
pyplot.bar(histo[1][:-1], cumulative_histo_counts, width=bin_size)
# pyplot.plot(histo[1][1:], cumulative_histo_counts)
或者,您可能需要曲线而不是直方图:

from datetime import  datetime
list_of_datetime_datetime_objects = [datetime(2010, 6, 14), datetime(1974, 2, 8), datetime(1974, 2, 8)]
bin_size = histo[1][1]-histo[1][0]
pyplot.bar(histo[1][:-1], cumulative_histo_counts, width=bin_size)
# pyplot.plot(histo[1][1:], cumulative_histo_counts)
如果希望x轴上的日期而不是数字,可以将数字转换回日期,并要求matplotlib使用日期字符串作为记号,而不是数字:

from matplotlib import ticker

# The format for the x axis is set to the chosen string, as defined from a numerical date:
pyplot.gca().xaxis.set_major_formatter(ticker.FuncFormatter(lambda numdate, _: num2date(numdate).strftime('%Y-%d-%m')))
# The formatting proper is done:
pyplot.gcf().autofmt_xdate()
# To show the result:
pyplot.show()  # or draw(), if you don't want to block
这里,
gca()
gcf()
分别返回当前轴和图形

当然,您可以在上面对
strftime()
的调用中调整显示日期的方式

除了你的问题,我想提到的是,这是一个非常好的信息来源:你通常可以通过查找与你正试图做的事情相似的图像,并查看它们的源代码,快速找到你需要的东西


不过它有点贵,我无法想象它会比Python简单多少。(好吧,我想easy是主观的,所以这只是我的观点)这个arange()方法似乎没有考虑一天中事件发生的次数。。我似乎只得到了一系列递增的数字。e、 g.也许我没有以最清晰的方式问我最初的问题。@ventolin:
arange()
与Python的内置
range()
是一样的,只是它返回一个NumPy数组而不是Python列表。它不应该考虑你的事件。您对问题的措辞意味着列表中包含一个
datetime
对象,用于事件的每次发生,我推断您希望每个事件在图表上有一个点。如果不是这样,请澄清,我可以相应地调整我的答案。+1表示matplotlib的
date2num
,以及
hist
中的
累积
选项@David:Aha,对不起,我不清楚。我提到的字典表示法可能会澄清一些问题:我需要的是Y轴上事件数量的图表,以及X轴上的时间(以每天固定的间隔)。一天可能会发生50个事件,下一天可能会发生2个,依此类推,我需要这些事件的累积图表。现在阅读EOL的回应…尝试“步骤”而不是“情节”?尝试这个,我得到。。。这是因为经过处理后,X轴上的点数与Y轴上的点数不同吗?还是我偏离了正轨?你说得对。我更新了答案中的代码,它在我的机器上运行。