web-dev-qa-db-ja.com

Matplotlibを使用した非ブロッキング方法でのプロット

私はここ数日で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 __== '__main__':
    main()

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

93
opetroch

私は解決策を探すのに長い時間を費やし、 この答え を見つけました。

あなた(そして私)が望むものを得るためには、plt.ion()plt.show()blocking=Falseではなく、非推奨です)、そして最も重要なこととしてplt.pause(.001)(またはあなたが望む時間)の組み合わせが必要です。 pause は、描画を含むメインコードがスリープしている間に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 __== '__main__':
    main()
125
krs013

私のために働く簡単なトリックは次のとおりです:

  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()は、スクリプトの最終行です。

16
serafeim

プロットを配列に書き込み、別のスレッドで配列を表示することにより、実行のブロックを回避できます。 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()

結果:

Sine animation

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

リファレンス: Matplotlib:プロットをnumpy配列に保存

11
Default picture

ライブプロット

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はベクター形式をサポートでき、ライブ更新をサポートする軽量ビューアがあります

ライブアップデートを備えた高速軽量ビューア

PDFには、いくつかの適切なオプションがあります

  • Windowsでは SumatraPDF を使用します。これは無料、高速、軽量です(私の場合は1.8MB 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,Non-Blocking

1
Ali80

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

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

このエラーを回避するには、ユーザーがEnterキーを押した後にプロットを閉じる(または clear )と役立ちます。

私のために働いたコードは次のとおりです:

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()
1
Pro Q

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

必要に応じて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の回答を使用してこれを把握しました
これにより、誰かが個別のスレッドですべての図を起動したり、これを理解するためだけにこれらの小説を読む必要がなくなります。

1
iggy12345

Pythonパッケージdrawnowを使用すると、非ブロッキング方式でリアルタイムにプロットを更新できます。
また、ウェブカメラやOpenCVと連携して、たとえば各フレームの測定値をプロットします。
元の投稿 を参照してください。

0
Ismael EL ATIFI