Read-Sensor-Resistances/serial_plotter.py

71 lines
3.1 KiB
Python
Raw Permalink Normal View History

2022-08-08 22:51:36 +00:00
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
2022-08-12 07:33:27 +00:00
matplotlib.use("WXAgg") # for JetBrains IDE to force use the wx backend
2022-08-08 22:51:36 +00:00
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:
2022-08-12 07:33:27 +00:00
""" render a frame of the animated graph """
2022-08-08 22:51:36 +00:00
try:
plt.cla() # clear previous frame
2022-08-12 07:33:27 +00:00
# read the last line from the .csv file, the data start from the second colunm so omit index # 0
2022-08-08 22:51:36 +00:00
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()
2022-08-12 07:33:27 +00:00
def plotting(self) -> FuncAnimation:
2022-08-08 22:51:36 +00:00
ani = FuncAnimation(self.fig, self.animation, blit=False)
return ani