【问题标题】:Callbacks for graphical mouse input - how to refresh graphics, how to tell Matplotlib I am done?图形鼠标输入的回调 - 如何刷新图形,如何告诉 Matplotlib 我完成了?
【发布时间】:2014-03-08 10:42:30
【问题描述】:

希望有人能告诉我在我的第一个程序中我做错了什么 回调。

目标:

  • 显示包含数据的图
  • 允许用户点击绘图 4 次。每次,X坐标 被附加到保存的列表中。
  • 当鼠标移动时,它的水平位置由垂直 在情节中来回移动的线。 (我保存二维线 对象为self.currentLine)
  • 当用户通过单击选择一个点时,垂直线会下降到 x-感兴趣的坐标,并生成一个新的继续跟踪 鼠标位置。

在用户输入的末尾,应该有四行垂直线和类 应该返回一个包含它们的 x 坐标的列表。

目前,我无法弄清楚更新线对象的正确方法 情节(即我可以得到我想要的鼠标跟踪效果)。我也拿不到 完成后返回值列表的类。

我知道while 循环可能不是正确的方法,但我无法找出正确的方法。

import matplotlib.pyplot as plt
import pdb

class getBval:
    def __init__(self):
        figWH = (8,5) # in
        self.fig = plt.figure(figsize=figWH)
        plt.plot(range(10),range(10),'k--')
        self.ax = self.fig.get_axes()[0]
        self.x = [] # will contain 4 "x" values
        self.lines = [] # will contain 2D line objects for each of 4 lines            

        self.connect =    self.ax.figure.canvas.mpl_connect
        self.disconnect = self.ax.figure.canvas.mpl_disconnect

        self.mouseMoveCid = self.connect("motion_notify_event",self.updateCurrentLine)
        self.clickCid     = self.connect("button_press_event",self.onClick)
    def updateCurrentLine(self,event):
        xx = [event.xdata]*2
        self.currentLine, = self.ax.plot(xx,self.ax.get_ylim(),'k')
        plt.show()
    def onClick(self, event):
        if event.inaxes:
            self.updateCurrentLine(event)
            self.x.append(event.xdata)
            self.lines.append(self.currentLine)
            del self.currentLine
            if len(self.x)==4:
                self.cleanup()
    def cleanup(self):
        self.disconnect(self.mouseMoveCid)
        self.disconnect(self.clickCid)
        return self


xvals = getBval()
print xvals.x

【问题讨论】:

  • 由于回调的工作方式,您无法预先说“返回”,但您可以询问对象是否 a) 它已完成并且 b) 它的值是什么。事件驱动编程可能需要一些时间来理解。
  • 谢谢。如果return 语句不合适,那么等待对象完成的可接受协议是什么?只是一个while 循环重复检查变量的值直到它满足标准(例如我的问题中的 4 个项目的列表)?这似乎效率低下,但我不知道用谷歌搜索什么来找到正确的答案。再次感谢。
  • signals 可以很方便或者只是 while + sleep(假设你有线程)。有了你正在做的事情,你可能想放弃一个简单的脚本并接受你正在使用的 gui 框架工作(嵌入 mpl),这会给你更多的回调,你可以在选择足够的点时触发。
  • 假设你有线程 Sleep + while 阻止窗口出现(也许这应该告诉我我没有线程)。你的意思是我需要导入和使用threading 模块吗?另外,嵌入 mpl 是指like this? (tkinter)(部分解决了我现在遇到的问题)

标签: python class matplotlib callback


【解决方案1】:

我建议您为垂直线使用Cursor 小部件,并只收集点击的x 值(不是整个Line2D),这是一个示例:

import matplotlib.pyplot as plt
import matplotlib.widgets as mwidgets

class getBval:

    def __init__(self):
        figWH = (8,5) # in
        self.fig = plt.figure(figsize=figWH)
        plt.plot(range(10),range(10),'k--')
        self.ax = self.fig.get_axes()[0]
        self.x = [] # will contain 4 "x" values
        self.lines = [] # will contain 2D line objects for each of 4 lines            

        self.cursor = mwidgets.Cursor(self.ax, useblit=True, color='k')
        self.cursor.horizOn = False

        self.connect = self.ax.figure.canvas.mpl_connect
        self.disconnect = self.ax.figure.canvas.mpl_disconnect

        self.clickCid = self.connect("button_press_event",self.onClick)

    def onClick(self, event):
        if event.inaxes:
            self.x.append(event.xdata)
            if len(self.x)==4:
                self.cleanup()

    def cleanup(self):
        self.disconnect(self.clickCid)
        plt.close()


xvals = getBval()
plt.show()

print xvals.x

【讨论】:

  • 谢谢。我不知道 mpl 'Widgets'——这些看起来很有用。我想我没有很好地表达我的问题,但我遇到的一个障碍是不知道如何控制我的程序流程---我希望它等待用户输入,然后一旦将第四项保存到列表中,继续到程序的下一部分并在其他地方使用该数据。有小费吗?谢谢。
  • 好吧,plt.show() 和刚刚在 cleanup 上添加的 plt.close() 的组合应该可以满足您的需求(检查我的答案的代码),但不是更好的方法(至少从面向对象的观点)
  • plt.close 不适用于 plot.show() (see relevant post)---但只要程序流程继续,使用 draw() 似乎也不起作用。这包括sleep,正如上面提到的@tcaswell。我不愿意仅仅为了这个任务而学习 tkinter,因为我不希望使用它太多(博士生;这只是我快速处理一些测试数据的一个技巧)。嗯。暂时难住了!再次感谢。
  • 你运行了我的代码,plt.close() 没有关闭窗口吗?...我今天刚刚复制粘贴了代码,它运行顺利,它甚至打印了 x 值的列表正如最后的声明所说。但我的后端是 PyQt 可能有事做
猜你喜欢
  • 2016-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-13
  • 2014-04-26
  • 2017-12-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多