2

我正在看一个使用 matplotlib 进行交互式绘图的示例(我在这里找到了)

我刚刚将其修改为在函数(称为测试)中调用,如下所示

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()

奇怪的是,它现在不起作用。如果我删除该函数并将其主体放回“if name ==' main '”块下,它会按预期工作(就像在原始代码中一样)。

我正在尝试生成交互式绘图作为我正在构建的课程的一部分,我对为什么会发生这种情况感到困惑。有任何想法吗?

4

1 回答 1

0

当我在 ipython 中运行您的代码时,我看到了同样的事情:onpick()从不被调用。python example_code.py通过从命令行调用直接运行相同的代码将在调用该onpick()方法的意义上起作用;但是,它不会显示第二个数字。我认为这是事件循环的问题,但我不确定。

但是,如果你想在 ipython 中运行你的代码,你可以使用下面的代码,它将你的嵌套函数构造替换为一个类:

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()

嵌套函数为您提供了自己的复杂程度,因为必须将嵌套级别的局部变量存储在闭包单元中,以便以后能够在嵌套函数已经终止时访问它们(如X, xs, 和ys在您的代码中) )。

于 2013-10-18T08:48:10.660 回答