web-dev-qa-db-ja.com

更新ごとにインタラクティブなmatplotlibウィンドウが前面に表示されないようにする(Windows 7)

今日、私はmatplotlibをバージョン2.0.2にアップグレードしましたが、おそらく3年間アップグレードしませんでした。

これで、インタラクティブプロットではウィンドウが常に前面に表示されるという問題があります。これは、ここで matplotlibプロットウィンドウをアクティブウィンドウとしてポップアップ表示する がデフォルトの動作になったかのようです。

どうすれば無効にできますか? 5秒ごとにウィンドウが前面に表示されて、テキストエディター、ブラウザーなどが表示されないようにしたい...

アクティブウィンドウの前面または背面のどちらに配置しても、配置したZオーダーのままにしておきます。

2016年1月31日の次のコミットがこの問題のある動作の原因であると思います: tkagg:それぞれの新しいウィンドウを上げる;部分的に#596に対処

Githubに関連するコメントが見つかりました https://github.com/matplotlib/matplotlib/issues/596#issuecomment-305298577

この問題を引き起こしているのはplt.pauseへの私の呼び出しであり、plt.plotの呼び出しではないようです。

13
Daniel F

バックエンドを変更する

この問題は、Tkバックエンドを使用した場合にのみ発生するようです。 Qtバックエンドを使用すると、ウィンドウは、_plt.pause_で更新しているときと同じ場所にとどまります。

バックエンドを変更するには、スクリプトの先頭でこれらの行を使用します。

_import matplotlib
matplotlib.use("Qt4agg") # or "Qt5agg" depending on you version of Qt
_

_plt.pause_の変更

バックエンドを変更できない場合は、次の方法が役立つことがあります。ウィンドウが常に前面にポップアップする原因は、_plt.pause_が内部でplt.show()を呼び出すことにあります。したがって、pauseを呼び出さずに、独自のshow関数を実装します。これは、最初にplt.ion()をインタラクティブモードにしてから、少なくとも1回はplt.show()を呼び出す必要があります。その後、以下に示すように、カスタムmypause関数を使用してプロットを更新できます。

_import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
from time import time
from random import random

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

plt.show(block=False)

def mypause(interval):
    backend = plt.rcParams['backend']
    if backend in matplotlib.rcsetup.interactive_bk:
        figManager = matplotlib._pylab_helpers.Gcf.get_active()
        if figManager is not None:
            canvas = figManager.canvas
            if canvas.figure.stale:
                canvas.draw()
            canvas.start_event_loop(interval)
            return


t0 = time()
t = []
y = []
while True:
    t.append( time()-t0 )
    y.append( random() )
    plt.gca().clear()
    plt.plot( t , y )
    mypause(1)
_

animationを使用します。

最後に、_matplotlib.animation_クラスを使用すると、上記のすべてが廃止されます。 _matplotlib.animation.FuncAnimation_の例を示します matplotlibページ

Macでも同じ問題が発生しました。これが最善の方法かどうかはわかりませんが、plt.pause(0.001)を使用する代わりに、fig.canvas.start_event_loop(0.001)に切り替えて、アニメーションの各フレームを更新しました。これにより、ウィンドウをバックグラウンドに留めることができます。

4
DanHickstein

これは2019年4月で、Matplotlib 3.0.3のmypause()関数(最新のpyplot実装からコピー)は次のようになります。

import time
import matplotlib.pyplot as plt
def mypause(interval):
    manager = plt._pylab_helpers.Gcf.get_active()
    if manager is not None:
        canvas = manager.canvas
        if canvas.figure.stale:
            canvas.draw_idle()        
        #plt.show(block=False)
        canvas.start_event_loop(interval)
    else:
        time.sleep(interval)

いくつかのテスト(Qt5バックエンド/ Spyder/Windows 7 64ビット)の後、私にとってトリックとなる呼び出しは次のとおりです。

#plt.pause(0.001) #Brings plot to foreground
#fig.canvas.draw() #Does not work
#plt.draw_all() #Does not work
#plt.draw() #Does not work
#fig.canvas.flush_events() #Updates only if I click the figure 
#import time; time.sleep(0.001) #Does not help flush_events()
#fig.canvas.draw_idle() #Does not work by itself
#fig.canvas.start_event_loop(0.001) #Does not work by itself
#mypause(0.001) #Works!

#Works!
fig.canvas.draw_idle()
fig.canvas.start_event_loop(0.001)

イチジクはあなたのフィギュアオブジェクトでした。私の場合、どちらも単独では機能しませんでした。 animation のドキュメントによると、これは本質的にFuncAnimationが行うことです。

4
pepgma

このドキュメントページの助けを借りて、matplotlib.animationを使用するようにコードを書き直しました https://matplotlib.org/devdocs/api/animation_api.html#module-matplotlib.animation

私はこのページからそのページに到達しました https://matplotlib.org/devdocs/api/_as_gen/matplotlib.pyplot.pause.html

matplotlib.pyplot.pauseについて次のように述べています

これは粗雑なアニメーションに使用できます。より複雑なアニメーションについては、matplotlib.animationを参照してください。

この関数は実験的です。その動作は将来のリリースで変更または拡張される可能性があります。

0
Daniel F