【问题标题】:(python) matplotlib pyplot show() .. blocking or not?(python) matplotlib pyplot show() .. 阻塞与否?
【发布时间】:2011-05-31 12:31:04
【问题描述】:

我一遍又一遍地遇到show() 的这个麻烦,我确定我做错了什么,但不确定做我想做的事情的“正确”方法。

而且[我认为]我想要的是某种方式在主线程中阻塞,直到 GUI 线程中发生事件,这样的事情第一次起作用:

from matplotlib import pyplot as p
from scipy import rand

im = (255*rand(480,640)).astype('uint8')
fig = p.figure()
ax = fig.add_subplot(111)
ax.imshow(im)

# just any mutable container for storing a click
s = [-1, -1]

def onclick(event):
  if event.xdata is not None and event.ydata is not None:
    s[0] = event.xdata
    s[1] = event.ydata
    p.close()

cid = fig.canvas.mpl_connect('button_press_event', onclick)
p.show()
print s

p.show() 阻塞,直到在事件处理程序中调用 p.close()。但是当第二次运行相同的代码时,它会越过p.show() 并打印出原来的s, [-1, -1]

我已经阅读了关于是否可以或应该从同一程序多次调用 p.show() 的相互矛盾的信息。似乎它被设计为使用一次,并且只在脚本末尾使用一次。其他用例似乎以某种方式破坏了pyplot(状态机?)。

我尝试使用 p.draw()p.ion()p.ioff() 的组合,但无法获得我想要的行为(要么事情没有正确阻止,要么情节没有在正确的时间出现)。

我也很困惑事件处理程序如何能够在这里看到s,以及这是否是一种传入/传出信息的糟糕方式。如果我不使用像数组或列表这样的可变容器,我想要由事件处理程序设置的信息就会作为局部变量丢失。还有其他我错过的方法,GUI线程可以将信号传递回主线程吗?有没有办法在继续之前阻止来自事件处理程序的信号,而无需定期轮询或忙于等待?

所以我想最终我的主要问题是:

p.show() 是否有一个很好的替代品,可以满足我的要求(与p.show() 第一次的行为相同),或者这种代码是否需要完全重新思考/重写?

【问题讨论】:

    标签: python events matplotlib blocking


    【解决方案1】:

    不同质量的几个想法:

    如果你不喜欢 s 作为一个全局变量,你可以让 onclick() 成为一个可调用的对象,把它附加到它上面。

    您的回调可以获取/释放锁来控制程序流(有点脏)。

    你可以主动轮询 s 来控制程序流程(很脏)。

    您可以通过 fig.canvas.draw() 手动控制图形的绘制

    【讨论】:

    • 感谢您的想法。我能够通过从源代码构建 mpl 来改变 show() 的阻塞行为。
    【解决方案2】:

    我今天能够解决我的问题。如果其他人有兴趣改变 show() 的行为,请继续阅读以了解如何做到这一点:

    我注意到 matplotlib 网页的 what's new 部分上标题为 multiple call to show supported 的段落:

    一个长期存在的要求是支持对 show() 的多次调用。这一直很困难,因为很难在操作系统、用户界面工具包和版本之间获得一致的行为。 Eric Firing 在跨后端合理化 show 方面做了大量工作,期望的行为是让 show 提升所有新创建的图形并阻止执行直到它们关闭。重复调用 show 应提高自上次调用以来新创建的数字。 Eric 对他可以访问的用户界面工具包以及版本和平台进行了大量测试,但不可能全部测试,因此请向邮件列表和错误跟踪器报告问题。

    这是 1.0.1 版本的“新功能”,在撰写本文时,synaptic 中的版本仍然在 0.99.3 上。我能够从源代码v1.0.1 下载和构建。我还需要满足依赖关系的其他包是libfreetype6-dev tk-dev tk8.5-dev tcl8.5-dev python-gtk2-dev

    现在有了matplotlib.__version__ == 1.0.1,下面的代码会按照我的预期进行:

    import matplotlib.pyplot as p
    from scipy import eye
    p.imshow(eye(3))
    p.show()
    print 'a' 
    p.imshow(eye(6))
    p.show()
    print 'b' 
    p.imshow(eye(9))
    p.show()
    print 'c' 
    

    【讨论】:

      【解决方案3】:

      我注意到运行代码之间的区别

      1. 直接在 Python 解释器中(命令行)

      2. 将其放入 Python 脚本并从命令行运行(“python script.py”)

      两者都给出了阻塞行为,这没关系。

      从解释器中显示两个图像,从命令行只显示第一个。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-01-27
        • 2012-05-24
        • 2014-09-15
        • 1970-01-01
        • 2011-07-27
        • 1970-01-01
        • 1970-01-01
        • 2021-07-15
        相关资源
        最近更新 更多