partially successfully break the graph into parts
This commit is contained in:
parent
f94456bcf3
commit
f1b9c21865
|
@ -26,9 +26,40 @@ class SerialPlotter:
|
|||
self.colors = ['blue', 'orange', 'green', 'yellow']
|
||||
|
||||
# TODO: make the figure size an UI option and pass into the settings.json
|
||||
self.fig, self.axs = plt.subplots(1, 1, figsize=(9, 6))
|
||||
#self.fig, self.axs = plt.subplots(figsize=(9, 6))
|
||||
# self.fig_1 = plt.figure(1)
|
||||
# self.axs_1 = plt.axes()
|
||||
|
||||
self.fig.canvas.mpl_connect('close_event', self.event_close)
|
||||
# self.fig_2 = plt.figure(2)
|
||||
# self.axs_2 = plt.axes()
|
||||
if (self.sensors == 1) :
|
||||
self.fig_1, self.axs_1 = plt.subplots()
|
||||
|
||||
self.fig_1.canvas.mpl_connect('close_event', self.event_close)
|
||||
elif (self.sensors == 2) :
|
||||
self.fig_1, self.axs_1 = plt.subplots()
|
||||
self.fig_2, self.axs_2 = plt.subplots()
|
||||
|
||||
self.fig_1.canvas.mpl_connect('close_event', self.event_close)
|
||||
self.fig_2.canvas.mpl_connect('close_event', self.event_close)
|
||||
elif (self.sensors == 3) :
|
||||
self.fig_1, self.axs_1 = plt.subplots()
|
||||
self.fig_2, self.axs_2 = plt.subplots()
|
||||
self.fig_3, self.axs_3 = plt.subplots()
|
||||
|
||||
self.fig_1.canvas.mpl_connect('close_event', self.event_close)
|
||||
self.fig_2.canvas.mpl_connect('close_event', self.event_close)
|
||||
self.fig_3.canvas.mpl_connect('close_event', self.event_close)
|
||||
elif (self.sensors == 4) :
|
||||
self.fig_1, self.axs_1 = plt.subplots()
|
||||
self.fig_2, self.axs_2 = plt.subplots()
|
||||
self.fig_3, self.axs_3 = plt.subplots()
|
||||
self.fig_4, self.axs_4 = plt.subplots()
|
||||
|
||||
self.fig_1.canvas.mpl_connect('close_event', self.event_close)
|
||||
self.fig_2.canvas.mpl_connect('close_event', self.event_close)
|
||||
self.fig_3.canvas.mpl_connect('close_event', self.event_close)
|
||||
self.fig_4.canvas.mpl_connect('close_event', self.event_close)
|
||||
|
||||
self.timeStamps = {}
|
||||
self.sensorsData = {}
|
||||
|
@ -40,7 +71,7 @@ class SerialPlotter:
|
|||
|
||||
def event_close(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
|
||||
Actions 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 exist
|
||||
"""
|
||||
file = self.settings["file_name"]
|
||||
|
@ -48,7 +79,7 @@ class SerialPlotter:
|
|||
if self.parent:
|
||||
self.parent.Show()
|
||||
|
||||
def animation(self, t: int) -> None:
|
||||
def animation_1(self, t) -> None:
|
||||
"""
|
||||
render a frame of the animated graph.
|
||||
"""
|
||||
|
@ -61,44 +92,222 @@ class SerialPlotter:
|
|||
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 windowsize is not 0 (infinite)
|
||||
# TODO: make sure the two lists have the same size
|
||||
# if self.windowsize > 0 and len(self.timeStamps[i]) > self.windowsize
|
||||
if 0 < self.windowsize < len(self.timeStamps[i]):
|
||||
self.timeStamps[i].pop(0)
|
||||
self.sensorsData[i].pop(0)
|
||||
if 0 < self.windowsize < len(self.timeStamps[i]):
|
||||
self.timeStamps[i].pop(0)
|
||||
self.sensorsData[i].pop(0)
|
||||
|
||||
# self.timeStamps[i].append(datetime.now().strftime('%H:%M:%S')) # version 1
|
||||
|
||||
# version 2, if we decide to go with this one change the list type to list[int] from list[str]
|
||||
self.timeStamps[i].append(str(self.timeElapsed))
|
||||
self.timeStamps[i].append(str(self.timeElapsed))
|
||||
|
||||
self.sensorsData[i].append(row[i])
|
||||
self.sensorsData[i].append(row[i])
|
||||
# plot a line
|
||||
# round the number to scientific notation
|
||||
self.axs.plot(self.timeStamps[i], self.sensorsData[i], color=self.colors[i],
|
||||
self.axs_1.plot(self.timeStamps[i], self.sensorsData[i], color=self.colors[i],
|
||||
label=f'sensor {i + 1}, latest: {np.format_float_scientific(self.sensorsData[i][-1], precision = 2)} $\Omega$')
|
||||
|
||||
# TODO: make the font size an UI option from the settings.json
|
||||
# Make the font size of values placed on x-axis and y-aixs equal to 16 (large enough)
|
||||
plt.xticks(fontsize = max(self.fontSize, 10))
|
||||
plt.yticks(fontsize = max(self.fontSize, 10))
|
||||
#plt.xticks(fontsize = max(self.fontSize, 10))
|
||||
#plt.yticks(fontsize = max(self.fontSize, 10))
|
||||
self.axs_1.tick_params(axis='both', which='both', labelsize=max(self.fontSize, 10))
|
||||
|
||||
# make the label of two axes large enough
|
||||
self.axs.set_xlabel('Time (seconds)', fontsize = max(self.fontSize, 10))
|
||||
self.axs.set_ylabel(u'Resistance ($\Omega$)', fontsize = max(self.fontSize, 10))
|
||||
i += 1
|
||||
self.axs_1.set_xlabel('Time (seconds)', fontsize = max(self.fontSize, 10))
|
||||
self.axs_1.set_ylabel(u'Resistance ($\Omega$)', fontsize = max(self.fontSize, 10))
|
||||
#i += 1
|
||||
self.timeElapsed += 1 # increment time
|
||||
|
||||
# Acknowledgement: https://stackoverflow.com/a/13589144 (can you imagine how long it took me to find this before ChatGPT?)
|
||||
handles, labels = self.axs.get_legend_handles_labels()
|
||||
#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', fontsize = max(self.fontSize, 10)) # Make the legend on graph large enough
|
||||
|
||||
# handles, labels = self.axs_1.get_legend_handles_labels()
|
||||
# by_label = dict(zip(labels, handles))
|
||||
# self.axs_1.legend(by_label.values(), by_label.keys(), loc='best', fontsize = max(self.fontSize, 10))
|
||||
|
||||
handles, labels = plt.gca().get_legend_handles_labels()
|
||||
by_label = dict(zip(labels, handles))
|
||||
self.axs.legend(by_label.values(), by_label.keys(), loc='best', fontsize = max(self.fontSize, 10)) # Make the legend on graph large enough
|
||||
plt.legend(by_label.values(), by_label.keys(), loc='best', fontsize = max(self.fontSize, 10))
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
def plotting(self) -> FuncAnimation:
|
||||
def animation_2(self, t: int) -> None:
|
||||
"""
|
||||
render a frame of the animated graph.
|
||||
"""
|
||||
# Some of them copied from the old code, so even Eric may not 100% know what they do. ChatGPT may give a better explaination
|
||||
try:
|
||||
plt.cla() # clear previous frame
|
||||
# read the last line from the .csv file, the data start from the second column so omit index #0
|
||||
file = open(self.settings["file_name"], "r")
|
||||
ndata = np.array([np.asarray(line.split(", ")[1:], dtype=np.float32) for line in islice(file, 1, None)])#read from the second row of the file ignoring headers
|
||||
if len(ndata) > 0:
|
||||
row = ndata[-1]
|
||||
i = 1
|
||||
if 0 < self.windowsize < len(self.timeStamps[i]):
|
||||
self.timeStamps[i].pop(0)
|
||||
self.sensorsData[i].pop(0)
|
||||
|
||||
# self.timeStamps[i].append(datetime.now().strftime('%H:%M:%S')) # version 1
|
||||
|
||||
# version 2, if we decide to go with this one change the list type to list[int] from list[str]
|
||||
self.timeStamps[i].append(str(self.timeElapsed))
|
||||
|
||||
self.sensorsData[i].append(row[i])
|
||||
# plot a line
|
||||
# round the number to scientific notation
|
||||
self.axs_2.plot(self.timeStamps[i], self.sensorsData[i], color=self.colors[i],
|
||||
label=f'sensor {i + 1}, latest: {np.format_float_scientific(self.sensorsData[i][-1], precision = 2)} $\Omega$')
|
||||
# TODO: make the font size an UI option from the settings.json
|
||||
# Make the font size of values placed on x-axis and y-aixs equal to 16 (large enough)
|
||||
#self.axs_2.set_xticks(fontsize = max(self.fontSize, 10))
|
||||
#self.axs_2.set_yticks(fontsize = max(self.fontSize, 10))
|
||||
self.axs_2.tick_params(axis='both', which='both', labelsize=max(self.fontSize, 10))
|
||||
|
||||
# make the label of two axes large enough
|
||||
self.axs_2.set_xlabel('Time (seconds)', fontsize = max(self.fontSize, 10))
|
||||
self.axs_2.set_ylabel(u'Resistance ($\Omega$)', fontsize = max(self.fontSize, 10))
|
||||
#i += 1
|
||||
self.timeElapsed += 1 # increment time
|
||||
|
||||
# Acknowledgement: https://stackoverflow.com/a/13589144 (can you imagine how long it took me to find this before ChatGPT?)
|
||||
#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', fontsize = max(self.fontSize, 10)) # Make the legend on graph large enough
|
||||
|
||||
# handles, labels = self.axs_2.get_legend_handles_labels()
|
||||
# by_label = dict(zip(labels, handles))
|
||||
# self.axs_2.legend(by_label.values(), by_label.keys(), loc='best', fontsize = max(self.fontSize, 10))
|
||||
handles, labels = plt.gca().get_legend_handles_labels()
|
||||
by_label = dict(zip(labels, handles))
|
||||
plt.legend(by_label.values(), by_label.keys(), loc='best', fontsize = max(self.fontSize, 10))
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
def animation_3(self, t: int) -> None:
|
||||
"""
|
||||
render a frame of the animated graph.
|
||||
"""
|
||||
# Some of them copied from the old code, so even Eric may not 100% know what they do. ChatGPT may give a better explaination
|
||||
try:
|
||||
plt.cla() # clear previous frame
|
||||
# read the last line from the .csv file, the data start from the second column so omit index #0
|
||||
file = open(self.settings["file_name"], "r")
|
||||
ndata = np.array([np.asarray(line.split(", ")[1:], dtype=np.float32) for line in islice(file, 1, None)])#read from the second row of the file ignoring headers
|
||||
if len(ndata) > 0:
|
||||
row = ndata[-1]
|
||||
i = 2
|
||||
if 0 < self.windowsize < len(self.timeStamps[i]):
|
||||
self.timeStamps[i].pop(0)
|
||||
self.sensorsData[i].pop(0)
|
||||
|
||||
# self.timeStamps[i].append(datetime.now().strftime('%H:%M:%S')) # version 1
|
||||
|
||||
# version 2, if we decide to go with this one change the list type to list[int] from list[str]
|
||||
self.timeStamps[i].append(str(self.timeElapsed))
|
||||
|
||||
self.sensorsData[i].append(row[i])
|
||||
# plot a line
|
||||
# round the number to scientific notation
|
||||
self.axs_3.plot(self.timeStamps[i], self.sensorsData[i], color=self.colors[i],
|
||||
label=f'sensor {i + 1}, latest: {np.format_float_scientific(self.sensorsData[i][-1], precision = 2)} $\Omega$')
|
||||
# TODO: make the font size an UI option from the settings.json
|
||||
# Make the font size of values placed on x-axis and y-aixs equal to 16 (large enough)
|
||||
#self.axs_2.set_xticks(fontsize = max(self.fontSize, 10))
|
||||
#self.axs_2.set_yticks(fontsize = max(self.fontSize, 10))
|
||||
self.axs_3.tick_params(axis='both', which='both', labelsize=max(self.fontSize, 10))
|
||||
|
||||
# make the label of two axes large enough
|
||||
self.axs_3.set_xlabel('Time (seconds)', fontsize = max(self.fontSize, 10))
|
||||
self.axs_3.set_ylabel(u'Resistance ($\Omega$)', fontsize = max(self.fontSize, 10))
|
||||
#i += 1
|
||||
self.timeElapsed += 1 # increment time
|
||||
|
||||
# Acknowledgement: https://stackoverflow.com/a/13589144 (can you imagine how long it took me to find this before ChatGPT?)
|
||||
#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', fontsize = max(self.fontSize, 10)) # Make the legend on graph large enough
|
||||
|
||||
# handles, labels = self.axs_2.get_legend_handles_labels()
|
||||
# by_label = dict(zip(labels, handles))
|
||||
# self.axs_2.legend(by_label.values(), by_label.keys(), loc='best', fontsize = max(self.fontSize, 10))
|
||||
handles, labels = plt.gca().get_legend_handles_labels()
|
||||
by_label = dict(zip(labels, handles))
|
||||
plt.legend(by_label.values(), by_label.keys(), loc='best', fontsize = max(self.fontSize, 10))
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
def animation_4(self, t: int) -> None:
|
||||
"""
|
||||
render a frame of the animated graph.
|
||||
"""
|
||||
# Some of them copied from the old code, so even Eric may not 100% know what they do. ChatGPT may give a better explaination
|
||||
try:
|
||||
plt.cla() # clear previous frame
|
||||
# read the last line from the .csv file, the data start from the second column so omit index #0
|
||||
file = open(self.settings["file_name"], "r")
|
||||
ndata = np.array([np.asarray(line.split(", ")[1:], dtype=np.float32) for line in islice(file, 1, None)])#read from the second row of the file ignoring headers
|
||||
if len(ndata) > 0:
|
||||
row = ndata[-1]
|
||||
i = 3
|
||||
if 0 < self.windowsize < len(self.timeStamps[i]):
|
||||
self.timeStamps[i].pop(0)
|
||||
self.sensorsData[i].pop(0)
|
||||
|
||||
# self.timeStamps[i].append(datetime.now().strftime('%H:%M:%S')) # version 1
|
||||
|
||||
# version 2, if we decide to go with this one change the list type to list[int] from list[str]
|
||||
self.timeStamps[i].append(str(self.timeElapsed))
|
||||
|
||||
self.sensorsData[i].append(row[i])
|
||||
# plot a line
|
||||
# round the number to scientific notation
|
||||
self.axs_4.plot(self.timeStamps[i], self.sensorsData[i], color=self.colors[i],
|
||||
label=f'sensor {i + 1}, latest: {np.format_float_scientific(self.sensorsData[i][-1], precision = 2)} $\Omega$')
|
||||
# TODO: make the font size an UI option from the settings.json
|
||||
# Make the font size of values placed on x-axis and y-aixs equal to 16 (large enough)
|
||||
#self.axs_2.set_xticks(fontsize = max(self.fontSize, 10))
|
||||
#self.axs_2.set_yticks(fontsize = max(self.fontSize, 10))
|
||||
self.axs_4.tick_params(axis='both', which='both', labelsize=max(self.fontSize, 10))
|
||||
|
||||
# make the label of two axes large enough
|
||||
self.axs_4.set_xlabel('Time (seconds)', fontsize = max(self.fontSize, 10))
|
||||
self.axs_4.set_ylabel(u'Resistance ($\Omega$)', fontsize = max(self.fontSize, 10))
|
||||
#i += 1
|
||||
self.timeElapsed += 1 # increment time
|
||||
|
||||
# Acknowledgement: https://stackoverflow.com/a/13589144 (can you imagine how long it took me to find this before ChatGPT?)
|
||||
#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', fontsize = max(self.fontSize, 10)) # Make the legend on graph large enough
|
||||
|
||||
# handles, labels = self.axs_2.get_legend_handles_labels()
|
||||
# by_label = dict(zip(labels, handles))
|
||||
# self.axs_2.legend(by_label.values(), by_label.keys(), loc='best', fontsize = max(self.fontSize, 10))
|
||||
handles, labels = plt.gca().get_legend_handles_labels()
|
||||
by_label = dict(zip(labels, handles))
|
||||
plt.legend(by_label.values(), by_label.keys(), loc='best', fontsize = max(self.fontSize, 10))
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
def plotting_1(self) -> FuncAnimation:
|
||||
""" animate the dynamic plot """
|
||||
ani = FuncAnimation(self.fig, self.animation, blit=False, interval=self.delay * 1000, save_count=60)
|
||||
return ani
|
||||
ani_1 = FuncAnimation(self.fig_1, self.animation_1, blit=False, interval=self.delay * 1000, save_count=60)
|
||||
return ani_1
|
||||
|
||||
def plotting_2(self) -> FuncAnimation:
|
||||
""" animate the dynamic plot """
|
||||
ani_2 = FuncAnimation(self.fig_2, self.animation_2, blit=False, interval=self.delay * 1000, save_count=60)
|
||||
return ani_2
|
||||
|
||||
def plotting_3(self) -> FuncAnimation:
|
||||
""" animate the dynamic plot """
|
||||
ani_3 = FuncAnimation(self.fig_3, self.animation_3, blit=False, interval=self.delay * 1000, save_count=60)
|
||||
return ani_3
|
||||
|
||||
def plotting_4(self) -> FuncAnimation:
|
||||
""" animate the dynamic plot """
|
||||
ani_4 = FuncAnimation(self.fig_3, self.animation_3, blit=False, interval=self.delay * 1000, save_count=60)
|
||||
return ani_4
|
26
test.py
26
test.py
|
@ -5,6 +5,7 @@ from multiprocessing import *
|
|||
import os, sys, json, wx, importlib, warnings
|
||||
import serial.tools.list_ports
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
|
||||
|
@ -18,7 +19,7 @@ if '_PYIBoot_SPLASH' in os.environ and importlib.util.find_spec("pyi_splash"):
|
|||
HEIGHT = 800
|
||||
WIDTH = 800
|
||||
|
||||
global ani, t1
|
||||
#global ani, t1
|
||||
|
||||
# TODO: add the option to change the font size of the graph
|
||||
def main():
|
||||
|
@ -76,6 +77,8 @@ def gen_settings(resistors, input_voltage, port, filename, window_size, font_siz
|
|||
settings["file_name"] = filename
|
||||
settings["delay"] = delay
|
||||
settings["font_size"] = frame.fontSize.GetValue()
|
||||
global sensors
|
||||
sensors = len(settings['sensor_ports'])
|
||||
# TODO: get the input voltage from the UI and save it to the settings.json
|
||||
open(name, 'w').write(json.dumps(settings, indent=4))
|
||||
open(filename, "a", newline="", encoding="utf-8")
|
||||
|
@ -86,7 +89,7 @@ def run(e):
|
|||
run the read_arduino.py and Serial Plotter in parallel, but the plotter is in the main thread and other one can be in a separate thread, since
|
||||
matplot's FuncAnimation doesn't like to not be in the main thread (Big L for them..)
|
||||
"""
|
||||
global ani, t1 # the variables to call the plotter and the read_arduino.py, we want them to get tossed around between functions and even programs
|
||||
global ani_1, t1, ani_2, ani_3, ani_4 # the variables to call the plotter and the read_arduino.py, we want them to get tossed around between functions and even programs
|
||||
main()
|
||||
if 't1' in globals():
|
||||
t1.terminate() # end the previous serial reads, if there is any
|
||||
|
@ -97,8 +100,23 @@ def run(e):
|
|||
# run the plotter. Note that we should not put the plotter class, or function, in another process since
|
||||
# matplot's FuncAnimation doesn't like that
|
||||
plotter = SerialPlotter(frame)
|
||||
ani = plotter.plotting()
|
||||
plotter.fig.show()
|
||||
if (sensors == 1) :
|
||||
ani_1 = plotter.plotting_1()
|
||||
elif (sensors == 2):
|
||||
ani_1 = plotter.plotting_1()
|
||||
ani_2 = plotter.plotting_2()
|
||||
elif (sensors == 3) :
|
||||
ani_1 = plotter.plotting_1()
|
||||
ani_2 = plotter.plotting_2()
|
||||
ani_3 = plotter.plotting_3()
|
||||
elif (sensors == 4) :
|
||||
ani_1 = plotter.plotting_1()
|
||||
ani_2 = plotter.plotting_2()
|
||||
ani_3 = plotter.plotting_3()
|
||||
ani_4 = plotter.plotting_4()
|
||||
#plotter.fig_1.show()
|
||||
#plotter.fig_2.show()
|
||||
plt.show()
|
||||
|
||||
frame.btLaunch.SetLabelText("Plot") # change the text on the "launch" button to "plot"
|
||||
if not frame.show_msg.GetValue():
|
||||
|
|
Loading…
Reference in New Issue