Tracer un graphique cumulatif des datetimes de python

Dire que j'ai une liste de datetimes, et nous savons que chaque datetime à la durée d'enregistrement d'un événement.

est-il possible dans matplotlib de représenter graphiquement la fréquence de cet événement se produisant dans le temps, en montrant ces données dans un graphique cumulatif (de sorte que chaque point est supérieur ou égal à tous les points qui l'ont précédé), sans prétraitement de cette liste? (e.g. passer des objets datetime directement à une fonction matplotlib merveilleuse)

Ou dois-je me tourner ce liste des datetimes dans une liste d'éléments dans le dictionnaire, tels que:

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

puis de générer un graphique à partir de cette liste?

16
demandé sur user1211 2010-06-14 02:34:49

3 réponses

Cela devrait fonctionner pour vous:

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

vous pouvez bien sûr donner n'importe laquelle des options habituelles au plot appeler pour que le graphique ressemble à ce que vous voulez. (Je ferai remarquer que matplotlib est très habile à traiter les dates et les heures.)

une Autre option serait le fonction hist - il y a une option 'cumulatif=vrai' qui pourrait être utile. Vous pouvez créer un histogramme cumulatif montrant le nombre d'événements qui se sont produits à une date donnée quelque chose comme ceci:

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

mais cela produit un graphique à barres, qui pourrait ne pas être tout à fait ce que vous cherchez, et dans tous les cas, faire correctement les étiquettes de date sur l'affichage de l'axe horizontal exigera probablement un peu de doigté.

EDIT: j'ai l'impression que ce que vous voulez vraiment est un point (ou une barre) par date, avec la valeur y correspondante étant le nombre d'événements qui se sont produits jusqu'à (et y compris?) cette date. Dans ce cas, je serais suggère de faire quelque chose comme ceci:

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 de la fonction itertools module de produire le type de données que vous recherchez: une seule instance de chaque date, accompagnée d'une liste (un itérateur, en fait) de tous les datetime objets qui ont cette date. Comme suggéré par Jouni dans les commentaires, le step fonction va donner un graphique qui s'élève à chaque jour où les événements se sont produits, donc je suggère d'utiliser cela à la place de plot.

(Chapeau conseil à EOL pour me rappeler de cumsum)

Si vous voulez avoir un point pour chaque jour, que des événements survenus ce jour-là ou non, vous aurez besoin de modifier le code ci-dessus un peu:

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)

Je ne pense pas que cela fera vraiment une différence pour l'intrigue produite par le step la fonction si.

11
répondu David Z 2010-06-17 00:34:02

Donc, vous commencez avec une liste de dates que vous voulez histogramme:

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

Matplotlib vous permet de convertir un datetime.datetime objet dans un simple nombre, comme David mentionné:

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

ensuite, Vous pouvez calculer l'histogramme de vos données (regardez NumPy histogram docs pour plus d'options (nombre de bacs, etc.)):

import numpy
histo = numpy.histogram(num_dates)

Puisque vous voulez le cumulatif histogramme, vous ajoutez des chefs ensemble:

cumulative_histo_counts = histo[0].cumsum()

L'histogramme de la parcelle devra le bin taille:

from matplotlib import pyplot

vous pouvez alors tracer l'histogramme cumulatif:

bin_size = histo[1][1]-histo[1][0]
pyplot.bar(histo[1][:-1], cumulative_histo_counts, width=bin_size)

alternativement, vous pourriez vouloir une courbe au lieu d'un histogramme:

# pyplot.plot(histo[1][1:], cumulative_histo_counts)

si vous voulez des dates sur l'axe des x au lieu des nombres, vous pouvez convertir les nombres en dates et demander à matplotlib d'utiliser des chaînes de dates comme tics, au lieu des nombres:

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

Ici gca() et gcf() retourner l'axe et la figure actuels, respectivement.

bien sûr, vous pouvez adapter la façon dont vous l'affichage des dates, dans l'appel à strftime() ci-dessus.

aller au-delà De votre question, je tiens à mentionner que Matplotlib galerie est une très bonne source d'information: vous pouvez généralement trouver rapidement ce dont vous avez besoin en trouvant simplement des images qui ressemblent à ce que vous essayez de faire, et en regardant leur source code.

Example of accumulative curve with datetime labels

5
répondu Eric Lebigot 2016-05-30 14:26:49

je viens d'utiliser le directeur graphique de l'ingénierie logicielle avancée. Très facile à gérer, surtout avec les dates. Ils ont beaucoup d'exemples en python.

-2
répondu Khorkrak 2010-06-13 22:56:03