Построение кумулятивного графика Python datetimes

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

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

Или сделайте я должен превратить этот список datetimes в список объектов словаря, таких как:

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

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

16
задан user1211 24 July 2017 в 06:30
поделиться

3 ответа

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

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 даст график, который увеличивается каждый день, когда происходят события, поэтому я бы предложил использовать его вместо графика .

(Совет 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 .

11
ответ дан 30 November 2019 в 22:55
поделиться

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

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 гистограмму , чтобы узнать о дополнительных параметрах (количество ячеек и т. д.) ):

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

5
ответ дан 30 November 2019 в 22:55
поделиться

Я просто использую chart director из Advanced Software Engineering. С ним очень легко работать, особенно с датами. У них есть много примеров и на python.

-2
ответ дан 30 November 2019 в 22:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: