Objective: To plot a graph(x,y) and move a vertical line over the graph w.r.t to timer.
I started implementing this using matplotlib. Its possible to implement this using draw() feature of matplotlib , but it consumes cpu as it redraws every time and doesn't allow me to interact with the graph. so i decided to use animation feature of matplotlib. in Future i would aslo like to pause the moving line. So i cant use matplotlib.animation.FuncAnimatin
Problem: I use canvas.copy_from_bbox(ax.bbox), ax.draw_artist(line),canvas.blit(ax.bbox). But, I am not able to store the graph in the background and move a line over it. When i try to store, it overwrites in a quite weird way.
This is the code i have built. Could any one please help me ? Thanks in advance.
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();
So it looks like the "quite weird way" you are referring to is essentially that the wrong bbox has been captured with your background = canvas.copy_from_bbox(ax.bbox)
. I believe this is a known problem with most of the backends where the addition of toolbars etc. affect the position of the bbox for blitting.
Essentially, if you can capture the background after the window has popped up, then everything should be working for you. This can be done in a number of ways, in your case the simplest would be to replace your canvas.draw()
command with a plt.show(block=False)
, which will bring up the window, without making it a blocking command.
As a slight addition, I'm sure you are aware that semicolons are not necessary in python code, but while I was debugging, I tidied up your code a little (didn't quite get to the end):
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With