2012-08-13 18 views
5

Objetivo: Trazar un gráfico (x, y) y mover una línea vertical sobre el gráfico w.r.t al temporizador.Línea de progreso en Matplotlib Gráficos

Comencé a implementar esto usando matplotlib. Es posible implementar esto usando la función draw() de matplotlib, pero consume cpu ya que se vuelve a dibujar cada vez y no me permite interactuar con el gráfico. así que decidí usar la función de animación de matplotlib. en Future también me gustaría detener la línea móvil. Entonces no puedo usar matplotlib.animation.FuncAnimatin

Problema: Utilizo canvas.copy_from_bbox (ax.bbox), ax.draw_artist (line), canvas.blit (ax.bbox). Pero no puedo almacenar el gráfico en el fondo y mover una línea sobre él. Cuando intento almacenar, sobrescribe de una manera bastante extraña.

Este es el código que he creado. Podría alguien ayudarme por favor ? Gracias por adelantado.

import sys 
import matplotlib.pyplot as p 
import time 
fig=p.figure(); 
ax = fig.add_subplot(1,1,1) 

y=[];x=[];y1=[0,1000];x1=[0,0] 
y=numpy.random.randn(1000,1)*100 
x=numpy.arange(0,1000) 
line1, = ax.plot(x,y,color='black'); 
ax.set_ylim(0, 1000); 
line, = ax.plot(x1,y1,color='r',alpha=1,animated=True); # this is the line which i wanted to move over the graph w.r.t to time. (i can also use axvline , but i guess its the same). 
canvas = ax.figure.canvas 
canvas.draw() 
background = canvas.copy_from_bbox(ax.bbox); #my problem is here 
starttime=time.time(); 
mytimer=0; 
mytimer_ref=0; 
def update(canvas,line,ax): 
    canvas.restore_region(background) #my problem is here 
    t=time.time()-starttime; 
    mytimer=t+mytimer_ref; 
    x1=[mytimer,mytimer]; 
    line.set_xdata(x1); 
    ax.draw_artist(line) 
    canvas.blit(ax.bbox) #my problem is here 

def onclick(event): 
    global starttime 
    starttime=time.time(); 
    global mytimer_ref; 
    mytimer_ref=event.xdata; 
    print "starttime",starttime; 


cid=line1.figure.canvas.mpl_connect('button_press_event',onclick); # when i click the mouse over a point, line goes to that point and start moving from there. 
timer=fig.canvas.new_timer(interval=100); 
args=[canvas,line,ax]; 
timer.add_callback(update,*args); # every 100ms it calls update function 
timer.start(); 
p.show(); 
+0

¿Qué es el "camino bastante raro" se refiere? – pelson

Respuesta

4

lo que parece que el "camino bastante raro" se está refiriendo a es esencialmente que el Bbox mal ha sido capturado con su background = canvas.copy_from_bbox(ax.bbox). Creo que este es un problema conocido con la mayoría de los backends donde la adición de barras de herramientas, etc. afecta la posición del bbox para blitting.

Esencialmente, si puede capturar el fondo después de, la ventana ha aparecido, entonces todo debería funcionar para usted. Esto se puede hacer de varias maneras, en su caso lo más simple sería reemplazar su comando canvas.draw() con un plt.show(block=False), que abrirá la ventana, sin convertirlo en un comando de bloqueo.

Como pequeña adición, estoy seguro de que sabe que los puntos y comas no son necesarios en el código python, pero mientras estaba depurando, arreglé un poco su código (no llegó al final):

import sys 
import matplotlib.pyplot as plt 
import time 
import numpy 


fig = plt.figure() 
ax = fig.add_subplot(111) 


max_height = 100 
n_pts = 100 
y1 = [0, max_height] 
x1 = [0, 0] 
y = numpy.random.randn(n_pts) * max_height 
x = numpy.arange(0, n_pts) 

# draw the data 
line1, = ax.plot(x, y, color='black') 

# fix the limits of the plot 
ax.set_ylim(0, max_height) 
ax.set_xlim(0, n_pts) 

# draw the plot so that we can capture the background and then use blitting 
plt.show(block=False) 

# get the canvas object 
canvas = ax.figure.canvas 
background = canvas.copy_from_bbox(ax.bbox) 

# add the progress line. 
# XXX consider using axvline 
line, = ax.plot(x1, y1, color='r', animated=True) 


starttime=time.time() 
mytimer=0 
mytimer_ref=0 

def update(canvas, line, ax): 
    # revert the canvas to the state before any progress line was drawn 
    canvas.restore_region(background) 

    # compute the distance that the progress line has made (based on running time) 
    t = time.time() - starttime 
    mytimer = t + mytimer_ref 
    x1 = [mytimer,mytimer] 
    # update the progress line with its new position 
    line.set_xdata(x1) 
    # draw the line, and blit the axes 
    ax.draw_artist(line) 
    canvas.blit(ax.bbox) 

def onclick(event): 
    global starttime 
    starttime=time.time() 
    global mytimer_ref 
    mytimer_ref=event.xdata 
    print "starttime",starttime 


cid=line1.figure.canvas.mpl_connect('button_press_event',onclick) # when i click the mouse over a point, line goes to that point and start moving from there. 
timer=fig.canvas.new_timer(interval=100) 
args=[canvas,line,ax] 
timer.add_callback(update,*args) # every 100ms it calls update function 
timer.start() 
plt.show() 

HTH

+0

Hola, muchas gracias. Funciona bien. Pero en 2 casos no funciona. 1) cuando cambiamos el tamaño de la ventana y cuando hacemos zoom. ¿Tienes alguna sugerencia? –

+0

También creo que cuando cambie el tamaño y el zoom de la ventana, debería poder agregar algún evento para modificar el fondo. –

+0

Deberá volver a capturar el fondo al cambiar el tamaño. Creo que el evento es 'resize_event'. Quisiera leer la fuente de '' animate.py'' para ver ejemplos de buenas prácticas (manejo del cambio de tamaño, por ejemplo). Espero que ayude, – pelson

Cuestiones relacionadas