【问题标题】:How to keep matplotlib (python) window in background?如何将matplotlib(python)窗口保持在后台?
【发布时间】:2017-10-31 21:08:10
【问题描述】:

我有一个 python / matplotlib 应用程序,它经常使用来自测量仪器的新数据更新绘图。当用新数据更新绘图时,相对于我桌面上的其他窗口,绘图窗口不应从背景变为前景(反之亦然)。

这在运行带有 matplotlib 1.5.2rc 的 Ubuntu 16.10 的机器上使用 Python 3 可以正常工作。但是,在另一台装有 Ubuntu 17.04 和 matplotlib 2.0.0 的机器上,每次使用新数据更新绘图时,图形窗口都会弹出到前面。

如何在使用新数据更新绘图时控制窗口前景/背景行为并保持窗口焦点?

这是一个说明我的绘图例程的代码示例:

import matplotlib
import matplotlib.pyplot as plt
from time import time
from random import random

print ( matplotlib.__version__ )

# set up the figure
fig = plt.figure()
plt.xlabel('Time')
plt.ylabel('Value')
plt.ion()

# plot things while new data is generated:
t0 = time()
t = []
y = []
while True:
    t.append( time()-t0 )
    y.append( random() )
    fig.clear()
    plt.plot( t , y )
    plt.pause(1)

【问题讨论】:

  • 因为我无法以任何方式对此进行测试,只是建议尝试什么:而不是 plt.ion(),如果您使用 plt.show(block=False) 然后在您的 while 循环中添加 plt.draw() 会发生什么在plt.plot() 通话之后?
  • @Thomas Kühn:感谢您的建议。但是,这并没有改变 Ubuntu 17.04 / matplotlib 2.0.0 环境中的任何内容。
  • 你在用什么backend?可能值得改变它,看看这是否能解决问题。
  • @Ed Smith:我不知道上面显示的示例代码默认使用哪个后端。但为了确保我明确选择了 TkAgg 后端进行了尝试。这并没有改变任何东西。
  • 这是一个解决方法stackoverflow.com/a/45734500/277267

标签: python matplotlib background window focus


【解决方案1】:

对于 tkinter 后端(matplotlib.use("TkAgg")),使用flush_events 是不够的:您还需要在每个fig.canvas.flush_events() 之前调用fig.canvas.draw_idle()。正如@samlaf 所写,Qt5Agg 后端也是如此。

【讨论】:

    【解决方案2】:

    matplotlib 从 1.5.2rc 版本更改为 2.0.0 版本,因此 pyplot.show() 将窗口带到前台(请参阅here)。因此,关键是避免在循环中调用pyplot.show()pyplot.pause() 也是如此。

    下面是一个工作示例。这仍然会在开始时将窗口带到前台。但是用户可以将窗口移到背景中,当图形更新为新数据时,窗口将保留在那里。

    请注意,matplotlib 动画模块可能是生成此示例中显示的绘图的不错选择。但是,我无法使动画与交互式绘图一起使用,因此它会阻止其他代码的进一步执行。这就是为什么我不能在我的实际应用程序中使用动画模块的原因。

    import matplotlib
    matplotlib.use('TkAgg')
    import matplotlib.pyplot as plt
    import time
    from random import random
    
    print ( matplotlib.__version__ )
    
    # set up the figure
    plt.ion()
    fig = plt.figure()
    ax = plt.subplot(1,1,1)
    ax.set_xlabel('Time')
    ax.set_ylabel('Value')
    t = []
    y = []
    ax.plot( t , y , 'ko-' , markersize = 10 ) # add an empty line to the plot
    fig.show() # show the window (figure will be in foreground, but the user may move it to background)
    
    # plot things while new data is generated:
    # (avoid calling plt.show() and plt.pause() to prevent window popping to foreground)
    t0 = time.time()
    while True:
        t.append( time.time()-t0 )  # add new x data value
        y.append( random() )        # add new y data value
        ax.lines[0].set_data( t,y ) # set plot data
        ax.relim()                  # recompute the data limits
        ax.autoscale_view()         # automatic axis scaling
        fig.canvas.flush_events()   # update the plot and take care of window events (like resizing etc.)
        time.sleep(1)               # wait for next loop iteration
    

    【讨论】:

    • 如果您因使用 time.sleep 而遇到 UI 问题,例如无法移动/调整窗口大小,请查看此答案 stackoverflow.com/a/45734500/277267,这在某种程度上是对 @ 的重新实现987654327@方法。
    • 如果你只是更新行并且不需要其他重新缩放等,你可以将plt.pause()替换为fig.canvas.flush_events()。这是关键调用差异
    • 如果我可以将此答案标记为有用一百次,我当然会这样做。非常感谢你的代码 sn-p,它工作得很好:)
    • matplotlib 让我很头疼...当使用 Qt 作为后端 (matplotlib.use('Qt5Agg')) 时,您需要在 flush_events 调用之前插入一个fig.canvas.draw_idle()...
    猜你喜欢
    • 2017-09-25
    • 2011-06-30
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    • 1970-01-01
    • 2013-06-01
    • 2012-09-03
    • 2020-11-08
    相关资源
    最近更新 更多