「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > pyplotによるリアルタイムプロット

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

2024 年 11 月 8 日に公開
ブラウズ:548

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の答えにたどり着きます。引用すると:

軸の dataLim を更新してから、dataLim に基づいて軸の 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 に値を割り当てた場合にのみ更新されます。 lush_events() 呼び出しは「if」ステートメントの外側にあるため、頻繁に呼び出されていることに注意してください。

リリースステートメント この記事は次の場所に転載されています: https://dev.to/paxfeline/real-time-plotting-with-pyplot-2b3g?1 侵害がある場合は、[email protected] に連絡して削除してください。
最新のチュートリアル もっと>

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3