Matplotlibを使用してノンブロッキングでプロットする


138

ここ数日、Numpyとmatplotlibを使っています。実行をブロックせずにmatplotlibを関数にプロットしようとすると問題が発生します。SOには同様の質問をするスレッドがすでにたくさんあることを知っています。かなりググってみましたが、うまくいきませんでした。

一部の人が示唆するように、show(block = False)を使用してみましたが、取得できるのはフリーズしたウィンドウだけです。単にshow()を呼び出すと、結果は正しくプロットされますが、ウィンドウが閉じられるまで実行はブロックされます。私が読んだ他のスレッドから、show(block = False)が機能するかどうかはバックエンドに依存していると思います。これは正しいです?私のバックエンドはQt4Aggです。私のコードを見て、何かおかしいと思ったら教えてください。これが私のコードです。助けてくれてありがとう。

from math import *
from matplotlib import pyplot as plt
print plt.get_backend()



def main():
    x = range(-50, 51, 1)
    for pow in range(1,5):   # plot x^1, x^2, ..., x^4

        y = [Xi**pow for Xi in x]
        print y

        plt.plot(x, y)
        plt.draw()
        #plt.show()             #this plots correctly, but blocks execution.
        plt.show(block=False)   #this creates an empty frozen window.
        _ = raw_input("Press [enter] to continue.")


if __name__ == '__main__':
    main()

PS。新しいウィンドウを作成するのではなく、何かをプロットするたびに既存のウィンドウを更新することを忘れていました。


1
plt.ion()以前にmatplotlibインタラクティブモードを試しましたplt.show()か?その後、各プロットが子スレッドに生成されるので、それは非ブロッキングになるはずです。
Anzel、2015

@Anzel私は試してみましたが、違いはないようです。
opetroch

3
スクリプトをどのように実行していますか?端末/コマンドプロンプトからサンプルコードを実行すると、問題なく動作するように見えますが、IPython QtConsoleまたはIDEからこのようなことを行おうとすると、以前は問題があったと思います。
マリウス

1
@マリウスああ!! あなたが正しいです。実際、IDE(PyCharm)のコンソールから実行しています。コマンドプロンプトから実行すると、plt.show(block = False)は正常に動作します。あなたがそのアイデア/解決策を見つけたかどうか尋ねてもらえますか?どうもありがとう!
opetroch 2015

すみません、本当にわかりません。matplotlibがコンソールと対話する方法の詳細を本当に理解していないので、通常、でこれを行う必要がある場合は、コマンドプロンプトからの実行に切り替えますmatplotlib
マリウス

回答:


167

私は長い間解決策を探していましたが、この答えを見つけました。

それは、あなた(そして私)が望むものを手に入れるためにplt.ion()plt.show()(とではなくblock=False)と、そして最も重要なことには、plt.pause(.001)(またはあなたが望むいつでも)の組み合わせが必要であるように見えます。一時停止は、メインのコードは、図面を含め、寝ている間、GUIのイベントが発生したため、必要とされています。これは、スリープ状態のスレッドから時間を取得することによって実装される可能性があるため、IDEがそれを混乱させる可能性があります。

Python 3.5で動作する実装は次のとおりです。

import numpy as np
from matplotlib import pyplot as plt

def main():
    plt.axis([-50,50,0,10000])
    plt.ion()
    plt.show()

    x = np.arange(-50, 51)
    for pow in range(1,5):   # plot x^1, x^2, ..., x^4
        y = [Xi**pow for Xi in x]
        plt.plot(x, y)
        plt.draw()
        plt.pause(0.001)
        input("Press [enter] to continue.")

if __name__ == '__main__':
    main()

3
あなたの答えは、私が抱えていた同様の問題を解決するのに大いに役立ちました。以前はplt.draw続いていましたplt.show(block = False)が、機能しなくなりました。Figureが応答せず、閉じるとiPythonがクラッシュしました。私の解決策はのすべてのインスタンスを削除plt.draw()してそれをに置き換えることplt.pause(0.001)でした。以前はplt.show(block = False)like plt.drawが続いていたのではなく、plt.ion()and が前に付いていましたplt.show()。私は今持ってMatplotlibDeprecationWarningいますが、それは私の数字をプロットすることができたので、この解決策に満足しています。
blue_chip 2016年

3
Python 2.7ではraw_inputnot を使用する必要があることに注意してくださいinputここを
クリス

リアクティブな「アニメーション」アプローチが不可能な場合の本当に役立つ回避策!誰かが非推奨警告を取り除く方法を知っていますか?
フレデリックフォーティア2017

plt.showの前にplt.ionを追加しようとすると、なぜフリーズしたコマンドプロンプトが表示されるのですか?
Gabriel Augusto

@GabrielAugusto何が原因かわからないので、あなたの言っていることがよくわかりません。この例をPython 3.6でテストしたところ、まだ動作しています。同じパターンを使用してフリーズした場合は、インストールに問題がある可能性があります。通常のプロットが最初に機能するかどうかを確認する必要があります。別のことを試した場合、コメントでそれについて行うことは多くありません。どちらの場合も、別の質問をすることを検討してください。
krs013 2017年

23

私にとってうまくいく簡単なトリックは次のとおりです:

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

import matplotlib.pyplot as plt

plt.imshow(add_something)
plt.xlabel("x")
plt.ylabel("y")

plt.show(block=False)

#more code here (e.g. do calculations and use print to see them on the screen

plt.show()

plt.show()は私のスクリプトの最後の行です。


7
これにより(私にとっては、Linux、Anaconda、Python 2.7、デフォルトのバックエンド)空白のウィンドウが生成され、実行が終了するまで空白のままになります。最終的には、このウィンドウが埋められます。実行の途中でプロットを更新するのには役立ちません。:-(
sh37211

@ sh37211あなたの目標がわからない。何かをプロットしようとしたが、plotコマンドの後に他のコマンドがある場合、他のコマンドをプロットして実行できるため、これは便利です。詳細については、この投稿を参照してください:stackoverflow.com/questions/458209/…。プロットを更新したい場合は、別の方法である必要があります。
セラルーク

17

プロットを配列に書き込んでから、別のスレッドで配列を表示することにより、実行のブロックを回避できます。これは、pyformulas 0.2.8からpf.screenを使用してプロットを同時に生成および表示する例です。

import pyformulas as pf
import matplotlib.pyplot as plt
import numpy as np
import time

fig = plt.figure()

canvas = np.zeros((480,640))
screen = pf.screen(canvas, 'Sinusoid')

start = time.time()
while True:
    now = time.time() - start

    x = np.linspace(now-2, now, 100)
    y = np.sin(2*np.pi*x) + np.sin(3*np.pi*x)
    plt.xlim(now-2,now+1)
    plt.ylim(-3,3)
    plt.plot(x, y, c='black')

    # If we haven't already shown or saved the plot, then we need to draw the figure first...
    fig.canvas.draw()

    image = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
    image = image.reshape(fig.canvas.get_width_height()[::-1] + (3,))

    screen.update(image)

#screen.close()

結果:

サインアニメーション

免責事項:私はpyformulasのメンテナーです。

参照: Matplotlib:プロットをnumpy配列に保存


9

これらの答えの多くは非常に膨らんでおり、私が見つけることができるものから、答えを理解するのはそれほど難しくありません。

plt.ion()必要に応じて使用できますが、plt.draw()同じくらい効果的に使用していることがわかりました

私の特定のプロジェクトでは、画像をプロットしていますが、の代わりにplot()またはscatter()または何でも使用できますがfigimage()、それは問題ではありません。

plt.figimage(image_to_show)
plt.draw()
plt.pause(0.001)

または

fig = plt.figure()
...
fig.figimage(image_to_show)
fig.canvas.draw()
plt.pause(0.001)

実際のフィギュアを使用している場合。
私は@ krs013と@Default Pictureの回答を使用してこれを理解しました。
うまくいけば、誰かが別のスレッドですべての図を起動したり、これらの小説を読んでこれを理解したりする必要がなくなります


3

ライブプロット

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2 * np.pi, 100)
# plt.axis([x[0], x[-1], -1, 1])      # disable autoscaling
for point in x:
    plt.plot(point, np.sin(2 * point), '.', color='b')
    plt.draw()
    plt.pause(0.01)
