71 lines
2.9 KiB
Python
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
|
||
|
|