Read-Sensor-Resistances/serial_plotter.py

71 lines
2.9 KiB
Python

from datetime import datetime
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import os, json, traceback, ui, wx
matplotlib.use("WXAgg")
class SerialPlotter:
def __init__(self) -> None:
self.settings = json.load(open('settings.json', 'r'))
self.sensors = len(self.settings['sensor_ports'])
self.windowsize = self.settings['winSize']
self.delay = self.settings["delay"] / 1000
self.colors = ['blue', 'orange', 'green', 'yellow']
self.fig, self.axs = plt.subplots(1, 1, figsize=(7,5)) # TODO: make the figure size an UI option and pass into the settings.json
self.fig.canvas.mpl_connect('close_event', self._close_event)
self.timeStamps = {}
self.sensorsData = {}
for i in range(self.sensors):
self.timeStamps[i] = ['']#*self.windowsize
self.sensorsData[i] = [0]#*self.windowsize
plt.tight_layout()
def _close_event(self, event) -> None:
""" Actiions need to be executed when the graph has closed. Start a new .csv file to get read for new graph and bring back the UI, if hidden """
file = self.settings["file_name"]
wx.MessageBox(f"File has saved as {os.path.split(file)[1]} under {os.path.split(file)[0]} directory!\n")
def animation(self, t:int) -> None:
""" render a from of the animated graph """
# print("hi")
try:
plt.cla() # clear previous frame
file = open(self.settings["file_name"], "r")
ndata = np.array([np.asarray(line.split(", ")[1:], dtype=np.float32) for line in file])
if len(ndata) > 0:
row = ndata[-1]
i = 0
while i < self.sensors:
# shift all data left by 1 index, pop out the leftmost value
if self.windowsize > 0 and len(self.timeStamps[i]) > self.windowsize: # TODO: make sure the two lists have the same size
self.timeStamps[i].pop(0)
self.sensorsData[i].pop(0)
self.timeStamps[i].append(datetime.now().strftime('%H:%M:%S'))
self.sensorsData[i].append(row[i])
# plot a line
# TODO: round the number to 1-2- decimal places
self.axs.plot(self.timeStamps[i] ,self.sensorsData[i], color=self.colors[i], label=f'sensor {i + 1}, latest: {np.int32(self.sensorsData[i][-1])}')
i += 1
# Acknowledgement: https://stackoverflow.com/a/13589144
handles, labels = self.axs.get_legend_handles_labels()
by_label = dict(zip(labels, handles))
self.axs.legend(by_label.values(), by_label.keys(), loc='best')
except:
traceback.print_exc()
def plotting(self) -> None:
ani = FuncAnimation(self.fig, self.animation, blit=False)
return ani