首頁 >後端開發 >Python教學 >使用 pyplot 進行即時繪圖

使用 pyplot 進行即時繪圖

王林
王林原創
2024-09-03 17:17:02703瀏覽

Real-time plotting with pyplot

我想繪製一些從簡單的投票應用程式產生的資料的圖表。我過去曾對 pyplot 進行過修改,但我沒有嘗試從頭開始創建任何東西。幸運的是,它非常受歡迎,並且在 StackOverflow 和其他地方可以找到大量範例。

我進行了搜索,並從這個與隨時間更新圖表相關的答案開始。

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()

此程式碼動畫正弦波變化階段。

前兩行導入我想要使用的函式庫:matplotlib.pyplot 進行繪圖和處理 GUI。

ion() 方法,如果我理解的話(儘管我可能不理解),使 pyplot 驅動 GUI。您也可以在 tkinter 程式中使用它,或使用它來產生靜態圖像,但在我們的範例中,讓它為我們處理圖形的 GUI 是有意義的。 (這就是稍後調用的flush_events()正在做的事情:允許與圖形視窗進行互動。)

此範例使用 numpy 方法 linspace() 來建立 x 值。它傳回一個 numpy 數組,這是一個奇特的 Python 列表。

使用 np.sin 而不是 math.sin 的原因是廣播。這是將函數應用於列表中每個項目的 numpy 術語。事實上,我突然想到,不用 numpy 使用 map 也可以實現相同的事情:

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

但是numpy廣播使用起來方便又簡單。

現在是 pyplot 設定。首先,建立一個新的「圖形」(圖)。在此圖中,新增一個子圖(ax)-可能有很多。 111 有相當深奧的解釋,「建立一個 1x1 網格,並將這個子圖放在第一個單元格中。」

在這個子圖(或一組軸)中,使用傳遞的 x 和 y 值繪製一條線。 (點以直線連接並連續繪製。)「r-」是指定紅色實線的簡寫方式。我們可以指定多行,因此plot()傳回一個元組;上面的程式碼使用元組解包來提取我們想要的一個值。

這是一個好的開始,但我需要隨著時間的推移延長 x 軸。如有必要,此程式碼也不會更新 y 軸的邊界 - 它被鎖定到為第一個圖計算的任何邊界。更多的搜尋讓我找到了這個答案。引用他們的話:

您將需要更新座標區的 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 分鐘更新一次(或無論輪詢函數運行多少次);變數在程式碼行中間不存在被覆蓋的危險。

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 賦值時,圖表才會更新。請注意,flush_events() 呼叫位於「if」語句之外,因此它被頻繁地呼叫。

以上是使用 pyplot 進行即時繪圖的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn