2011-10-07 23 views
19

tengo una muestra de datos que se parece a esto:Trazado intervalos marcados en 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 

Lo que quiero es para trazar los datos anteriores de la siguiente manera:

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

Con el color de las líneas según el estado OK/FAILED del punto de datos. Las etiquetas (a/b/c/...) pueden repetirse o no.

Como he reunido a partir de la documentación para gnuplot y matplotlib, este tipo de una parcela debería ser más fácil de hacer en este último ya que no es una trama estándar y requeriría algún procesamiento previo.

La pregunta es:

  1. ¿Hay una manera estándar de hacer parcelas de este tipo en cualquiera de las herramientas?
  2. En caso negativo, ¿cómo debo hacer para trazar estos datos (punteros a herramientas/documentación/funciones/ejemplos relevantes que hacen algo, algo así como lo descrito aquí)?

Respuesta

21

Actualizado: Ahora incluye el manejo de la muestra de datos y usa la funcionalidad de fechas de 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

Gracias. Dibujé un gráfico con éxito usando su solución como base. Aceptará su respuesta si nadie propone una mejor solución. – dm3

+0

Actualicé mi respuesta, siempre quise aprender la funcionalidad de la fecha matplotlibs. – tillsten

+1

Para diferentes símbolos de los extremos, reemplace las líneas con símbolos de dispersión. plt.scatter (xstart, y, s = 100, c = color, marcador = 'x', lw = 2, edgecolor = color) – tillsten