2011-10-07 2 views
19

ho un campione di dati che assomiglia a questo:Tracciare intervalli etichettati in matplotlib/gnuplot

a 10:15:22 10:15:30 OK 
b 10:15:23 10:15:28 OK 
c 10:16:00 10:17:10 FAILED 
b 10:16:30 10:16:50 OK 

Quello che voglio è quello di tracciare i dati di cui sopra nel seguente modo:

captions^
    | 
c |   *------* 
b | *---* *--* 
a | *--* 
    |___________________ 
        time > 

Con il colore delle linee in base allo stato OK/FAILED del punto dati. Le etichette (a/b/c/...) possono essere ripetute o meno.

Come ho raccolto dalla documentazione per gnuplot e matplotlib, questo tipo di una trama dovrebbe essere più facile da fare in questi ultimi in quanto non è una trama di serie e richiederebbe un po 'di pre-elaborazione.

La domanda è:

  1. C'è un modo standard per fare trame come questo in uno qualsiasi degli strumenti?
  2. In caso contrario, come dovrei andare a tracciare questi dati (puntatori a strumenti/documentazione/funzioni/esempi pertinenti che fanno qualcosa di simile alla cosa descritta qui)?

risposta

21

Aggiornato: ora include la gestione del campione di dati e utilizza la funzionalità di date mpl.

import matplotlib.pyplot as plt 
from matplotlib.dates import DateFormatter, MinuteLocator, SecondLocator 
import numpy as np 
from StringIO import StringIO 
import datetime as dt 

### The example data 
a=StringIO("""a 10:15:22 10:15:30 OK 
b 10:15:23 10:15:28 OK 
c 10:16:00 10:17:10 FAILED 
b 10:16:30 10:16:50 OK 
""") 

#Converts str into a datetime object. 
conv = lambda s: dt.datetime.strptime(s, '%H:%M:%S') 

#Use numpy to read the data in. 
data = np.genfromtxt(a, converters={1: conv, 2: conv}, 
        names=['caption', 'start', 'stop', 'state'], dtype=None) 
cap, start, stop = data['caption'], data['start'], data['stop'] 

#Check the status, because we paint all lines with the same color 
#together 
is_ok = (data['state'] == 'OK') 
not_ok = np.logical_not(is_ok) 

#Get unique captions and there indices and the inverse mapping 
captions, unique_idx, caption_inv = np.unique(cap, 1, 1) 

#Build y values from the number of unique captions. 
y = (caption_inv + 1)/float(len(captions) + 1) 

#Plot function 
def timelines(y, xstart, xstop, color='b'): 
    """Plot timelines at y from xstart to xstop with given color.""" 
    plt.hlines(y, xstart, xstop, color, lw=4) 
    plt.vlines(xstart, y+0.03, y-0.03, color, lw=2) 
    plt.vlines(xstop, y+0.03, y-0.03, color, lw=2) 

#Plot ok tl black  
timelines(y[is_ok], start[is_ok], stop[is_ok], 'k') 
#Plot fail tl red 
timelines(y[not_ok], start[not_ok], stop[not_ok], 'r') 

#Setup the plot 
ax = plt.gca() 
ax.xaxis_date() 
myFmt = DateFormatter('%H:%M:%S') 
ax.xaxis.set_major_formatter(myFmt) 
ax.xaxis.set_major_locator(SecondLocator(interval=20)) # used to be SecondLocator(0, interval=20) 

#To adjust the xlimits a timedelta is needed. 
delta = (stop.max() - start.min())/10 

plt.yticks(y[unique_idx], captions) 
plt.ylim(0,1) 
plt.xlim(start.min()-delta, stop.max()+delta) 
plt.xlabel('Time') 
plt.show() 

Resulting image

+0

Grazie. Ho disegnato con successo un grafico usando la soluzione come base. Accetterà la tua risposta se nessuno propone una soluzione migliore. – dm3

+0

Ho aggiornato la mia risposta, ho sempre voluto imparare la funzionalità data matplotlibs. – tillsten

+1

Per i simboli di estremità diversi si sostituiscono le linee vc con simboli scatter. plt.scatter (xstart, y, s = 100, c = colore, marker = 'x', lw = 2, edgecolor = colore) – tillsten