簡體   English   中英

如何實時自動縮放圖形的 y 軸和 x 軸 python

[英]How to Auto scale y and x axis of a graph in real time python

我修改了本教程的代碼以創建自己的實時 plot:

https://learn.sparkfun.com/tutorials/graph-sensor-data-with-python-and-matplotlib/speeding-up-the-plot-animation

我需要 plot 實時來自接近傳感器的數據,數據通過 USB 電纜發送到計算機,我用串口讀取它,所以代碼已經按照我想要的方式工作,但我也想修改y軸和x軸,不要讓它static,因為有時峰值是3000,有時是2000,當傳感器沒有被觸摸時,峰值在200左右,因為它也檢測環境光。 任何線索我該怎么做?

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import serial


# Data from serial port
port = 'COM8'
baudrate = 9600
tout = 0.01  # Miliseconds

# Time to update the data of the sensor signal real time Rs=9600baud T=1/Rs
tiempo = (1 / baudrate) * 1000

# Parameters
x_len = 200         # Number of points to display
y_range = [20000, 40000]  # Range of Y values to display

# Create figure for plotting
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
xs = list(range(0, x_len))
ys = [0] * x_len
ax.set_ylim(y_range)

# Create a blank line. We will update the line in animate
line, = ax.plot(xs, ys)

# Markers
startMarker = 60  # Start marker "<"
endMarker = 62  # End marker ">"

# Begin Arduino communication, Port COM8, speed 9600
serialPort = serial.Serial(port, baudrate, timeout=tout)

# Begin to save the arduino data
def arduinodata():

    global startMarker, endMarker

    ck = ""
    x = "z"  # any value that is not an end- or startMarker
    bytecount = -1  # to allow for the fact that the last increment will be one too many

    # wait for the start character
    while ord(x) != startMarker:
        x = serialPort.read()

    # save data until the end marker is found
    while ord(x) != endMarker:
        if ord(x) != startMarker:
            ck = ck + x.decode()
            bytecount += 1
        x = serialPort.read()

    return ck


def readarduino():

    # Wait until the Arduino sends '<Arduino Ready>' - allows time for Arduino reset
    # It also ensures that any bytes left over from a previous message are discarded

    msg = ""

    while msg.find("<Arduino is ready>") == -1:

        while serialPort.inWaiting() == 0:
            pass
        # delete for example the "\r\n" that may contain the message
        msg = arduinodata()
        msg = msg.split("\r\n")
        msg = ''.join(msg)

        # If the sensor send very big numbers over 90000 they will be deleted
        if msg and len(msg) <= 5:
            msg = int(msg)
            return msg

        elif msg and len(msg) >= 4:
            msg = int(msg)
            return msg


# This function is called periodically from FuncAnimation
def animate(i, ys):

    # Read pulse from PALS2
    pulse = readarduino()

    # Add y to list
    ys.append(pulse)

    # Limit x and y lists to set number of items
    ys = ys[-x_len:]

    # Update line with new Y values
    line.set_ydata(ys)
    return line,


# Plot labels
plt.title('Heart frequency vs Time')
plt.ylabel('frequency ')
plt.xlabel('Samples')

# Set up plot to call animate() function periodically
ani = animation.FuncAnimation(fig, animate, fargs=(ys,), interval=tiempo, blit=True)
plt.show()
plt.close()
serialPort.close()

這就是圖表的樣子,x 和 y 軸總是相同的:

在此處輸入圖像描述

如果要自動縮放 y 軸,則只需在animate() function 中調整 y 軸范圍:

def animate(i, ys):

    # Read pulse from PALS2
    pulse = readarduino()

    # Add y to list
    ys.append(pulse)

    # Limit x and y lists to set number of items
    ys = ys[-x_len:]
    ymin = np.min(ys)
    ymax = np.max(ys)
    ax.set_ylim(ymin, ymax)

    # Update line with new Y values
    line.set_ydata(ys)
    return line,

但是,如果您使用blit=True ,結果將不會是您所期望的。 這是因為 blitting 試圖僅繪制圖形中已更改的部分,而軸上的刻度被排除在外。 如果您需要更改限制並因此更改刻度,您應該在調用FuncAnimation時使用blit=False 請注意,由於 matplotlib 將不得不在每一幀重新繪制整個 plot ,因此您將遇到性能損失,但如果您想更改限制,則沒有辦法解決。

所以我對這個鏈接https://www.learnpyqt.com/courses/graphics-plotting/plotting-pyqtgraph/的最后一個代碼進行了一些更改,我可以解決這個問題。 x 和 Y 軸現在自動縮放

import PyQt5
from PyQt5 import QtWidgets, QtCore
from pyqtgraph import PlotWidget, plot
import pyqtgraph as pg
import sys  # We need sys so that we can pass argv to QApplication
import os
from random import randint
import serial

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.graphWidget = pg.PlotWidget()
        self.setCentralWidget(self.graphWidget)

        # Data from serial port
        self.port = 'COM8'
        self.baudrate = 9600
        self.tout = 0.01  # Miliseconds

        # Time to update the data of the sensor signal Rs=9600baud T=1/Rs
        self.tiempo = (1 / self.baudrate) * 1000

        self.x_len = 200
        self.x = list(range(0, self.x_len))  # 100 time points
        self.y = [0] * self.x_len # 100 data points

        self.graphWidget.setBackground('w')

        # Markers
        self.startMarker = 60  # Start marker "<"
        self.endMarker = 62  # End marker ">"

        # Begin Arduino communication, Port COM8, speed 9600
        self.serialPort = serial.Serial(self.port, self.baudrate, timeout=self.tout)

        pen = pg.mkPen(color=(255, 0, 0))
        self.data_line = self.graphWidget.plot(self.x, self.y, pen=pen)

        self.timer = QtCore.QTimer()
        self.timer.setInterval(self.tiempo)
        self.timer.timeout.connect(self.update_plot_data)
        self.timer.start()

    # Begin to save the arduino data
    def arduinodata(self):

        ck = ""
        x = "z"  # any value that is not an end- or startMarker
        bytecount = -1  # to allow for the fact that the last increment will be one too many

        # wait for the start character
        while ord(x) != self.startMarker:
            x = self.serialPort.read()

        # save data until the end marker is found
        while ord(x) != self.endMarker:
            if ord(x) != self.startMarker:
                ck = ck + x.decode()
                bytecount += 1
            x = self.serialPort.read()

        return ck

    def readarduino(self):

        # Wait until the Arduino sends '<Arduino Ready>' - allows time for Arduino reset
        # It also ensures that any bytes left over from a previous message are discarded

        msg = ""

        while msg.find("<Arduino is ready>") == -1:

            while self.serialPort.inWaiting() == 0:
                pass
            # delete for example the "\r\n" that may contain the message
            msg = self.arduinodata()
            msg = msg.split("\r\n")
            msg = ''.join(msg)

            # If the sensor send very big numbers over 90000 they will be deleted
            if msg and len(msg) <= 5:
                msg = int(msg)
                return msg

            elif msg and len(msg) >= 4:
                msg = int(msg)
                return msg


    def update_plot_data(self):
        pulse = self.readarduino()
        self.x = self.x[1:]  # Remove the first y element.
        self.x.append(self.x[-1] + 1)  # Add a new value 1 higher than the last.

        self.y = self.y[1:]  # Remove the first
        self.y.append(pulse)  # Add a new random value.

        self.data_line.setData(self.x, self.y)  # Update the data.


app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM