Построение кумулятивного графика дат-времени Python - PullRequest
16 голосов
/ 14 июня 2010

Скажем, у меня есть список даты и времени, и мы знаем, что каждая дата и время являются записанным временем события.

Возможно ли в matplotlib построить график частоты этого события, происходящего во времени, отображая эти данные в кумулятивном графике (чтобы каждая точка была больше или равна всем точкам, которые были до нее), без предварительной обработки этого списка ? (например, передача объектов datetime непосредственно в какую-то замечательную функцию matplotlib)

Или мне нужно превратить этот список дат-таймов в список элементов словаря, например:

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

и затем сгенерировать график из этого списка?

Ответы [ 3 ]

11 голосов
/ 14 июня 2010

Это должно работать для вас:

counts = arange(0, len(list_of_dates))
plot(list_of_dates, counts)

Вы, конечно, можете задать любой из обычных параметров для вызова plot, чтобы график выглядел так, как вы этого хотите. (Я укажу, что matplotlib очень искусен в обработке дат и времени.)

Другим вариантом может быть Hist функция - она ​​имеет параметр 'cumulative = True', который может быть полезен. Вы можете создать кумулятивную гистограмму, показывающую количество событий, которые произошли на любую данную дату, примерно так:

from pyplot import hist
from matplotlib.dates import date2num
hist(date2num(list_of_dates), cumulative=True)

Но при этом получается гистограмма, которая может быть не совсем той, которую вы ищете, и в любом случае для правильного отображения меток даты на горизонтальной оси, вероятно, потребуется некоторая путаница.

РЕДАКТИРОВАТЬ : у меня возникает ощущение, что вы действительно хотите получить одну точку (или гистограмму) за дату, а соответствующее значение y - это число событий, которые произошли до (и в том числе?) этой даты. В этом случае я бы предложил сделать что-то вроде этого:

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)

Функция groupby из модуля itertools будет генерировать тот тип данных, который вы ищете: только один экземпляр каждой даты, сопровождаемый списком (фактически, итератором) всех datetime объекты, которые имеют эту дату. Как предложил Джоуни в комментариях, функция step будет отображать график, который повышается каждый день, когда происходили события, поэтому я бы предложил использовать его вместо plot.

(Наконечник шляпы EOL за напоминание о cumsum)

Если вы хотите получать одно очко за каждый день, независимо от того, происходили ли какие-либо события в этот день или нет, вам нужно будет немного изменить вышеприведенный код:

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)

Не думаю, что это действительно изменит график, созданный функцией step.

5 голосов
/ 14 июня 2010

Итак, вы начинаете со списка дат, которые вы хотите добавить к гистограмме:

from datetime import  datetime
list_of_datetime_datetime_objects = [datetime(2010, 6, 14), datetime(1974, 2, 8), datetime(1974, 2, 8)]

Matplotlib позволяет вам конвертировать datetime.datetime объект в простое число, как упомянул Дэвид:

from matplotlib.dates import date2num, num2date
num_dates = [date2num(d) for d in list_of_datetime_datetime_objects]

Затем вы можете рассчитать гистограмму ваших данных (см. NumPy histogram документы для получения дополнительных параметров (количество бинов и т. Д.) ):

import numpy
histo = numpy.histogram(num_dates)

Так как вам нужна гистограмма совокупности , вы добавляете отдельные счетчики вместе:

cumulative_histo_counts = histo[0].cumsum()

Для графика гистограммы потребуется размер ячейки:

from matplotlib import pyplot

Затем можно построить графиккумулятивная гистограмма:

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() выше.

Чтобы выйти за рамки вашего вопроса, я хотел бы отметить, что Галерея Matplotlib является очень хорошим источником информации: в общем, вы можете быстро найти то, что вам нужно, просто найдя изображенияэто похоже на то, что вы пытаетесь сделать, и глядя на их исходный код.

Example of accumulative curve with datetime labels

0 голосов
/ 14 июня 2010

Я просто использую диаграмму директора от передовой разработки программного обеспечения. Действительно легко иметь дело, особенно с датами. У них тоже есть много примеров в Python.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...