ホームページ  >  記事  >  バックエンド開発  >  pyplotによるリアルタイムプロット

pyplotによるリアルタイムプロット

王林
王林オリジナル
2024-09-03 17:17:02664ブラウズ

Real-time plotting with pyplot

単純な投票アプリから生成したデータをグラフにしたいと思いました。私は過去に py​​plot をいじったことがありますが、最初から何かを作成しようとしたことはありません。幸いなことに、これは非常に人気があり、StackOverflow などでたくさんの例が見つかります。

私は検索を行って、時間の経過に伴うグラフの更新に関連するこのSOの回答から始めました。

import matplotlib.pyplot as plt
import numpy as np

# You probably won't need this if you're embedding things in a tkinter plot...
plt.ion()

x = np.linspace(0, 6*np.pi, 100)
y = np.sin(x)

fig = plt.figure()
ax = fig.add_subplot(111)
line1, = ax.plot(x, y, 'r-') # Returns a tuple of line objects, thus the comma

for phase in np.linspace(0, 10*np.pi, 500):
    line1.set_ydata(np.sin(x + phase))
    fig.canvas.draw()
    fig.canvas.flush_events()

このコードは、位相が変化する正弦波をアニメーション化します。

最初の 2 行は、使用したいライブラリをインポートします。matplotlib.pyplot は、GUI のプロットと処理を行います。

ion() メソッドは、理解できれば (理解できないかもしれませんが)、pyplot で GUI を駆動します。 tkinter プログラム内で使用したり、静的画像を生成するために使用したりすることもできますが、この場合、プロットの GUI を処理させるのが合理的です。 (これは、後での flash_events() 呼び出しが行っていることです。つまり、Figure ウィンドウとの対話性を可能にします。)

この例では、numpy メソッド linspace() を使用して x 値を作成します。これは、派手な Python リストである numpy 配列を返します。

math.sin の代わりに np.sin を使用する理由はブロードキャストです。これは、リスト内のすべての項目に関数を適用するための厄介な用語です。実際、map:
を使用して numpy を使わなくても同じことが達成できるのではないかと思いました。

map(lambda n: math.sin(n), x)

しかし、numpy ブロードキャストは便利で使いやすいです。

次に、pyplot のセットアップを行います。まず、新しい「図形」(fig)を作成します。この図にサブプロット (ax) を追加します。サブプロットは多数ある可能性があります。 111 には、「1x1 グリッドを作成し、このサブプロットを最初のセルに配置する」というかなり難解な解釈があります。

このサブプロット (または一連の軸) に、渡された x 値と y 値を使用して線がプロ​​ットされます。 (点は直線で結ばれ、連続的にプロットされます。)「r-」は、赤い実線を指定する短縮方法です。複数の行を指定できるため、plot() はタプルを返します。上記のコードは、タプルのアンパックを使用して、必要な 1 つの値を抽出します。

これは良いスタートですが、時間の経過とともに X 軸を拡張する必要があります。また、このコードは、必要に応じて y 軸の境界を更新しません。最初のプロットで計算された境界にロックされます。もう少し検索すると、このSOの答えにたどり着きます。それらを引用すると:

Axes の dataLim を更新してから、dataLim に基づいて Axes の viewLim を更新する必要があります。適切なメソッドは、axes.relim() メソッドと ax.autoscale_view() メソッドです。

確かに、いいですね。彼らの例に基づいて、x と y の両方で成長するデモ グラフを作成しました。

import matplotlib.pyplot as plt
import numpy as np
from threading import Thread
from time import sleep

x = list(map(lambda x: x / 10, range(-100, 100)))
x_next_max = 100
y = np.sin(x)

# You probably won't need this if you're embedding things in a tkinter plot...
plt.ion()

fig = plt.figure()
ax = fig.add_subplot(111)
line1 = ax.plot(x, y, 'r-')[0] # Returns a tuple of line objects

growth = 0

while True:
    x.append(x_next_max / 10)
    x_next_max += 1
    line1.set_xdata(x)
    line1.set_ydata(np.sin(x) + np.sin(np.divide(x, 100)) + np.divide(x, 100))
    ax.relim()
    ax.autoscale()
    fig.canvas.draw()
    fig.canvas.flush_events()

    sleep(0.1)

今、私はどこかに向かっています。しかし、これはブロッキング ループであり、データを時々更新する必要があります。複数のスレッドがある場合、変数の更新がスレッドセーフであるかどうかを心配する必要があります。この場合、変数は 5 分に 1 回しか更新されない (ポーリング関数が実行される頻度は同じ) ことがわかっているため、怠惰になる可能性があります。コード行の途中で変数が上書きされる危険はありません。

import matplotlib.pyplot as plt
import numpy as np
from threading import Timer
from time import sleep

x = list(map(lambda x: x / 10, range(-100, 100)))
x_next_max = 100
y = np.sin(x)

# You probably won't need this if you're embedding things in a tkinter plot...
plt.ion()

fig = plt.figure()
ax = fig.add_subplot(111)
line1 = ax.plot(x, y, 'r-')[0] # Plot returns a tuple of line objects

growth = 0
new_x = None

dT = 1

def grow():
    global new_x, x_next_max
    while True:
        new_x = x + [x_next_max / 10]
        x_next_max += 1
        sleep(dT) # grow every dT seconds

t = Thread(target=grow)
t.start()

while True:

    if new_x:
        x = new_x
        new_x = None
        line1.set_xdata(x)
        line1.set_ydata(np.sin(x) + np.sin(np.divide(x, 100)) + np.divide(x, 100))
        ax.relim()
        ax.autoscale()
        fig.canvas.draw()

    fig.canvas.flush_events()

    sleep(0.1)

グラフは、成長スレッドが new_x に値を割り当てた場合にのみ更新されます。 flash_events() 呼び出しは「if」ステートメントの外側にあるため、頻繁に呼び出されていることに注意してください。

以上がpyplotによるリアルタイムプロットの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。