import pandas as pd import matplotlib.pyplot as plt import numpy as np import time # 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=''): self.fig, self.ax1 = plt.subplots(2, figsize=(12, 10)) self.fig.suptitle("Measurement "+title, color="red") # First plot: Phase and magnitude self.path_collection_phase = self.ax1[0].scatter([], [], c='red', marker='<', label='Phase') self.magnitude_axis = self.ax1[0].twinx() self.path_collection_mag = self.magnitude_axis.scatter([], [], c='#3120E0', marker='4', label='Magnitude') self.equi_axis0 = self.ax1[0].twinx() self.equi_axis0.spines['right'].set_position(('outward', 40)) self.path_collection_equi0 = self.equi_axis0.scatter([], [], c='black', marker=".", label='Equilibrium_Indicator') self.ax1[0].set_xlabel("TIMESTAMP") self.ax1[0].set_ylabel("PHASE", color='red') self.magnitude_axis.set_ylabel("MAGNITUDE", color='#3120E0') self.equi_axis0.set_ylabel("EQUILIBRIUM_INDICATOR", 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 self.path_collection_temp = self.ax1[1].scatter([], [], c='blue', marker='p', label="Temperature") self.humidity_axis = self.ax1[1].twinx() self.path_collection_hum = self.humidity_axis.scatter([], [], c='green', marker="*", label="Humidity") self.equi_axis1 = self.ax1[1].twinx() self.equi_axis1.spines['right'].set_position(('outward', 40)) self.path_collection_equi1 = self.equi_axis1.scatter([], [], c='black', marker=".", label="Equilibrium_Indicator") self.ax1[1].set_xlabel("TIMESTAMP") self.ax1[1].set_ylabel("TEMPERATURE ", color='blue') self.humidity_axis.set_ylabel("HUMIDITY", color='green') self.equi_axis1.set_ylabel("EQUILIBRIUM_INDICATOR", 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') 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) 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]) 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]) 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]) 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]) 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() if distance == 0.: distance = 0.5 return array.min()-0.05*distance, array.max()+0.05*distance if __name__ == '__main__': m = MeasurementPlot() plt.ion() measurements = [] 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 } measurements.append(measurement) data_frame = pd.DataFrame(measurements) m.draw(data_frame) print(str(i)) time.sleep(0.3) print('I am done. ') plt.ioff() m.draw(data_frame, 'the.pdf')