pythonmatplotlibtitlesubplotpyvisa

Title missing in the last subplot


I have created subplots that contain measurements taken from an oscilloscope. N is a parameter that determines the number of subplots. The issue is that when there's 1 plot, it has no title or y label. When there are more than one plot, only the last one is affected

##Plots a time trend of the active measurements on a MSO4/5/6
##Pierre Dupont - Tek - 2020

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import visa
import sys

rm = visa.ResourceManager()
scope = rm.open_resource('TCPIP::192.168.1.34::INSTR')

##determines number of active measurements
def active_measurements():
    meas_list=scope.query('MEASUrement:LIST?')
    N=meas_list.count(",")+1
    if "NONE" in meas_list:
        scope.close()
        sys.exit("No measurement found, exiting...")
    return(N)

N=active_measurements()
plots_set={} ##dictionary that will contain the subplots. One per active measurement.
ydata_set={} ##dictionary that will contain the array of logged data
fig=plt.figure()
IDN=scope.query('*idn?')
fig.suptitle('Measurement data logger / connected to: '+IDN,fontsize=10,color='purple')
plt.style.use('ggplot')

##definition of the subplots in the dictionary + subplots titles and axis legend
for i in range (1,N+1):
    plots_set["ax"+str(i)]=fig.add_subplot(N,1,i)
    meas_type=scope.query('MEASUrement:MEAS{}:TYPe?'.format(i))
    plots_set["ax"+str(i)].set_title(meas_type,fontsize='small')
    meas_unit=scope.query('MEASUrement:MEAS{}:YUNIT?'.format(i))
    plots_set["ax"+str(i)].set_ylabel(meas_unit.replace('"',''))
    print(i,meas_type,meas_unit)
    ydata_set["y"+str(i)]=[]


index=0
x=[]

## function that runs at every data log. Appends the arrays of measurement 
## data and updates the subplots
def animate(i):
    global index
    index+=1
    x.append(index)
    t=1
    for k,k2 in zip(ydata_set,plots_set):
        scope.query('*OPC?')
        M=float(scope.query('MEASUrement:MEAS{}:RESUlts:CURRentacq:MEAN?'.format(t)))
        t+=1
        plt.cla()
        ydata_set[k].append(M)
        plots_set[k2].plot(x,ydata_set[k],marker="X",linewidth=0.5,color='blue')


##frames parameter = number of logs // interval parameter = time between 2 logs (in ms)
ani=FuncAnimation(plt.gcf(), animate, frames=1000, interval=500, repeat=False)
plt.tight_layout()
plt.show()

scope.close()

OUTPUT:

1 RISETIME
 "s"

2 POVERSHOOT
 "%"

3 MAXIMUM
 "V"

example, 3rd plot misses y label and title

Many thanks for your inputs. Sorry for any lack of clarity that's my first post.


Solution

  • Calling plt.cla() clears the current, in this case most recently created, axes. This will clear all lines, labels, title, etc. If you want to use plt.cla() in your animate function you will need to reset those each time, e.g.

    def animate(i):
        # ...
        plt.cla()
        plt.set_title("title")
        plt.set_ylabel("label")
        # etc
    

    An alternative would be to use set_data to update your plots, i.e.

    lines = [subplot.plot(x, ydata, marker="X", linewidth=0.5, color='blue')[0] 
             for subplot, ydata in zip(plots_set, ydata)]
    def animate(i):
        global index
        index+=1
        x.append(index)
        t=1    
        for ydata, line in zip(ydata_set, lines):
            scope.query('*OPC?')
            M=float(scope.query('MEASUrement:MEAS{}:RESUlts:CURRentacq:MEAN?'.format(t)))
            t+=1
            ydata.append(M)
            line.set_data(x, ydata)
    

    This will not require the entire subplot to be cleared each time new data comes in.