# plt.clf()                           # clear the current figure

データ量が多すぎる場合は、単純なカウンターで更新率を下げることができます

cnt += 1
if (cnt == 10):       # update plot each 10 points
    plt.draw()
    plt.pause(0.01)
    cnt = 0

プログラム終了後のプロットの保持

これは、満足のいく答えを見つけることができなかった私の実際の問題でした。スクリプトが終了した後(MATLABのように)閉じないプロットが必要でした。

考えてみると、スクリプトが終了するとプログラムが終了し、このようにプロットを保持する論理的な方法がないため、2つのオプションがあります。

  1. スクリプトの終了をブロックします(これはplt.show()であり、私が望んでいるものではありません)。
  2. 別のスレッドでプロットを実行する(複雑すぎる)

これは十分ではなかったので、箱の外で別の解決策を見つけました

SaveToFileおよび外部ビューアでの表示

このため、保存と表示の両方が高速で、ビューアがファイルをロックしてはいけません。 、コンテンツを自動的に更新する必要があります

保存するフォーマットの選択

ベクターベースのフォーマットは小さくて高速です

  • SVGは良いですが、デフォルトで手動更新が必要なWebブラウザーを除いて、に適したビューアーを見つけることはできません。
  • PDFはベクター形式をサポートでき、ライブ更新をサポートする軽量のビューアがあります

Live Updateを備えた高速軽量ビューア

PDFいくつかの良いオプションがあります

  • WindowsのI使用上のSumatraPDF無料、高速かつ軽量である(唯一の私の場合のために1.8メガバイトのRAMを使用しています)

  • Linuxでは、Evince(GNOME)やOcular(KDE)など、いくつかのオプションがあります。

サンプルコードと結果

プロットをファイルに出力するためのサンプルコード

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(2 * x)
plt.plot(x, y)
plt.savefig("fig.pdf")

最初の実行後、上記のビューアのいずれかで出力ファイルを開いて楽しんでください。

これは、SumatraPDFと一緒のVSCodeのスクリーンショットです。また、プロセスは、セミライブ更新レートを取得するのに十分な速さです(セットアップtime.sleep()間で使用するだけで、セットアップで10Hz近くになることがあります)。 pyPlot、非ブロッキング


2

Iggyの答えは私がフォローするのが最も簡単subplotでしたが、私が行っていたときにそこになかった後続のコマンドを実行すると、次のエラーが発生しましたshow

MatplotlibDeprecationWarning:以前のAxesと同じ引数を使用してAxesを追加すると、現在以前のインスタンスが再利用されます。将来のバージョンでは、新しいインスタンスが常に作成されて返されます。一方、各軸インスタンスに一意のラベルを渡すことにより、この警告を抑制し、将来の動作を保証できます。

このエラーを回避するには、ユーザーがEnterキーを押した後にプロットを閉じる(またはクリアする)のを助けます。

これが私のために働いたコードです:

def plt_show():
    '''Text-blocking version of plt.show()
    Use this instead of plt.show()'''
    plt.draw()
    plt.pause(0.001)
    input("Press enter to continue...")
    plt.close()

0

Pythonパッケージのdrawowを使用すると、プロットをリアルタイムでブロックしない方法で更新できます。
また、WebカメラやOpenCVと連携して、各フレームのメジャーをプロットすることもできます。元の投稿を
参照してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.