計算を続行できるようにmatplotlibプロットを分離する方法はありますか?


258

Pythonインタープリターでのこれらの指示の後、プロットのあるウィンドウが表示されます。

from matplotlib.pyplot import *
plot([1,2,3])
show()
# other code

残念show()ながら、プログラムがさらに計算を行っている間に作成された図をインタラクティブに探索し続ける方法がわかりません。

まったく可能ですか?場合によっては計算が長くなり、中間結果の調査中に進めると役立ちます。


5
16:52にnoskloから選択したソリューションが機能していることを確認できません。私にとって、ドローはプロットを表示するウィンドウを開かず、解決策を表示するのは最後のブロッキングショーだけです。しかし、17:00からの彼の回答は正しい。経由でインタラクティブモードをオンにion()すると、問題が解決します。
H.ブランズマイヤー、2011

上級プログラマであればos.fork()使用os.fork()できますが、古いプロセスをコピーして新しいプロセスを作成しているため、使用が難しい場合があることに注意してください。
Trevor Boyd Smith

回答:


214

matplotlibブロックしないの呼び出しを使用します。

使用draw()

from matplotlib.pyplot import plot, draw, show
plot([1,2,3])
draw()
print 'continue computation'

# at the end call show to ensure window won't close.
show()

インタラクティブモードの使用:

from matplotlib.pyplot import plot, ion, show
ion() # enables interactive mode
plot([1,2,3]) # result shows immediatelly (implicit draw())

print 'continue computation'

# at the end call show to ensure window won't close.
show()

28
matplotlib 0.98.3では、正しいインポートはmatplotlib.pyplotインポートプロットから行われ、描画、表示
meteore

112
draw()私にとっては機能しません。ウィンドウが開きません。ただし、show(block=False)代わりにを使用するとdraw()、matplotlib 1.1でトリックが実行されるようです。
ランペル2013年

4
@nosklo、見ましたか?あなたはそれをpython チュートリアルにした
Jan

4
@noskolo複数の図がある場合、背景を続けながらFig1をプロットして表示する方法は?次の図が生成されるまでこの図を開いておきたいので、最後にすべての図を開いてコードを完成させます。あなたの現在の解決策では、Fig1を閉じるのを待ってからコードを続行します。ありがとう!!
physiker 2016年

9
draw()私もpause(0.001)
うまくいき

133

キーワード 'block'を使用して、ブロッキング動作をオーバーライドします。例:

from matplotlib.pyplot import show, plot

plot(1)  
show(block=False)

# your code

コードを続行します。


17
しかし、これはプロットウィンドウをすぐに閉じ、プロットを開いたままにしません。
LWZ 2013

8
ええ、コマンドラインからスクリプトを呼び出す場合はそうです。Ipythonシェルを使用している場合、ウィンドウは閉じられません。
2013

1
一般的なケースでウィンドウを開いたままにするトリックについては、@ Nicoの回答を確認してください。
Jan

2
私にとっては、これはウィンドウがすぐに閉じるのではなく、スクリプトが終了したときだけです(そのため、スクリプトを開いたままにしたい場合は、スクリプトの最後で手動でブロックできます)。
Luator

はい、ブロックされていないウィンドウは、スクリプトが終了すると閉じます。(a)最後のプロットでのブロッキングを許可するか、(b)スクリプトを終了しない(おそらく、「<Enter>を押してプロットを終了する」などの入力を求める)ことができます。
ダニエルゴールドファーブ

29

ノンブロッキングでの使用がサポートされている場合は、使用しているライブラリを常に確認することをお勧めします。

しかし、より一般的なソリューションが必要な場合、または他に方法がない場合はmultprocessing、Pythonに含まれているモジュールを使用して、別のプロセスでブロックするものを実行できます。計算は続行されます:

from multiprocessing import Process
from matplotlib.pyplot import plot, show

def plot_graph(*args):
    for data in args:
        plot(data)
    show()

p = Process(target=plot_graph, args=([1, 2, 3],))
p.start()

print 'yay'
print 'computation continues...'
print 'that rocks.'

print 'Now lets wait for the graph be closed to continue...:'
p.join()

これは、新しいプロセスを起動するオーバーヘッドがあり、複雑なシナリオでデバッグするのが難しい場合があるため、他のソリューション(matplotlib非ブロッキングAPI呼び出しを使用)を使用します


ありがとう!私のシステムにはまだPython 2.6がないので、Processingの代わりにthreading.Threadを使用しました。後続の印刷ステートメントが耐えられないほど遅くなるのを観察しました(3番目の印刷、1分間待機した後でKeyboardInterruptを発行しました)。これはマルチプロセッシングの代わりにスレッディングを使用することの影響ですか?
隕石2009年

@meteore:はい、スレッディングは最悪です。ここからいつでもpython <2.6のマルチプロセッシングを取得できます:pyprocessing.berlios.de
nosklo

これは絶対に素晴らしいです。プロットウィンドウが閉じられるまで、Emacs(Pythonモード)で印刷ステートメントが実行されない理由を知っていますか?
隕石2009年

Ubuntu 8.10(Intrepid)では、パッケージ(python <2.6用)はpython-processingと呼ばれ、 'import processing'でインポートします
meteore

1
あなたは逃しませんでしたif __name__ == '__main__':か?
平日

25

試す

import matplotlib.pyplot as plt
plt.plot([1,2,3])
plt.show(block=False)
# other code
# [...]

# Put
plt.show()
# at the very end of your script to make sure Python doesn't bail out
# before you finished examining.

show()ドキュメントは言います:

非インタラクティブモードでは、すべての図を表示し、図が閉じるまでブロックします。インタラクティブモードでは、非インタラクティブモードからインタラクティブモードに変更する前に図形が作成されていない限り、効果はありません(非推奨)。その場合、図は表示されますがブロックされません。

単一の実験的なキーワード引数であるblockをTrueまたはFalseに設定して、上記のブロッキング動作をオーバーライドできます。


なぜdraw();を使わないのか [。その他のコード]; 公演() ?私の知る限り、block = Falseは廃止されました
Bogdan

なぜ廃止されたと思いますか?ここに文書化されているのがわかります
NicoSchlömer2016

11

重要:明確にするために。コマンドは.pyスクリプト内にあり、スクリプトはpython script.pyコンソールなどから呼び出されると想定しています。

私のために働く簡単な方法は:

  1. show内でblock = Falseを使用します:plt.show(block = False)
  2. .pyスクリプトの最後別の show()使用します。

script.pyファイルの

plt.imshow(*something*)                                                               
plt.colorbar()                                                                             
plt.xlabel("true ")                                                                   
plt.ylabel("predicted ")                                                              
plt.title(" the matrix")  

# Add block = False                                           
plt.show(block = False)

################################
# OTHER CALCULATIONS AND CODE HERE ! ! !
################################

# the next command is the last line of my script
plt.show()



8

私の場合、計算中にいくつかのウィンドウをポップアップさせたいと思っていました。参考までに、これは方法です:

from matplotlib.pyplot import draw, figure, show
f1, f2 = figure(), figure()
af1 = f1.add_subplot(111)
af2 = f2.add_subplot(111)
af1.plot([1,2,3])
af2.plot([6,5,4])
draw() 
print 'continuing computation'
show()

PS。matplotlibのOOインターフェースに関する非常に役立つガイド


6

さて、非ブロッキングコマンドを理解するのに非常に苦労しました...しかし、最後に、「Cookbook / Matplotlib / Animations-選択したプロット要素のアニメーション」の例をやり直すことができたので、スレッドで機能しますPipeそして、スレッド間でデータを渡します Ubuntu 10.04のPython 2.6.5のグローバル変数またはマルチプロセスを介して)。

スクリプトはここにあります:Animating_selected_plot_elements - thread.py-参照用に以下に貼り付けます(コメントを少なくして):

import sys
import gtk, gobject
import matplotlib
matplotlib.use('GTKAgg')
import pylab as p
import numpy as nx 
import time

