【问题标题】:How to Auto scale y and x axis of a graph in real time python如何实时自动缩放图形的y和x轴python
【发布时间】:2020-10-27 21:39:08
【问题描述】:

我修改了本教程的代码来创建自己的实时绘图:

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

我需要实时绘制来自接近传感器的数据,数据通过 USB 电缆发送到计算机,然后我用串口读取它,所以代码已经按照我想要的方式工作了,但我也想要修改y轴和x轴,不要让它静止,因为有时峰值是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 轴总是相同的:

【问题讨论】:

    标签: python matplotlib animation graph real-time


    【解决方案1】:

    如果您想自动调整 y 轴,则只需在 animate() 函数中调整 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 必须在每一帧重新绘制整个绘图,但如果您想更改限制,则无法解决。

    【讨论】:

    • 是的,我只是按照你说的做了,现在画线太慢了,有时甚至无法画线,如果我让 blit=True 图形现在可以自动缩放,但是轴始终保持不变。
    【解决方案2】:

    所以我对这个链接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_())
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-23
      • 2014-12-25
      • 2012-10-12
      相关资源
      最近更新 更多