2012-08-13 24 views
5

Ziel: Zeichnen eines Graphen (x, y) und Bewegen einer vertikalen Linie über den Graph w.r.t zum Zeitgeber.Fortschrittslinie in Matplotlib-Graphen

Ich begann, dies mit Matplotlib zu implementieren. Es ist möglich, dies mit der Funktion draw() von matplotlib zu implementieren, aber es verbraucht CPU, da es jedes Mal neu gezeichnet wird und es mir nicht erlaubt, mit dem Graphen zu interagieren. Also entschied ich mich, die Animationsfunktion von Matplotlib zu verwenden. In Zukunft würde ich auch gern die bewegliche Linie anhalten. So kann ich nicht matplotlib.animation.FuncAnimatin verwenden

Problem: Ich benutze canvas.copy_from_bbox (ax.bbox), ax.draw_artist (line), canvas.blit (ax.bbox). Aber ich kann das Diagramm nicht im Hintergrund speichern und eine Linie darüber bewegen. Wenn ich versuche zu speichern, überschreibt es auf eine ziemlich seltsame Art und Weise.

Dies ist der Code, den ich gebaut habe. Könnte jemand bitte mir helfen? Danke im Voraus.

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

Was die "ganz seltsame Art und Weise" ist verweisen Sie auf? – pelson

Antwort

4

So sieht es aus wie die „ganz seltsame Art und Weise“ Sie sich beziehen ist im Wesentlichen, dass die falsche bbox mit Ihrem background = canvas.copy_from_bbox(ax.bbox) erfaßt wurde. Ich glaube, das ist ein bekanntes Problem bei den meisten Backends, wo das Hinzufügen von Symbolleisten etc. die Position der bbox für Blitting beeinflusst.

Im Wesentlichen, wenn Sie den Hintergrund erfassen können nach das Fenster ist aufgetaucht, dann sollte alles für Sie arbeiten. Dies kann auf verschiedene Arten geschehen, in Ihrem Fall wäre es am einfachsten, Ihren canvas.draw() Befehl durch einen plt.show(block=False) zu ersetzen, der das Fenster öffnet, ohne es zu blockieren.

Als kleine Ergänzung, ich bin sicher, dass Sie wissen, dass Semikolons in Python-Code nicht notwendig sind, aber während ich debugging, räumte ich Ihren Code ein wenig (nicht ganz bis zum Ende):

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

Hey, vielen Dank. Es läuft gut. Aber in 2 Fällen funktioniert es nicht. 1) wenn wir die Größe des Fensters ändern und wenn wir zoomen. Hast du irgendwelche Vorschläge? –

+0

Ich denke auch, wenn ich das Fenster verkleinern und vergrößern, sollte ich in der Lage sein, ein Ereignis hinzuzufügen, um den Hintergrund zu ändern –

+0

Sie müssen den Hintergrund auf der Größe neu erfassen. Ich denke, das Ereignis ist 'resize_event'. Ich würde die Quelle von '' animate.py'' für Beispiele für gute Praxis (Handhabung der Größenänderung zum Beispiel) lesen. Hoffe das hilft, – pelson