import threading 



ax = p.subplot(111)
canvas = ax.figure.canvas

# for profiling
tstart = time.time()

# create the initial line
x = nx.arange(0,2*nx.pi,0.01)
line, = ax.plot(x, nx.sin(x), animated=True)

# save the clean slate background -- everything but the animated line
# is drawn and saved in the pixel buffer background
background = canvas.copy_from_bbox(ax.bbox)


# just a plain global var to pass data (from main, to plot update thread)
global mypass

# http://docs.python.org/library/multiprocessing.html#pipes-and-queues
from multiprocessing import Pipe
global pipe1main, pipe1upd
pipe1main, pipe1upd = Pipe()


# the kind of processing we might want to do in a main() function,
# will now be done in a "main thread" - so it can run in
# parallel with gobject.idle_add(update_line)
def threadMainTest():
    global mypass
    global runthread
    global pipe1main

    print "tt"

    interncount = 1

    while runthread: 
        mypass += 1
        if mypass > 100: # start "speeding up" animation, only after 100 counts have passed
            interncount *= 1.03
        pipe1main.send(interncount)
        time.sleep(0.01)
    return


# main plot / GUI update
def update_line(*args):
    global mypass
    global t0
    global runthread
    global pipe1upd

    if not runthread:
        return False 

    if pipe1upd.poll(): # check first if there is anything to receive
        myinterncount = pipe1upd.recv()

    update_line.cnt = mypass

    # restore the clean slate background
    canvas.restore_region(background)
    # update the data
    line.set_ydata(nx.sin(x+(update_line.cnt+myinterncount)/10.0))
    # just draw the animated artist
    ax.draw_artist(line)
    # just redraw the axes rectangle
    canvas.blit(ax.bbox)

    if update_line.cnt>=500:
        # print the timing info and quit
        print 'FPS:' , update_line.cnt/(time.time()-tstart)

        runthread=0
        t0.join(1)   
        print "exiting"
        sys.exit(0)

    return True



global runthread

update_line.cnt = 0
mypass = 0

runthread=1

gobject.idle_add(update_line)

global t0
t0 = threading.Thread(target=threadMainTest)
t0.start() 

# start the graphics update thread
p.show()

print "out" # will never print - show() blocks indefinitely! 

これが誰かを助けることを願って、
乾杯!


5

多くの場合、画像を保存する方が便利ですを.pngファイルとしてハードドライブにです。理由は次のとおりです。

利点:

  • あなたはそれを開いて、それを見て、プロセス中いつでもそれを閉じることができます。これは、アプリケーションが長時間実行されている場合に特に便利です。
  • 何もポップアップせず、ウィンドウを開く必要はありません。これは、多くの数値を扱う場合に特に便利です。
  • 画像は後で参照できるようにアクセスでき、Figureウィンドウを閉じても失われません。

欠点:

  • 私が考えることができる唯一のことは、あなたはフォルダーを見つけて自分で画像を開く必要があるということです。

たくさんの画像を生成しようとしているのなら、心から同意します。
2014年

6
ドローバックpngはインタラクティブではありません:\

5

コンソールで作業している場合、つまり、他の回答で指摘されているようにIPython使用できplt.show(block=False)ます。ただし、怠惰な場合は、次のように入力します。

plt.show(0)

どちらも同じです。


5

またplt.pause(0.001)、コードを追加して、実際にforループ内で機能させる必要があります(そうしないと、最初と最後のプロットしか表示されません)。

import matplotlib.pyplot as plt

plt.scatter([0], [1])
plt.draw()
plt.show(block=False)

for i in range(10):
    plt.scatter([i], [i+1])
    plt.draw()
    plt.pause(0.001)

これは、macOSでmatplotlib3を使用して動作しました。すごい!
ジェリーMa

4

私のシステムではshow()はブロックしませんが、続行する前にユーザーがグラフと対話する(そして 'pick_event'コールバックを使用してデータを収集する)のをスクリプトに待機させたいと思いました。

プロットウィンドウが閉じるまで実行をブロックするために、私は以下を使用しました:

fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(x,y)

# set processing to continue when window closed
def onclose(event):
    fig.canvas.stop_event_loop()
fig.canvas.mpl_connect('close_event', onclose)

fig.show() # this call does not block on my system
fig.canvas.start_event_loop_default() # block here until window closed

# continue with further processing, perhaps using result from callbacks

ただし、canvas.start_event_loop_default()が次の警告を生成したことに注意してください。

C:\Python26\lib\site-packages\matplotlib\backend_bases.py:2051: DeprecationWarning: Using default event loop until function specific to this GUI is implemented
  warnings.warn(str,DeprecationWarning)

スクリプトはまだ実行されましたが。


ありがとうございました!Spyderは-pylabを起動時にインポートしますが、これは一般的には便利ですが、ioff()の実行時にshow()がブロックしないことを意味します。これにより、この動作を修正できます。
負け

3

エラーが発生した場合でも、プロットに残りのコードを実行して表示し続けたいと思っていました(その後も表示を続けます)(デバッグにプロットを使用することもあります)。この小さなハックをコード化して、このwithステートメント内のプロットがそのように動作するようにしました。

これはおそらく少し標準的ではなく、量産コードにはお勧めできません。このコードには、おそらく多くの隠された「落とし穴」があります。

from contextlib import contextmanager

@contextmanager
def keep_plots_open(keep_show_open_on_exit=True, even_when_error=True):
    '''
    To continue excecuting code when plt.show() is called
    and keep the plot on displaying before this contex manager exits
    (even if an error caused the exit).
    '''
    import matplotlib.pyplot
    show_original = matplotlib.pyplot.show
    def show_replacement(*args, **kwargs):
        kwargs['block'] = False
        show_original(*args, **kwargs)
    matplotlib.pyplot.show = show_replacement

    pylab_exists = True
    try:
        import pylab
    except ImportError: 
        pylab_exists = False
    if pylab_exists:
        pylab.show = show_replacement

    try:
        yield
    except Exception, err:
        if keep_show_open_on_exit and even_when_error:
            print "*********************************************"
            print "Error early edition while waiting for show():" 
            print "*********************************************"
            import traceback
            print traceback.format_exc()
            show_original()
            print "*********************************************"
            raise
    finally:
        matplotlib.pyplot.show = show_original
        if pylab_exists:
            pylab.show = show_original
    if keep_show_open_on_exit:
        show_original()

# ***********************
# Running example
# ***********************
import pylab as pl
import time
if __name__ == '__main__':
    with keep_plots_open():
        pl.figure('a')
        pl.plot([1,2,3], [4,5,6])     
        pl.plot([3,2,1], [4,5,6])
        pl.show()

        pl.figure('b')
        pl.plot([1,2,3], [4,5,6])
        pl.show()

        time.sleep(1)
        print '...'
        time.sleep(1)
        print '...'
        time.sleep(1)
        print '...'
        this_will_surely_cause_an_error

適切な「エラーが発生した場合でもプロットを開いたままにして、新しいプロットを表示できるようにする」を実装する場合、ユーザーの干渉が他に指示しない限り(バッチ実行の目的で)スクリプトを適切に終了します。

私はタイムアウトの質問のようなものを使用するかもしれません「スクリプトの終了!\ nプロット出力を一時停止したい場合は、pを押してください(5秒あります):」/programming/26704840/corner -cases-for-my-wait-for-user-input-interruption-implementation


2
plt.figure(1)
plt.imshow(your_first_image)

plt.figure(2)
plt.imshow(your_second_image)

plt.show(block=False) # That's important 

raw_input("Press ENTER to exist") # Useful when you run your Python script from the terminal and you want to hold the running to see your figures until you press Enter

16
存在する前に、どのように押しますか?
grovina 2017年

2

OPは、matplotlibプロットのデタッチについて尋ねます。ほとんどの回答は、Pythonインタープリター内からのコマンド実行を想定しています。ここに示すユースケースは、ターミナル(bashなど)でコードをテストするための私の好みです。file.pyが実行され、プロットが表示され、Pythonスクリプトが完了してコマンドプロンプトに戻る。

