Visual improvements for csv graphs

This commit is contained in:
Martin Zietz
2021-02-09 12:21:07 +01:00
parent 792848dda2
commit a0bab62ebc
4 changed files with 82 additions and 61 deletions
+13 -15
View File
@@ -279,7 +279,6 @@ class Configuration(Frame):
self.file_select_frame.grid(row=row_counter, column=0, sticky=W, padx=20)
# Create and place buttons
# ToDo: comments
load_file_button = Button(self.file_select_frame, text="Load config file...", command=self.load_config,
pady=5, padx=5, font=SMALL_BUTTON_FONT)
load_file_button.grid(row=0, column=0, padx=5)
@@ -299,17 +298,17 @@ class Configuration(Frame):
port_frame.grid(row=row_counter, column=0, sticky=W)
entry_texts = ["XY PSU Serial Port:", "Z PSU Serial Port:"]
self.XY_port = StringVar(value=g.XY_PORT)
self.XY_port = StringVar(value=g.XY_PORT) # create variables to store the port names and set to current names
self.Z_port = StringVar(value=g.Z_PORT)
port_vars = [self.XY_port, self.Z_port]
row = 0
for text in entry_texts:
field = Entry(port_frame, textvariable=port_vars[row])
field = Entry(port_frame, textvariable=port_vars[row]) # create entry field
field.grid(row=row, column=1, sticky=W)
axis_label = Label(port_frame, text=text, padx=5, pady=10)
axis_label.grid(row=row, column=0, sticky=W)
unit_label = Label(port_frame, text="e.g. COM10")
unit_label.grid(row=row, column=2, sticky=W)
info_label = Label(port_frame, text="e.g. COM10")
info_label.grid(row=row, column=2, sticky=W)
row += 1
row_counter += 1
@@ -514,7 +513,6 @@ class Configuration(Frame):
class ExecuteCSVMode(Frame):
# generate configuration window to set program constants
# ToDo (optional): Generate graph to show sequence to be executed
def __init__(self, parent, controller):
Frame.__init__(self, parent)
@@ -606,13 +604,13 @@ class ExecuteCSVMode(Frame):
if exists(filename): # does the file exist?
ui_print("File selected:", filename)
try:
self.sequence_array = csv.read_csv_to_array(filename)
self.sequence_array = csv.read_csv_to_array(filename) # read array from csv
except BaseException as e:
ui_print("Error while opening file:", e)
messagebox.showerror("Error!", "Error while opening file: \n%s" % e)
csv.check_array(self.sequence_array)
self.display_plot()
csv.check_array_ok(self.sequence_array) # check for values exceeding limits
self.display_plot() # plot data and display
self.execute_button["state"] = "normal" # activate run button
elif filename == '': # this happens when file selection window is closed without selecting a file
@@ -641,8 +639,8 @@ class ExecuteCSVMode(Frame):
self.stop_button["state"] = "disabled"
self.reinit_button["state"] = "normal"
def display_plot(self): # ToDo: comments
# calculate available height for plot:
def display_plot(self):
# calculate available height for plot (in pixels):
height_others = 0
for element in self.row_elements: # go through all rows in the widget except the plot frame
height_others += element.winfo_height() # add up heights
@@ -650,10 +648,10 @@ class ExecuteCSVMode(Frame):
width = min(self.parent.winfo_width() - 100, 1100) # set width to available space but max. 1100
figure = csv.plot_field_sequence(self.sequence_array, width, height)
plotCanvas = FigureCanvasTkAgg(figure, self.plotFrame)
plotCanvas.draw()
plotCanvas.get_tk_widget().grid(row=0, column=0, sticky="nesw")
figure = csv.plot_field_sequence(self.sequence_array, width, height) # create figure to be displayed
plotCanvas = FigureCanvasTkAgg(figure, self.plotFrame) # create canvas to draw figure on
plotCanvas.draw() # equivalent to matplotlib.show()
plotCanvas.get_tk_widget().grid(row=0, column=0, sticky="nesw") # place canvas in UI
class StatusDisplay(Frame):
+16 -15
View File
@@ -364,16 +364,17 @@ def set_current_vec(vector): # sets needed currents on each axis for given vect
def devices_ok(xy_off=False, z_off=False, arduino_off=False):
# ToDo: comments
try:
if not xy_off:
if g.XY_DEVICE is not None:
g.X_AXIS.update_status_info()
if g.X_AXIS.connected != "Connected":
return False
else:
# check if all devices are connected, return True if yes
# checks for individual devices can be disabled by parameters above (default not disabled)
try: # handle errors while checking connections
if not xy_off: # if check for this device is not disabled
if g.XY_DEVICE is not None: # has the handle for this device been set?
g.X_AXIS.update_status_info() # update info --> this actually communicates with the device
if g.X_AXIS.connected != "Connected": # if not connected
return False # return and exit function
else: # if handle has not been set the device is inactive --> not ok
return False
if not z_off:
if not z_off: # same as above
if g.Z_DEVICE is not None:
g.Z_AXIS.update_status_info()
if g.Z_AXIS.connected != "Connected":
@@ -381,12 +382,12 @@ def devices_ok(xy_off=False, z_off=False, arduino_off=False):
else:
return False
if not arduino_off:
g.ARDUINO.update_status_info()
if not arduino_off: # check not disabled
g.ARDUINO.update_status_info() # update status info --> attempts communication
if g.ARDUINO.connected != "Connected":
return False
except Exception as e:
messagebox.showerror("Error!", "Error while checking devices: \n%s" % e)
return False
else:
except Exception as e: # if an error is encountered while checking the devices
messagebox.showerror("Error!", "Error while checking devices: \n%s" % e) # show error pop-up
return False # clearly something is not ok
else: # if nothing has triggered so far all devices are ok --> return True
return True
+41 -31
View File
@@ -11,7 +11,6 @@ import globals as g
class ExecCSVThread(Thread):
# ToDo: handling for disconnected devices
def __init__(self, threadID, array, parent, controller):
Thread.__init__(self)
@@ -79,46 +78,57 @@ def execute_sequence(array, delay, parent, controller): # runs through array co
def read_csv_to_array(filepath):
# csv format: time (s); xField (T); yField (T); zField (T) (german excel)
# decimal commas
ui.ui_print("Reading File:", filepath)
file = pandas.read_csv(filepath, sep=';', decimal=',', header=0) # read csv file
array = file.to_numpy() # convert csv to array
return array
def check_array(array):
# ToDo: message formatting, pop up warning
# ToDo: comments
concerns = []
for row in array:
i = 1
for axis in g.AXES:
value = row[i]
if value > axis.max_comp_field[1]:
concerns.append(row)
elif value < axis.max_comp_field[0]:
concerns.append(row)
i += 1
ui.ui_print("Checked csv, found %i concerns." % len(concerns))
if len(concerns) > 0:
ui.ui_print(concerns)
def check_array_ok(array): # check if any magnetic fields in an array exceed the limits
values_ok = True
for i in [0, 1, 2]: # go through axes
max_val = g.AXES[i].max_comp_field[1] # get limits
min_val = g.AXES[i].max_comp_field[0]
data = array[:, i + 1] # extract data for this axis from array
# noinspection PyTypeChecker
if any(data > max_val) or any(data < min_val): # if any datapoint is out of bounds
values_ok = False
if not values_ok: # show warning pop-up if values are exceeding limits
messagebox.showwarning("Value Limits Warning!", "Found field values exceeding limits of test stand."
"\nSee plot and check values in csv.")
def plot_field_sequence(array, width, height): # ToDo: comments
# ToDo: make pretty
fig_dpi = 100
px = 1/fig_dpi
figure = plt.Figure(figsize=(width*px, height*px), dpi=fig_dpi)
def plot_field_sequence(array, width, height): # create plot of fixed size from array
# ToDo (optional): polar plots, plots of angle...
# ToDo (optional): show graphs as steps (as performed by test stand)
fig_dpi = 100 # set figure resolution
px = 1/fig_dpi # get pixel to inch size conversion
figure = plt.Figure(figsize=(width*px, height*px), dpi=fig_dpi) # create figure with correct size
# noinspection PyTypeChecker,SpellCheckingInspection
axes = figure.subplots(3, sharex=True, sharey=True, gridspec_kw={'hspace': 0.4})
axes = figure.subplots(3, sharex=True, sharey=True, gridspec_kw={'hspace': 0.4}) # create subplots with shared axes
figure.suptitle("Magnetic Field Sequence")
t = array[:, 0]
for i in [0, 1, 2]:
data = array[:, i + 1] * 1e6
plot = axes[i]
plot.plot(t, data)
plot.set_title(g.AXIS_NAMES[i])
t = array[:, 0] # extract time column
for i in [0, 1, 2]: # go through all three axes
data = array[:, i + 1] * 1e6 # extract field column of this axis
max_val = g.AXES[i].max_comp_field[1] * 1e6 # get limits of achievable field
min_val = g.AXES[i].max_comp_field[0] * 1e6
plot = axes[i] # get appropriate subplot
return figure
plot.plot(t, data, linestyle='solid', marker='.') # plot data
if any(data > max_val): # if any value is higher than the maximum
plot.axhline(y=max_val, linestyle='dashed', color='r') # plot horizontal line to show maximum
# add label to line:
plot.text(t[-1], max_val, "max", horizontalalignment='center', verticalalignment='top', color='r')
if any(data < min_val): # same as above
plot.axhline(y=min_val, linestyle='dashed', color='r')
plot.text(t[-1], min_val, "min", horizontalalignment='center', color='r')
plot.set_title(g.AXIS_NAMES[i], size=10) # set subplot title (e.g. "X-Axis")
# set shared axis labels:
axes[2].set_xlabel("Time (s)")
axes[1].set_ylabel("Magnetic Field (\u03BCT)")
return figure # return the created figure to be inserted somewhere else
+12
View File
@@ -0,0 +1,12 @@
Time (s);xField (T);yField (T);zField (T);
0;0,00015;-0,00015;0,00002;150
1;0,00017;-0,00017;0,00002;170
2;0,00018;-0,00018;0,00002;180
3;0,00019;-0,00019;0,00002;190
4;0,0002;-0,0002;0,00002;200
5;0,00021;-0,00021;0,00002;210
6;0,00022;-0,00022;0,00002;220
7;0,0002;-0,0002;0,00002;200
8;0,00018;-0,00018;0,00002;180
9;0,00005;-0,00005;0,00002;50
10;-0,00004;0,00004;0,00002;-40
1 Time (s) xField (T) yField (T) zField (T)
2 0 0,00015 -0,00015 0,00002 150
3 1 0,00017 -0,00017 0,00002 170
4 2 0,00018 -0,00018 0,00002 180
5 3 0,00019 -0,00019 0,00002 190
6 4 0,0002 -0,0002 0,00002 200
7 5 0,00021 -0,00021 0,00002 210
8 6 0,00022 -0,00022 0,00002 220
9 7 0,0002 -0,0002 0,00002 200
10 8 0,00018 -0,00018 0,00002 180
11 9 0,00005 -0,00005 0,00002 50
12 10 -0,00004 0,00004 0,00002 -40