Skip to content
Snippets Groups Projects
MeasurementPlot.py 13.9 KiB
Newer Older
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import time
import sys
# Different exceptions can be thrown while plotting, depending on the backend.
# We catch them all locally and raise our own exception instead
class PlottingError(Exception):
    "Raised when plotting fails"
    pass

class MeasurementPlot:
    def __init__(self, title='', legend_sensor0 = ['Temperature Sensor0', 'Humidity Sensor0'], \
                 legend_sensor1 =['Temperature Sensor1','Humidity Sensor1', 'Air Pressure Sensor1']):
          # set python for opening an separate plot window when starting from anaconda, Michael
        if 'ipykernel' in sys.modules:
            from IPython import get_ipython
            get_ipython().run_line_magic('matplotlib', 'qt')
        
        # set contents of labels for additional external sensors in legend of subplots, Michael
        label_temp_sensor0 = legend_sensor0[0]
        label_hum_sensor0 = legend_sensor0[1]
        
        label_temp_sensor1 = legend_sensor1[0]
        label_hum_sensor1 = legend_sensor1[1]
        label_air_press_sensor1 = legend_sensor1[2]
        
        # Third, Fourth and Fifth plot for additional external sensors, Michael
        self.fig, self.ax1 = plt.subplots(5, figsize=(25, 20))
        self.fig.subplots_adjust(bottom= 0.1, hspace = 0.4)
        self.fig.suptitle("Measurement "+title, color="red")

        # First plot: Phase and magnitude, Michael
        self.path_collection_phase = self.ax1[0].scatter([], [], c='red', marker='<', label='DUT Phase')
        self.magnitude_axis = self.ax1[0].twinx()
        
        # in entry of legend for phase and magnitude the word DUT is added in front, Michael
        self.path_collection_mag = self.magnitude_axis.scatter([], [], c='#3120E0', marker='4', label='DUT Magnitude')
        self.equi_axis0 = self.ax1[0].twinx()
        self.equi_axis0.spines['right'].set_position(('outward', 75))
        self.path_collection_equi0 = self.equi_axis0.scatter([], [], c='black', marker=".", label='Equilibrium_Indicator')

        # units added to y-axes of subplot 1, Michael
        self.ax1[0].set_xlabel("TIMESTAMP")
        self.ax1[0].set_ylabel("PHASE [°]", color='red')
        self.magnitude_axis.set_ylabel("MAGNITUDE [dB]", color='#3120E0')
        # label of y-axis for equilibrium indicator is changed to Indiccator Value because it's shorter, Michael
        self.equi_axis0.set_ylabel("INDICATOR VALUE", color='black')
        # fix range to 0..31 with some extra margin for plotting
        self.equi_axis0.set_ylim(-1, 32)

        self.ax1[0].grid(True, linestyle=":")
        all_path_collections = [self.path_collection_phase, self.path_collection_mag, self.path_collection_equi0]
        labels = [pc.get_label() for pc in all_path_collections]
        self.ax1[0].legend(all_path_collections, labels, loc='lower right')

        # Second plot: Humidity and temperature of climate chamber requested from internal sensors of chamber
        self.path_collection_temp = self.ax1[1].scatter([], [], c='blue', marker='p', label="Chamber Temperature")
        self.humidity_axis = self.ax1[1].twinx()
        self.path_collection_hum = self.humidity_axis.scatter([], [], c='green', marker="*", label="Chamber Humidity")
        self.equi_axis1 = self.ax1[1].twinx()
        self.equi_axis1.spines['right'].set_position(('outward', 75))
        self.path_collection_equi1 = self.equi_axis1.scatter([], [], c='black', marker=".", label="Equilibrium_Indicator")

        # units added to y-axes of subplot 2, Michael
        self.ax1[1].set_xlabel("TIMESTAMP")
        self.ax1[1].set_ylabel("TEMPERATURE [°C] ", color='blue')
        self.humidity_axis.set_ylabel("HUMIDITY [%RH]", color='green')
        # label of y-axis for equilibrium indicator is changed to Indiccator Value because it's shorter, Michael        
        self.equi_axis1.set_ylabel("INDICATOR VALUE", color='black')
        self.equi_axis1.set_ylim(-1, 32)

        self.ax1[1].grid(True, linestyle=":")
        all_path_collections = [self.path_collection_temp, self.path_collection_hum, self.path_collection_equi1]
        labels = [pc.get_label() for pc in all_path_collections]
        self.ax1[1].legend(all_path_collections, labels, loc='lower right')
        
        
        # Third plot:  temperature external sensor0,  humidity external sensors0, Michael
        # sensor 0 is the sensor at port 0 of ahlborn and used for the DUT temperature, DUT humidity, Michael
        # label for temeprature and humidity of sensor 0 can be configure by ext_sens_data.json, Michael
        
        self.path_collection_temp_sensor0 = self.ax1[2].scatter([],[], c='red', marker='p', label=label_temp_sensor0)
        
        self.ext_sens_hum_axis = self.ax1[2].twinx()
        self.path_collection_hum_sensor0 = self.ext_sens_hum_axis.scatter([],[], c='purple', marker='*', label=label_hum_sensor0)
        
        
        self.ax1[2].set_xlabel("TIMESTAMP")
        self.ax1[2].set_ylabel("TEMPERATURE [°C]", color='red')
        self.ext_sens_hum_axis.set_ylabel("HUMIDITY [%RH]", color = 'purple')

        self.ax1[2].grid(True, linestyle=":")
        all_path_collections = [self.path_collection_temp_sensor0, self.path_collection_hum_sensor0]
        labels = [pc.get_label() for pc in all_path_collections]
        self.ax1[2].legend(all_path_collections, labels, loc='lower right')
        
        # Forth plot: temperatur external sensor1,  humidity external sensors1, air pressure external sensor 1, Michael
        # sensor 1 is the sensor at port 1 of ahlborn and used for the room temperature, the room humidity 
        # and the air pressure in the room, Michael
        # label for temeprature and humidity of sensor 0 can be configure by ext_sens_data.json, Michael
        
        self.path_collection_temp_sensor1 = self.ax1[3].scatter([],[], c='green', marker='*', label=label_temp_sensor1)    
        
        self.sec_ext_hum_sens_axis = self.ax1[3].twinx()
        self.path_collection_hum_sensor1 = self.sec_ext_hum_sens_axis.scatter([],[], c='orange', marker='>', label=label_hum_sensor1)
        
        self.press_axis = self.ax1[3].twinx()
        self.press_axis.spines['right'].set_position(('outward', 75))
        self.path_collection_press = self.press_axis.scatter([],[], c='grey', marker='4', label=label_air_press_sensor1)
        
        self.ax1[3].set_xlabel("TIMESTAMP")
        self.ax1[3].set_ylabel("TEMPERATURE [°C]", color='green')
        self.sec_ext_hum_sens_axis.set_ylabel("HUMIDITY [%RH]", color = 'orange')
        self.press_axis.set_ylabel("AIR PRESSURE [mb]", color ='grey')
        
        self.ax1[3].grid(True, linestyle=":")        
        all_path_collections = [self.path_collection_temp_sensor1, self.path_collection_hum_sensor1, \
                                self.path_collection_press]
        labels = [pc.get_label() for pc in all_path_collections]
        self.ax1[3].legend(all_path_collections, labels, loc='lower right')
                
        # Fifth plot: heater activity of temeprature heater and humidity heater
        # values for activity are requested from climate chamber, Michael
        
        self.path_collection_temp_heater = self.ax1[4].scatter([],[], c='black', marker='<', label='Temp Heater')
        self.path_collection_hum_heater = self.ax1[4].scatter([],[], c='brown', marker='o', label='Hum Heater')
        
        self.ax1[4].set_xlabel("TIMESTAMP")
        self.ax1[4].set_ylabel("HEATER PERCENTAGE [%]", color='black')
        
        self.ax1[4].grid(True, linestyle=":")
        all_path_collections = [self.path_collection_temp_heater, \
                                self.path_collection_hum_heater]
        labels = [pc.get_label() for pc in all_path_collections]
        self.ax1[4].legend(all_path_collections, labels, loc='lower right')
        
        
      
    def draw(self, data_frame, pdf_name=''):
        timestamps = data_frame.TIMESTAMP
        minimum, maximum = self.get_extended_min_max(timestamps)
        self.ax1[0].set_xlim(minimum, maximum)
        self.ax1[1].set_xlim(minimum, maximum)
        # because subplots where increase x-axis limits has to be set equal to first and second plot, Michael 
        self.ax1[2].set_xlim(minimum, maximum)
        self.ax1[3].set_xlim(minimum, maximum)
        self.ax1[4].set_xlim(minimum, maximum)
        # refresh data for phase in subplot for phase and magnitude 
        phases = data_frame.S21_PHASE
        minimum, maximum = self.get_extended_min_max(phases)
        self.ax1[0].set_ylim(minimum, maximum)
        self.path_collection_phase.set_offsets(np.c_[timestamps, phases])

        # refresh data for magnitude in subplot for phase and magnitude
        magnitudes = data_frame.S21_MAGNITUDE
        minimum, maximum = self.get_extended_min_max(magnitudes)
        self.magnitude_axis.set_ylim(minimum, maximum)
        self.path_collection_mag.set_offsets(np.c_[timestamps, magnitudes])

        # refresh data for chamber temperature in subplot for chamber temperature and humidity  
        temperatures = data_frame.READBACK_TEMPERATURE
        minimum, maximum = self.get_extended_min_max(temperatures)
        self.ax1[1].set_ylim(minimum, maximum)
        self.path_collection_temp.set_offsets(np.c_[timestamps, temperatures])

        # refresh data for chamber humidity in subplot for chamber temperature and humidity
        humidities = data_frame.READBACK_HUMIDITY
        minimum, maximum = self.get_extended_min_max(humidities)
        self.humidity_axis.set_ylim(minimum, maximum)
        self.path_collection_hum.set_offsets(np.c_[timestamps, humidities])
        
        # refresh temperatures for external sensors in subplots for sensor 0 and sensor1, Michael
        temp_sensor0 = data_frame.TEMP_SENSOR0
        temp_sensor1 = data_frame.TEMP_SENSOR1
        
        minimum, maximum = self.get_extended_min_max(temp_sensor0)
        self.ax1[2].set_ylim(minimum, maximum)
        
        minimum, maximum = self.get_extended_min_max(temp_sensor1)
        self.ax1[3].set_ylim(minimum, maximum)
        
        self.path_collection_temp_sensor0.set_offsets(np.c_[timestamps, temp_sensor0])
        self.path_collection_temp_sensor1.set_offsets(np.c_[timestamps, temp_sensor1])
        
        # refresh humidities external sensors in subplots for sensor 0 and sensor 1, Michael
        hum_sensor0 = data_frame.HUM_SENSOR0
        hum_sensor1 = data_frame.HUM_SENSOR1
        
        
        minimum, maximum = self.get_extended_min_max(hum_sensor0)
        self.ext_sens_hum_axis.set_ylim(minimum, maximum)
        
        minimum, maximum = self.get_extended_min_max(hum_sensor1)
        self.sec_ext_hum_sens_axis.set_ylim(minimum, maximum)
        self.path_collection_hum_sensor0.set_offsets(np.c_[timestamps, hum_sensor0])
        self.path_collection_hum_sensor1.set_offsets(np.c_[timestamps, hum_sensor1])
        
        
        # refresh air pressure of external sensor in subplot for sensor 1 Michael
        air_press = data_frame.AIR_PRESSURE
        minimum, maximum = self.get_extended_min_max(air_press)
        self.press_axis.set_ylim(minimum, maximum)
        self.path_collection_press.set_offsets(np.c_[timestamps, air_press])
        
        # refresh heater percentage values of climate chamber in subplot of heater values, Michael
        temp_heater = data_frame.TEMP_HEATER
        hum_heater = data_frame.HUM_HEATER
        min_temp_heater, max_temp_heater = self.get_extended_min_max(temp_heater)
        min_hum_heater, max_hum_heater = self.get_extended_min_max(hum_heater)
        minimum = min(min_temp_heater, min_hum_heater)
        maximum = max(max_temp_heater, max_hum_heater)
        self.ax1[4].set_ylim(minimum-0.05*(maximum-minimum), maximum+0.05*(maximum-minimum))
        self.path_collection_temp_heater.set_offsets(np.c_[timestamps, temp_heater])
        self.path_collection_hum_heater.set_offsets(np.c_[timestamps, hum_heater])
        
        self.path_collection_equi0.set_offsets(np.c_[timestamps, data_frame.EQUILIBRIUM_INDICATOR])
        self.path_collection_equi1.set_offsets(np.c_[timestamps, data_frame.EQUILIBRIUM_INDICATOR])

        if not pdf_name == '':
            self.fig.savefig(pdf_name)

        plt.show()
        if plt.isinteractive():
            try:
                self.fig.canvas.draw()
                self.fig.canvas.flush_events()
            except Exception as e:
                raise PlottingError from e

    # add 5 % of the distance between min and max to the range
    @staticmethod
    def get_extended_min_max(array):
        distance = array.max() - array.min()
            distance = 1
        return array.min()-0.05*distance, array.max()+0.05*distance

# test procedure for measurement plot procedure
if __name__ == '__main__':
    m = MeasurementPlot()
    plt.ion()
    measurements = []

# generation of datapoints for plot
    for i in range(20):
        measurement = {
            'TIMESTAMP': i,
            'READBACK_TEMPERATURE': 25 - i,
            'READBACK_HUMIDITY': 10 + 0.1*i,
            'EQUILIBRIUM_INDICATOR': i % 4,
            'S21_PHASE': 20 - 2*i,
            'S21_MAGNITUDE': 0.3*i,
            'TEMP_HEATER': 10,
            # percentage humidity heater, Michael
            'HUM_HEATER': 3,
            # Temperature Sensor0of external temp sensor added, Michael
            'TEMP_SENSOR0': i,
            # Temperature Sensor 1 of external temp sensor added, Michael
            'TEMP_SENSOR1': 25-i,
            # Humidity Sensor0 of external hum sensor added, Michael
            'HUM_SENSOR0': 40,
            # Humidity Sensor 1 of external hum sensor added, Michael
            'HUM_SENSOR1': 45,
            # Air pressure of external sensor added, Michael
            'AIR_PRESSURE': 1200-10*i
        }
        measurements.append(measurement)
        data_frame = pd.DataFrame(measurements)
        # plot of data frame with test data for actual step
        # plot of step number
        print(str(i))
        time.sleep(0.3)

    print('I am done. ')
    plt.ioff()
    m.draw(data_frame, 'the.pdf')