このスタンドアロンファイルは、multiprocessingを使用してデータをプロットするための別のプロセスを起動するために使用しますmatplotlib。メインスレッドはos._exit(1)この投稿で述べたように終了します。os._exit()出口までの主な勢力が、葉matplotlibのプロットウィンドウが閉じられるまで生きていると応答性の子プロセスを。それは完全に別のプロセスです。

このアプローチは、応答性の高いコマンドプロンプトが表示されるFigureウィンドウを使用したMatlab開発セッションに少し似ています。このアプローチを使用すると、Figureウィンドウプロセスとの連絡がすべて失われますが、開発とデバッグには問題ありません。ウィンドウを閉じてテストを続けるだけです。

multiprocessingはPythonのみのコード実行用に設計されているため、に比べておそらくより適していsubprocessます。multiprocessingクロスプラットフォームなので、これはWindowsまたはMacでほとんどまたはまったく調整せずにうまく機能します。基盤となるオペレーティングシステムを確認する必要はありません。これはLinux、Ubuntu 18.04LTSでテストされました。

#!/usr/bin/python3

import time
import multiprocessing
import os

def plot_graph(data):
    from matplotlib.pyplot import plot, draw, show
    print("entered plot_graph()")
    plot(data)
    show() # this will block and remain a viable process as long as the figure window is open
    print("exiting plot_graph() process")

if __name__ == "__main__":
    print("starting __main__")
    multiprocessing.Process(target=plot_graph, args=([1, 2, 3],)).start()
    time.sleep(5)
    print("exiting main")
    os._exit(0) # this exits immediately with no cleanup or buffer flushing

ランニング file.pyすると、Figureウィンドウが表示されてから__main__終了しますが、multiprocessing+ matplotlibFigureウィンドウは独立したプロセスであるため、ズーム、パン、その他のボタンで応答し続けます。

次のコマンドを使用して、bashコマンドプロンプトでプロセスを確認します。

ps ax|grep -v grep |grep file.py


私はあなたの解決策を使おうとしましたが、それは私にはうまくいかないようで、その理由を理解しようとしています。私はターミナルを介してコードを実行していませんが、違いがある場合はPycharm IDEから実行していますが、違いはありません。
ttsesm

1
はい、最終的に私のために働いたのは、子プロセスを .daemon=False、ここで説明したようstackoverflow.com/a/49607287/1476932しかし、sys.exit()そこに記載されているように私は、子ウィンドウを閉じまで、親プロセスが終了していませんでした。一方os._exit(0)、上記の例から使用するとうまくいきました。
ttsesm


0

複数の図を開きたいが、それらをすべて開いたままにしたい場合、このコードは私にとってはうまくいきました:

show(block=False)
draw()

show(block = False)は廃止され、現在は機能していません
Bogdan

0

OPのリクエストに直接応答することはできませんが、この回避策を投稿すると、この状況で誰かを助ける可能性があります。

  • プロットを生成する必要がある場所にpythonをインストールできないため、pyinstallerで.exeを作成しています。プロットを生成し、.pngとして保存して閉じ、次の手順に進み、いくつかのプロットとして実装します。ループまたは関数の使用。

このイムを使用して:

import matplotlib.pyplot as plt
#code generating the plot in a loop or function
#saving the plot
plt.savefig(var+'_plot.png',bbox_inches='tight', dpi=250) 
#you can allways reopen the plot using
os.system(var+'_plot.png') # unfortunately .png allows no interaction.
#the following avoids plot blocking the execution while in non-interactive mode
plt.show(block=False) 
#and the following closes the plot while next iteration will generate new instance.
plt.close() 

「var」はループ内のプロットを識別するため、上書きされません。


-1

使用する plt.show(block=False)、スクリプトの呼び出しの最後にplt.show()

これにより、スクリプトが終了したときにウィンドウが閉じないようになります。


@nico-schlömerの回答をご覧ください
Josh Wolff
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.