0

I am reading data from 4 different sensors using serial communication and want to plot each sensor data in a separate plot. My code is:

import serial
import matplotlib.pyplot as plt
import numpy as np

connected = False

comPort = 'COM4'        

ser = serial.Serial(comPort, 115200)    # Sets up serial connection (make sure baud rate is correct - matches Arduino)

while not connected:
    serin = ser.read()
    connected = True

plt.ion()                               # Sets plot to animation mode

fig1 = plt.figure()
fig2 = plt.figure()
fig3 = plt.figure()
fig4 = plt.figure()

length = 20                             # Determines length of data taking session (in data points); length/10 = seconds

w = [0]*length                          # Create empty variable of length of test
x = [0]*length               
y = [0]*length
z = [0]*length

wline, = plt.plot(w)                    # Sets up future lines to be modified
xline, = plt.plot(x)                    
yline, = plt.plot(y)
zline, = plt.plot(z)

plt.ylim(0,64535)                       # Sets the y axis limits - 16 bits resolution

for i in range(length):                 # While you are taking data
    data = ser.readline()               # Reads until it gets a carriage return (/n).
    sep = data.split()                  # Splits string into a list at the tabs

    w.append(int(sep[0]))               # Add new values as int to current list
    x.append(int(sep[1]))   
    y.append(int(sep[2]))
    z.append(int(sep[3]))

    del w[0]
    del x[0]
    del y[0]
    del z[0]

    wline.set_xdata(np.arange(len(w)))  # Sets wdata to new list length  
    xline.set_xdata(np.arange(len(x)))  
    yline.set_xdata(np.arange(len(y)))  
    zline.set_xdata(np.arange(len(z)))  

    wline.set_ydata(w)                  # Sets ydata to new lists 
    xline.set_ydata(x)                 
    yline.set_ydata(y)
    zline.set_ydata(z)

    print i
    print sep

    ax1 = fig1.add_subplot(111)
    ax1.plot(wline.set_ydata(w))
#    ax1.plot(sep[0])
    plt.pause(0.001)                   
    plt.grid(True)
    plt.draw()                         # Draws new plot

    ax2 = fig2.add_subplot(111)
    ax2.plot(xline.set_ydata(x))
    plt.pause(0.001)                   
    plt.grid(True)
    plt.draw()                         # Draws new plot

    ax3 = fig3.add_subplot(111)
    ax3.plot(yline.set_ydata(y))
    plt.pause(0.001)                   
    plt.grid(True)
    plt.draw()                         # Draws new plot

    ax4 = fig4.add_subplot(111)
    ax4.plot(zline.set_ydata(z)) 
    plt.pause(0.001)                   
    plt.grid(True)
    plt.draw()                         # Draws new plot

plt.show()

ser.close()                             # Closes serial connection

The data is acquired correctly and the the 4 figures are generated, however only the last one is plotting the data. Furthermore it is plotting all 4 sensors and the Y axes of the other subplots is also wrong (please see output screenshot). I am also printing the array that contains the data ("print sep") just to check if the data is there.

Screenshot of the program output

Am I missing something obvious? Thank you very much for your help

1 Answer 1

1

When you create your 4 lines, they will all be created on the active figure (i.e. in this case, the last one you created).

You could move the creation of the 4 subplot axes to before your loop, and then create the matplotlib line instances on their correct axes (using the object-oriented ax.plot instead of plt.plot). Then, they will show up on the correct figures.

fig1 = plt.figure()
fig2 = plt.figure()
fig3 = plt.figure()
fig4 = plt.figure()

ax1 = fig1.add_subplot(111)
ax2 = fig2.add_subplot(111)
ax3 = fig3.add_subplot(111)
ax4 = fig4.add_subplot(111)

length = 20                             # Determines length of data taking session (in data points); length/10 = seconds

w = [0]*length                          # Create empty variable of length of test
x = [0]*length               
y = [0]*length
z = [0]*length

wline, = ax1.plot(w)                    # Sets up future lines to be modified
xline, = ax2.plot(x)                    
yline, = ax3.plot(y)
zline, = ax4.plot(z)

and then you can remove the following lines of code inside the for loop:

ax1 = fig1.add_subplot(111)
ax1.plot(wline.set_ydata(w))
...
ax2 = fig2.add_subplot(111)
ax2.plot(xline.set_ydata(x))
...
ax3 = fig3.add_subplot(111)
ax3.plot(yline.set_ydata(y))
...
ax4 = fig4.add_subplot(111)
ax4.plot(zline.set_ydata(z)) 

You will also need to change each plt.draw() to

fig1.canvas.draw()
fig2.canvas.draw()
fig3.canvas.draw()
fig4.canvas.draw()

and the plt.grid(True) should change to:

ax1.grid(True)
ax2.grid(True)
ax3.grid(True)
ax4.grid(True)
Sign up to request clarification or add additional context in comments.

3 Comments

thank you very much, that effectively solved the problem. I also fixed the scale (ylim) by applying the same reasoning (for example using ax1.set_ylim() instead of plt). Another issue came up though: Only the active figure is updating "its" plot in real time, i.e., by clicking/selecting one particular figure, that plot is being updated with the coming data but the 3 other figures are frozen unless I click/select them. Any idea? Thanks again.
Ah, that's because plt.draw only acts on the current figure. You should switch those to fig1.canvas.draw(), etc. See my edit above.
I was editing my previous comment. Thanks @Tom, it works. All plots updating correctly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.