web-dev-qa-db-fra.com

est-il possible de tracer des chronologies avec matplotlib?

J'essaie de tracer des dates avec des valeurs comme celle-ci.

Tue  2 Jun 16:55:51 CEST 2015,3
Wed  3 Jun 14:51:49 CEST 2015,3
Fri  5 Jun 10:31:59 CEST 2015,3
Sat  6 Jun 20:47:31 CEST 2015,3
Sun  7 Jun 13:58:23 CEST 2015,3
Mon  8 Jun 14:56:49 CEST 2015,2
Tue  9 Jun 23:39:11 CEST 2015,1
Sat 13 Jun 16:55:26 CEST 2015,2
Sun 14 Jun 15:52:34 CEST 2015,3
Sun 14 Jun 16:17:24 CEST 2015,3
Mon 15 Jun 13:23:18 CEST 2015,1
...

Je fais quelque chose de très similaire à la première réponse ici: Timplications Matplotlib

Mais il est vraiment difficile d’obtenir une bonne compréhension des données relatives à ce type de visualisation. Ensuite, je me rends compte que j’essaie de tracer des périodes et que je n’ai pas besoin d’un axe y significatif, seul l’axe x avec les dates et les valeurs peut être en couleur

Quelque chose comme ça:

---===-===---****
DDDDDDDDDDDDDDDDD

-=* = type of values (using colors for example, but any representation would do)
D = dates

Je ne vois rien de semblable en regardant les exemples de matplotlib

colorbars semble pouvoir fonctionner, mais pas tout à fait, puisque l’axe doit être un intervalle de dates http://matplotlib.org/examples/api/colorbar_only.html

10
mr_pen

Par exemple, ce sont des données qualitatives pour que vous ne vouliez pas utiliser un axe y spatial? 

 enter image description here

de: 

import matplotlib.pyplot as plt
import pandas as pd

dates = ["Tue  2 Jun 16:55:51 CEST 2015",
"Wed  3 Jun 14:51:49 CEST 2015",
"Fri  5 Jun 10:31:59 CEST 2015",
"Sat  6 Jun 20:47:31 CEST 2015",
"Sun  7 Jun 13:58:23 CEST 2015",
"Mon  8 Jun 14:56:49 CEST 2015",
"Tue  9 Jun 23:39:11 CEST 2015",
"Sat 13 Jun 16:55:26 CEST 2015",
"Sun 14 Jun 15:52:34 CEST 2015",
"Sun 14 Jun 16:17:24 CEST 2015",
"Mon 15 Jun 13:23:18 CEST 2015"]

values = [3,3,3,3,3,2,1,2,3,3,1]

X = pd.to_datetime(dates)
fig, ax = plt.subplots(figsize=(6,1))
ax.scatter(X, [1]*len(X), c=values,
           marker='s', s=100)
fig.autofmt_xdate()

# everything after this is turning off stuff that's plotted by default

ax.yaxis.set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.xaxis.set_ticks_position('bottom')

ax.get_yaxis().set_ticklabels([])
day = pd.to_timedelta("1", unit='D')
plt.xlim(X[0] - day, X[-1] + day)
plt.show()
12
cphlewis

EDIT: Depuis que je n’aimais aucune solution, je cuire moi-même avec PIL:

Voici le résultat:

 Resulting visualisation

C'est le code:

#!/usr/bin/env python3
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
import csv
import matplotlib.pyplot as plt
import matplotlib.dates as pltdate
from PIL import Image, ImageDraw

lines = []
with open('date') as f:
    lines = list(csv.reader(f))
    frmt = '%a %d %b %X %Z %Y'
    dates = [datetime.strptime(line[0], frmt) for line in lines]
    data = [line[1] for line in lines]

#datesnum = pltdate.date2num(dates)
#fig, ax = plt.subplots()
#ax.plot_date(datesnum, data, 'o')

#plt.show()

#generate image
WIDTH, HEIGHT = 4000, 400
BORDER = 70
W = WIDTH - (2 * BORDER)
H = HEIGHT - (2 * BORDER)


colors = { '0': "Lime", '1' : (255,200,200), '2' : (255,100,100), '3' : (255,0,0) }

image = Image.new("RGB", (WIDTH, HEIGHT), "white")
min_date = dates[0]
max_date = datetime.now()
#print(min_date)
#print(max_date)
interval = max_date - min_date
#print(interval.days)

#draw frame
draw = ImageDraw.Draw(image)
draw.rectangle((BORDER, BORDER, WIDTH-BORDER, HEIGHT-BORDER), fill=(128,128,128), outline=(0,0,0))

#draw circles
circle_w = 10
range_secs = W / interval.total_seconds()
#print(range_secs)
for i in range(len(dates)):
    wat = dates[i] - min_date
    offset_sec = (dates[i] - min_date).total_seconds()
    offset = range_secs * offset_sec
    x = BORDER + offset
    draw.ellipse((x, BORDER + 50, x + circle_w, BORDER + 50 + circle_w), outline=colors[data[i]])
    #draw.text((x, BORDER + 75), str(i), fill=colors[data[i]])

#draw rectangles
range_days = W / (interval.days + 1)
#print("range_days",range_days)
current_date = min_date
date_month = min_date + relativedelta(months=1)
current_index = 0
for i in range(interval.days + 1):
    max_color = '0'
    while dates[current_index].date() == current_date.date():
        if int(data[current_index]) > int(max_color):
            max_color = data[current_index]
        current_index += 1
        if current_index > len(dates) - 1:
            current_index = 0
    x = BORDER + range_days * i
    draw.rectangle((x, BORDER + 100, x+range_days, BORDER + 100 + 50), fill=colors[max_color], outline=(0,0,0))
    if current_date == date_month:
        draw.line((x, BORDER + 100 +50, x, H + BORDER + 20), fill="black")
        draw.text((x, H + BORDER + 20), str(date_month.date()), fill="black")
        date_month = date_month + relativedelta(months=1)
    #draw.text((x, BORDER + 175), str(i), fill=colors[max_color])
    current_date = current_date + timedelta(days=1)

#draw start and end dates
draw.text((BORDER, H + BORDER + 20), str(min_date.date()), fill="black")
draw.text((BORDER + W, H + BORDER + 20), str(max_date.date()), fill="black")

image.save("date.png")
13
mr_pen

J'utilise la broken_barh() API, quelque chose comme:

mycolors=deque(["#d24e32","#6a40c5","#59ba45",...])        

# for each bar to draw
ax.broken_barh([(x, w), ...], (y, h), color=mycolors, alpha=0.3, antialiased=True)

mycolors.rotate(-1)
0
bobah