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

我只是一个虾纸丫 提交于 2020-07-22 05:58:04

问题


I modified the code of this tutorial to create my own real time plot:

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

I needed to plot the data from a proximity sensor in real time, the data is sent through USB cable to the computer and I read it with the serial port, so the code is already working how I wanted to, but I also want to modify the y-axis and x-axis, not let it static, because sometimes the peaks are 3000 and sometimes 2000 and when the sensor is not being touched, the peaks are at around 200 because it also detects the ambient light. any clue how can I make it?

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

This is how the graph looks like, the x and y axis are always the same:


回答1:


If you want to autoscale the y-axis, then you can simply adjust the y-axis limits in your animate() function:

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,

HOWEVER, the result will not be what you expect if you use blit=True. This is because blitting is attempting to only draw the parts of the graphs that have changed, and the ticks on the axes are excluded from that. If you need to change the limits and therefore the ticks, you should use blit=False in your call to FuncAnimation. Note that you will encounter a performance hit since matplotlib will have to redraw the whole plot at every frame, but if you want to change the limits, there is no way around that.



来源:https://stackoverflow.com/questions/62778498/how-to-auto-scale-y-and-x-axis-of-a-graph-in-real-time-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!