简体   繁体   English

Matplotlib拼图中的交互式绘图

[英]Interactive plotting in matplotlib puzzle

I'm looking at an example for interactive plotting with matplotlib (which i found here ) 我正在看一个使用matplotlib进行交互式绘图的示例(我在这里找到)

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). 如果我删除该函数并将其主体放回“ if name ==' main '”块下,它将按预期工作(如原始代码中一样)。

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. 当我在ipython中运行您的代码时,我看到了同样的事情: onpick()从未被调用。 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; 从命令行调用python example_code.py直接运行相同的代码在某种意义上可以正常工作,即调用了onpick()方法。 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: 但是,如果要从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()

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). 嵌套函数给您带来了自己的复杂程度,因为必须在嵌套函数已经终止时(如Xxsys将嵌套级别的局部变量存储在闭包单元中,以便以后可以访问它们。在您的代码中)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM