I'm looking at an example for interactive plotting with matplotlib (which i found here )
I've just modified it to be called inside a function (called test) like so
class PointBrowser:
def __init__(self,xs,ys):
self.xs = (xs)
self.ys = (ys)
self.fig = figure()
self.ax = self.fig.add_subplot(111)
self.line, = self.ax.plot(self.xs,self.ys,'ro ', picker=5)
self.lastind = 0
self.text = self.ax.text(0.05, 0.95, 'Datapoint index selected: none',
transform=self.ax.transAxes, va='top')
self.selected, = self.ax.plot([self.xs[0]],
[self.ys[0]], 'o', ms=12, alpha=0.4,
color='yellow', visible=False)
self.fig.canvas.mpl_connect('pick_event', self.onpick)
self.fig.canvas.mpl_connect('key_press_event', self.onpress)
def onpress(self, event):
'define some key press events'
if self.lastind is None: return
if event.key in ('q','Q'): sys.exit()
if event.key not in ('n', 'p'): return
if event.key=='n': inc = 1
else: inc = -1
self.lastind += inc
self.lastind = clip(self.lastind, 0, len(self.xs)-1)
self.update()
def onpick(self, event):
if event.artist!=self.line: return True
N = len(event.ind)
if not N: return True
if N > 1:
print '%i points found!' % N
# the click locations
x = event.mouseevent.xdata
y = event.mouseevent.ydata
dx = array(x-self.xs[event.ind],dtype=float)
dy = array(y-self.ys[event.ind],dtype=float)
distances = hypot(dx,dy)
indmin = distances.argmin()
dataind = event.ind[indmin]
self.lastind = dataind
self.update()
def update(self):
if self.lastind is None: return
dataind = self.lastind
self.selected.set_visible(True)
self.selected.set_data(self.xs[dataind], self.ys[dataind])
self.text.set_text('datapoint index selected: %d'%dataind)
# put a user function in here!
self.userfunc(dataind)
self.fig.canvas.draw()
def userfunc(self,dataind):
print 'No userfunc defined'
pass
def test():
import numpy as npy
X = npy.random.rand(100, 200)
xs = npy.mean(X, axis=1)
ys = npy.std(X, axis=1)
p = PointBrowser(xs,ys)
def plot2(dataind):
fig2 = figure(2)
ax2 = fig2.add_subplot(111)
ax2.cla()
ax2.plot(X[dataind])
ax2.text(0.05, 0.9, 'mu=%1.3f\nsigma=%1.3f'%(xs[dataind], ys[dataind]),
transform=ax2.transAxes, va='top')
ax2.set_ylim(-0.5, 1.5)
fig2.canvas.draw()
p.userfunc = plot2
xlabel('$\mu$')
ylabel('$\sigma$')
show()
if __name__ == '__main__':
test()
The strange thing is that it now does not work. If I remove the function and put its body back under the "if name ==' main '" block, it works as expected (like in the original code).
I'm trying to generate interactive plots as part of a class I'm building and I'm puzzled as to why this is happening. Any ideas?
When I run your code inside ipython, I see the same thing: onpick()
is never called. Running the same code directly by calling python example_code.py
from the command line will work in the sense that the onpick()
method is called; however, it will not show the second figure. This is in my opinion a problem of event loops, but I am not sure.
However, if you want to run your code from within ipython, you can use the following code, which replaces your nested function construction with a class:
from numpy import *
from matplotlib.pyplot import *
class PointBrowser:
def __init__(self,xs,ys):
self.xs = (xs)
self.ys = (ys)
self.fig = figure()
self.ax = self.fig.add_subplot(111)
self.line, = self.ax.plot(self.xs,self.ys,'ro ', picker=5)
self.lastind = 0
self.text = self.ax.text(0.05, 0.95, 'Datapoint index selected: none',
transform=self.ax.transAxes, va='top')
self.selected, = self.ax.plot([self.xs[0]],
[self.ys[0]], 'o', ms=12, alpha=0.4,
color='yellow', visible=False)
self.fig.canvas.mpl_connect('pick_event', self.onpick)
self.fig.canvas.mpl_connect('key_press_event', self.onpress)
print "init done"
def onpress(self, event):
'define some key press events'
if self.lastind is None: return
if event.key in ('q','Q'): sys.exit()
if event.key not in ('n', 'p'): return
if event.key=='n': inc = 1
else: inc = -1
self.lastind += inc
self.lastind = clip(self.lastind, 0, len(self.xs)-1)
self.update()
def onpick(self, event):
print "in onpick"
if event.artist!=self.line: return True
N = len(event.ind)
if not N: return True
if N > 1:
print '%i points found!' % N
# the click locations
x = event.mouseevent.xdata
y = event.mouseevent.ydata
dx = array(x-self.xs[event.ind],dtype=float)
dy = array(y-self.ys[event.ind],dtype=float)
distances = hypot(dx,dy)
indmin = distances.argmin()
dataind = event.ind[indmin]
self.lastind = dataind
self.update()
def update(self):
print "in update"
if self.lastind is None: return
dataind = self.lastind
self.selected.set_visible(True)
self.selected.set_data(self.xs[dataind], self.ys[dataind])
self.text.set_text('datapoint index selected: %d'%dataind)
# put a user function in here!
self.userfunc(dataind)
self.fig.canvas.draw()
def userfunc(self,dataind):
print 'No userfunc defined'
pass
class Test2:
def __init__(self):
self.X = random.rand(100, 200)
self.xs = mean(self.X, axis=1)
self.ys = std(self.X, axis=1)
self.p = PointBrowser(self.xs,self.ys)
self.p.userfunc = self.plot2
xlabel('$\mu$')
ylabel('$\sigma$')
show()
def plot2(self, dataind):
fig2 = figure(2)
ax2 = fig2.add_subplot(111)
ax2.cla()
ax2.plot(self.X[dataind])
ax2.text(0.05, 0.9, 'mu=%1.3f\nsigma=%1.3f'%(self.xs[dataind], self.ys[dataind]),
transform=ax2.transAxes, va='top')
ax2.set_ylim(-0.5, 1.5)
fig2.canvas.draw()
if __name__ == '__main__':
Test2()
Nested functions give you their own level of complication, since the have to store local variables from the nesting level in closure cells in order to be able to access them later, when the nesting function has already terminated (as with X
, xs
, and ys
in your code).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.