Fixed graph export buttons

This commit is contained in:
2022-10-08 18:12:18 +02:00
parent effcc72966
commit d5c9879eae
4 changed files with 150 additions and 68 deletions
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 291 KiB

+78 -43
View File
@@ -410,12 +410,13 @@ class MagnetometerCalibrationSimple(Thread):
class MagnetometerCalibrationComplete(Thread):
TEST_VECTOR_MAGNITUDE = 100e-6 # In Tesla. Chosen so it can be achieved with a 3A PSU.
def __init__(self, view_queue, calibration_points, calibration_interval, mgm_to_helmholtz_cos_trans):
def __init__(self, view_queue, calibration_points, calibration_interval, mgm_to_helmholtz_cos_trans,right_column):
Thread.__init__(self)
self.view_queue = view_queue
self.calibration_points = calibration_points
self.calibration_interval = calibration_interval
self.matrix_trans_mgm_to_hh = [[x.get() for x in row] for row in mgm_to_helmholtz_cos_trans]
self.right_column = right_column
# Hardware checks are done in the init method to allow for exception handling in main thread
# This means the run method should/must be called directly after Thread object creation.
@@ -754,6 +755,7 @@ class MagnetometerCalibrationComplete(Thread):
def plot_magnetometer_calibration(self, mag_x_set, mag_y_set, mag_z_set, mag_x_m, mag_y_m, mag_z_m, cal_x, cal_y,
cal_z, mag_amp_avg_set):
plot_fontsize = 5
ax_width = 0.2
# Plot frame (overwrite plotframe)
plot_frame = LabelFrame(self.right_column, text="Result plots:")
@@ -773,16 +775,23 @@ class MagnetometerCalibrationComplete(Thread):
ax1.set_ylabel(r'$B_y [{\mu}T]$', fontsize=plot_fontsize)
ax1.set_zlabel(r'$B_z [{\mu}T]$', fontsize=plot_fontsize)
ax1.tick_params(axis='both', labelsize=plot_fontsize)
for axis in ['top', 'bottom', 'left', 'right']:
ax1.spines[axis].set_linewidth(ax_width)
ax1.xaxis.set_tick_params(width=ax_width)
ax1.yaxis.set_tick_params(width=ax_width)
ax1.zaxis.set_tick_params(width=ax_width)
ax1.grid(which='major', linewidth=ax_width)
ax1.grid(which='minor', linewidth=ax_width/2)
# linking lines between measured and calibrated points
for i, j, k, l, m, n in zip(mag_x_set * u_tesla, mag_y_set * u_tesla, mag_z_set * u_tesla, mag_x_m * u_tesla,
mag_y_m * u_tesla,
mag_z_m * u_tesla):
ax1.plot([i, l], [j, m], [k, n], linewidth=0.5, color='b')
ax1.plot([i, l], [j, m], [k, n], linewidth=0.2, color='b')
# set magnetic vectors
l1 = ax1.scatter(mag_x_set * u_tesla, mag_y_set * u_tesla, mag_z_set * u_tesla, s=5, color='k',
l1 = ax1.scatter(mag_x_set * u_tesla, mag_y_set * u_tesla, mag_z_set * u_tesla, s=1, color='k',
label="$B_{set}$ Helmholtz field")
# measured values
l2 = ax1.scatter(mag_x_m * u_tesla, mag_y_m * u_tesla, mag_z_m * u_tesla, s=5, color='b',
l2 = ax1.scatter(mag_x_m * u_tesla, mag_y_m * u_tesla, mag_z_m * u_tesla, s=1, color='b',
label="$B_{raw}$ uncalibrated")
# plot sphere with magnitude
u = np.linspace(0, 2 * np.pi, 100)
@@ -790,8 +799,8 @@ class MagnetometerCalibrationComplete(Thread):
x = np.outer(np.cos(u), np.sin(v)) * mag_amp_avg_set
y = np.outer(np.sin(u), np.sin(v)) * mag_amp_avg_set
z = np.outer(np.ones(np.size(u)), np.cos(v)) * mag_amp_avg_set
ax1.plot_wireframe(x * u_tesla, y * u_tesla, z * u_tesla, rstride=10, cstride=10, alpha=0.7, color='y')
ax1.plot_surface(x * u_tesla, y * u_tesla, z * u_tesla, alpha=0.3, color='y')
ax1.plot_wireframe(x * u_tesla, y * u_tesla, z * u_tesla, rstride=10, cstride=10, alpha=0.7, color='y', linewidth=0.1)
ax1.plot_surface(x * u_tesla, y * u_tesla, z * u_tesla, alpha=0.3, color='y', linewidth=0.1)
# ax1.legend(loc='upper right', fontsize=plot_fontsize)
# Calibrated result plot
@@ -800,16 +809,23 @@ class MagnetometerCalibrationComplete(Thread):
ax2.set_ylabel(r'$B_y [\mu T]$', fontsize=plot_fontsize)
ax2.set_zlabel(r'$B_z [\mu T]$', fontsize=plot_fontsize)
ax2.tick_params(axis='both', labelsize=plot_fontsize)
for axis in ['top', 'bottom', 'left', 'right']:
ax2.spines[axis].set_linewidth(ax_width)
ax2.xaxis.set_tick_params(width=ax_width)
ax2.yaxis.set_tick_params(width=ax_width)
ax2.zaxis.set_tick_params(width=ax_width)
ax2.grid(which='major', linewidth=ax_width)
ax2.grid(which='minor', linewidth=ax_width/2)
# linking lines between measured and calibrated points
for i, j, k, l, m, n in zip(mag_x_set * u_tesla, mag_y_set * u_tesla, mag_z_set * u_tesla, cal_x * u_tesla,
cal_y * u_tesla,
cal_z * u_tesla):
ax2.plot([i, l], [j, m], [k, n], linewidth=0.5, color='r')
ax2.plot([i, l], [j, m], [k, n], linewidth=0.2, color='r')
# set magnetic vectors
l3 = ax2.scatter(mag_x_set * u_tesla, mag_y_set * u_tesla, mag_z_set * u_tesla, s=5, color='k',
l3 = ax2.scatter(mag_x_set * u_tesla, mag_y_set * u_tesla, mag_z_set * u_tesla, s=1, color='k',
label="$B_{set}$ Helmholtz field")
# calibrated values ellipsoid fit
l4 = ax2.scatter(cal_x * u_tesla, cal_y * u_tesla, cal_z * u_tesla, s=5, color='r',
l4 = ax2.scatter(cal_x * u_tesla, cal_y * u_tesla, cal_z * u_tesla, s=1, color='r',
label="$B_{cal,el}$ ellipsoid fit")
# plot sphere with magnitude
u = np.linspace(0, 2 * np.pi, 100)
@@ -817,17 +833,18 @@ class MagnetometerCalibrationComplete(Thread):
x = np.outer(np.cos(u), np.sin(v)) * mag_amp_avg_set
y = np.outer(np.sin(u), np.sin(v)) * mag_amp_avg_set
z = np.outer(np.ones(np.size(u)), np.cos(v)) * mag_amp_avg_set
ax2.plot_wireframe(x * u_tesla, y * u_tesla, z * u_tesla, rstride=10, cstride=10, alpha=0.7, color='y')
ax2.plot_surface(x * u_tesla, y * u_tesla, z * u_tesla, alpha=0.3, color='y')
ax2.plot_wireframe(x * u_tesla, y * u_tesla, z * u_tesla, rstride=10, cstride=10, alpha=0.7, color='y', linewidth=0.1)
ax2.plot_surface(x * u_tesla, y * u_tesla, z * u_tesla, alpha=0.3, color='y', linewidth=0.1)
# ax2.legend(loc='upper right', fontsize=plot_fontsize)
ax3 = fig1.add_subplot(222)
ax3.axis('off')
ax3.legend([l1, l2], ["$B_{set}$", "$B_{raw}$"],
loc='upper right', fontsize=plot_fontsize)
loc='right', fontsize=plot_fontsize)
ax4 = fig1.add_subplot(224)
ax4.axis('off')
ax4.legend([l3, l4], ["$B_{set}$", "$B_{cal,el}$"],
loc='upper right', fontsize=plot_fontsize)
loc='right', fontsize=plot_fontsize)
fig1.subplots_adjust(bottom=0.15, left=0.05, right=0.95, top=1.0)
canvas1.draw()
canvas1.get_tk_widget().grid(row=0, column=0)
@@ -836,41 +853,59 @@ class MagnetometerCalibrationComplete(Thread):
fig2.clf() # clear figure from previous use
canvas2 = FigureCanvasTkAgg(fig2, plot_frame)
# x panel
ax3 = fig2.add_subplot(311)
ax3.set_ylabel(r'$B_x [\mu T]$', fontsize=plot_fontsize)
ax3.plot(np.linspace(1, meas_no, meas_no), mag_x_set * u_tesla, linewidth=0.5, color='k', linestyle='solid',
ax5 = fig2.add_subplot(311)
ax5.grid(which='major', linewidth=ax_width)
ax5.grid(which='minor', linewidth=ax_width/2)
ax5.set_ylabel(r'$B_x [\mu T]$', fontsize=plot_fontsize)
ax5.plot(np.linspace(1, meas_no, meas_no), mag_x_set * u_tesla, linewidth=0.2, color='k', linestyle='solid',
label=r'$B_{x,set}$')
ax3.plot(np.linspace(1, meas_no, meas_no), mag_x_m * u_tesla, linewidth=0.5, color='b', linestyle='solid',
ax5.plot(np.linspace(1, meas_no, meas_no), mag_x_m * u_tesla, linewidth=0.2, color='b', linestyle='solid',
label=r'$B_{x,m}$')
ax3.plot(np.linspace(1, meas_no, meas_no), cal_x * u_tesla, linewidth=0.5, color='r', linestyle='solid',
ax5.plot(np.linspace(1, meas_no, meas_no), cal_x * u_tesla, linewidth=0.2, color='r', linestyle='solid',
label=r'$B_{x,el}$')
ax3.legend(loc='upper right', fontsize=plot_fontsize)
ax3.tick_params(axis='both', labelsize=plot_fontsize)
ax3.axes.get_xaxis().set_visible(False)
# y panel
ax4 = fig2.add_subplot(312)
ax4.set_ylabel(r'$B_y [\mu T]$', fontsize=plot_fontsize)
ax4.plot(np.linspace(1, meas_no, meas_no), mag_y_set * u_tesla, linewidth=0.5, color='k', linestyle='solid',
label=r'$B_{y,set}$')
ax4.plot(np.linspace(1, meas_no, meas_no), mag_y_m * u_tesla, linewidth=0.5, color='b', linestyle='solid',
label=r'$B_{y,m}$')
ax4.plot(np.linspace(1, meas_no, meas_no), cal_y * u_tesla, linewidth=0.5, color='r', linestyle='solid',
label=r'$B_{y,el}$')
ax4.legend(loc='upper right', fontsize=plot_fontsize)
ax4.tick_params(axis='both', labelsize=plot_fontsize)
ax4.axes.get_xaxis().set_visible(False)
# z panel
ax5 = fig2.add_subplot(313)
ax5.set_xlabel("Measurement number", fontsize=plot_fontsize)
ax5.set_ylabel(r'$B_z [\mu T]$', fontsize=plot_fontsize)
ax5.plot(np.linspace(1, meas_no, meas_no), mag_z_set * u_tesla, linewidth=0.5, color='k', linestyle='solid',
label=r'$B_{z,set}$')
ax5.plot(np.linspace(1, meas_no, meas_no), mag_z_m * u_tesla, linewidth=0.5, color='b', linestyle='solid',
label=r'$B_{z,m}$')
ax5.plot(np.linspace(1, meas_no, meas_no), cal_z * u_tesla, linewidth=0.5, color='r', linestyle='solid',
label=r'$B_{z,el}$')
ax5.legend(loc='upper right', fontsize=plot_fontsize)
ax5.tick_params(axis='both', labelsize=plot_fontsize)
ax5.axes.get_xaxis().set_visible(False)
for axis in ['top', 'bottom', 'left', 'right']:
ax5.spines[axis].set_linewidth(ax_width)
ax5.xaxis.set_tick_params(width=ax_width)
ax5.yaxis.set_tick_params(width=ax_width)
# y panel
ax6 = fig2.add_subplot(312)
ax6.grid(which='major', linewidth=ax_width)
ax6.grid(which='minor', linewidth=ax_width/2)
ax6.set_ylabel(r'$B_y [\mu T]$', fontsize=plot_fontsize)
ax6.plot(np.linspace(1, meas_no, meas_no), mag_y_set * u_tesla, linewidth=0.2, color='k', linestyle='solid',
label=r'$B_{y,set}$')
ax6.plot(np.linspace(1, meas_no, meas_no), mag_y_m * u_tesla, linewidth=0.2, color='b', linestyle='solid',
label=r'$B_{y,m}$')
ax6.plot(np.linspace(1, meas_no, meas_no), cal_y * u_tesla, linewidth=0.2, color='r', linestyle='solid',
label=r'$B_{y,el}$')
ax6.legend(loc='upper right', fontsize=plot_fontsize)
ax6.tick_params(axis='both', labelsize=plot_fontsize)
ax6.axes.get_xaxis().set_visible(False)
for axis in ['top', 'bottom', 'left', 'right']:
ax6.spines[axis].set_linewidth(ax_width)
ax6.xaxis.set_tick_params(width=ax_width)
ax6.yaxis.set_tick_params(width=ax_width)
# z panel
ax7 = fig2.add_subplot(313)
ax7.grid(which='major', linewidth=ax_width)
ax7.grid(which='minor', linewidth=ax_width/2)
ax7.set_xlabel("Measurement number", fontsize=plot_fontsize)
ax7.set_ylabel(r'$B_z [\mu T]$', fontsize=plot_fontsize)
ax7.plot(np.linspace(1, meas_no, meas_no), mag_z_set * u_tesla, linewidth=0.2, color='k', linestyle='solid',
label=r'$B_{z,set}$')
ax7.plot(np.linspace(1, meas_no, meas_no), mag_z_m * u_tesla, linewidth=0.2, color='b', linestyle='solid',
label=r'$B_{z,m}$')
ax7.plot(np.linspace(1, meas_no, meas_no), cal_z * u_tesla, linewidth=0.2, color='r', linestyle='solid',
label=r'$B_{z,el}$')
ax7.legend(loc='upper right', fontsize=plot_fontsize)
ax7.tick_params(axis='both', labelsize=plot_fontsize)
for axis in ['top', 'bottom', 'left', 'right']:
ax7.spines[axis].set_linewidth(ax_width)
ax7.xaxis.set_tick_params(width=ax_width)
ax7.yaxis.set_tick_params(width=ax_width)
canvas2.draw()
canvas2.get_tk_widget().grid(row=0, column=1)
+72 -24
View File
@@ -10,6 +10,7 @@ from tkinter import ttk
from tkinter import messagebox
from tkinter import filedialog
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
# import general packages:
import numpy as np
@@ -1625,7 +1626,7 @@ class CalibrateMagnetometerComplete(Frame):
self.copy_calibration_button.grid(row=0, column=1, padx=5, pady=5)
self.import_calibration_data_button = Button(save_calibration_results_frame, text="Import data set",
command=self.import_csv_calibration_raw_data,
state="active",
state="normal",
pady=5, padx=5)
self.import_calibration_data_button.grid(row=0, column=2, padx=5, pady=5)
@@ -1633,10 +1634,35 @@ class CalibrateMagnetometerComplete(Frame):
# Notes on the calibration method
calibration_method_notes_frame = LabelFrame(self.right_column, text="Calibration method notes:")
calibration_method_notes_frame.grid(row=0, column=0, padx=(100, 0), pady=20, sticky="nw")
label = "-Implementation of calibration according to Kok et al. [ISBN: 978-0-9824438-5-9]\n-Implementation of ellipsoid fit according to Li et al. [DOI: 10.1109/GMAP.2004.1290055]\n-Points created by Fibonacci sphere\n-Accounts for soft-iron (A matrix) and hard-iron (b offset vector) effects!\n-MEasured to calibrated field function: h=A^-1 (h_m-b)"
label = "-Implementation of calibration according to Kok et al. [ISBN: 978-0-9824438-5-9]\n-Implementation of ellipsoid fit according to Li et al. [DOI: 10.1109/GMAP.2004.1290055]\n-Points created by Fibonacci sphere\n-Accounts for soft-iron (A matrix) and hard-iron (b offset vector) effects!\n-Measured to calibrated field function: h=A^-1 (h_m-b)"
calibration_method_notes = Label(calibration_method_notes_frame, anchor='w', justify='left', text=label)
calibration_method_notes.grid(row=0, column=0, padx=5, pady=5, sticky="nw")
# Plot frame (overwrite plotframe)
plot_frame = LabelFrame(self.right_column, text="Result plots:")
plot_frame.grid(row=1, column=0, padx=(100, 0), pady=20, sticky="nw")
fig1 = plt.figure('MGM_cal_complete_left', figsize=(2.5, 3), dpi=100)
canvas1 = FigureCanvasTkAgg(fig1, plot_frame)
canvas1.draw()
canvas1.get_tk_widget().grid(row=0, column=0, columnspan=2)
fig2 = plt.figure('MGM_cal_complete_right', figsize=(4, 3), dpi=100)
canvas2 = FigureCanvasTkAgg(fig2, plot_frame)
canvas2.draw()
canvas2.get_tk_widget().grid(row=0, column=2, columnspan=2)
# Export figures with buttons
self.export_figure_left_button = Button(plot_frame, text="Export graph to file",
command=lambda: self.export_figure1_to_file(fig1),
state="active",
pady=5, padx=5)
self.export_figure_left_button.grid(row=1, column=0, padx=5, pady=5)
self.export_figure_right_button = Button(plot_frame, text="Export graph to file",
command=lambda: self.export_figure2_to_file(fig2),
state="normal",
pady=5, padx=5)
self.export_figure_right_button.grid(row=1, column=2, padx=5, pady=5)
# FLAG Buttons
# This starts an endless polling loop
self.update_view()
@@ -1744,7 +1770,8 @@ class CalibrateMagnetometerComplete(Frame):
self.calibration_thread = MagnetometerCalibrationComplete(self.view_mpi_queue,
calibration_points,
calibration_interval,
self.mgm_to_helmholtz_cos_trans)
self.mgm_to_helmholtz_cos_trans,
self.right_column)
self.calibration_thread.start()
self.deactivate_buttons()
except (DeviceAccessError, TclError) as e:
@@ -1758,26 +1785,30 @@ class CalibrateMagnetometerComplete(Frame):
ui_print("Saved calibration results to magnetometer_calibration.csv.")
def import_csv_calibration_raw_data(self):
data, raw_data, filename = load_dict_list_from_csv('magnetometer_calibration.csv', query_path=True)
if data is None or filename is None:
ui_print("File could not be loaded! Read file name is {]".format(filename))
return
ui_print("Loaded calibration results from {}".format(filename))
ui_print("Size of read data is {}.".format(data.shape))
if data.shape[1] != 6:
ui_print("File does not have 6 columns instead of {}!".format(data.shape))
ui_print("[h_x_set|h_y_set|h_z_set|h_x_m|h_y_m|h_z_m|")
return
self.calibration_raw_results = raw_data
try:
data, raw_data, filename = load_dict_list_from_csv('magnetometer_calibration.csv', query_path=True)
if data is None or filename is None:
ui_print("File could not be loaded! Read file name is {]".format(filename))
return
ui_print("Loaded calibration results from {}".format(filename))
ui_print("Size of read data is {}.".format(data.shape))
if data.shape[1] != 6:
ui_print("File does not have 6 columns instead of {}!".format(data.shape))
ui_print("[h_x_set|h_y_set|h_z_set|h_x_m|h_y_m|h_z_m|")
return
self.calibration_raw_results = raw_data
# Execute calibration function and display results
sensor_parameters, mag_x_set, mag_y_set, mag_z_set, mag_x_m, mag_y_m, mag_z_m, cal_x, cal_y, cal_z, mag_amp_avg_set = MagnetometerCalibrationComplete.solve_system(
self.view_mpi_queue, raw_data, self.mgm_to_helmholtz_cos_trans)
MagnetometerCalibrationComplete.plot_magnetometer_calibration(self, mag_x_set, mag_y_set, mag_z_set, mag_x_m,
mag_y_m, mag_z_m, cal_x, cal_y,
cal_z, mag_amp_avg_set)
# Pass results to UI
self.put_message('calibration_data', {'results': sensor_parameters, 'raw_data': raw_data})
# Execute calibration function and display results
sensor_parameters, mag_x_set, mag_y_set, mag_z_set, mag_x_m, mag_y_m, mag_z_m, cal_x, cal_y, cal_z, mag_amp_avg_set = MagnetometerCalibrationComplete.solve_system(
self.view_mpi_queue, raw_data, self.mgm_to_helmholtz_cos_trans)
MagnetometerCalibrationComplete.plot_magnetometer_calibration(self, mag_x_set, mag_y_set, mag_z_set,
mag_x_m,
mag_y_m, mag_z_m, cal_x, cal_y,
cal_z, mag_amp_avg_set)
# Pass results to UI
self.put_message('calibration_data', {'results': sensor_parameters, 'raw_data': raw_data})
except TypeError:
ui_print('File path is incorrect, no data could be loaded!')
def export_csv_cos_trans_matrix(self):
cos_trans_matrix = [
@@ -1794,8 +1825,25 @@ class CalibrateMagnetometerComplete(Frame):
if cos_trans_matrix is None:
ui_print("Error: Failed to export non-existent coordinate transformation matrix.")
return
save_dict_list_to_csv('magnetometer_cos_trans_matrix.csv', cos_trans_matrix, query_path=True)
ui_print("Saved MGM to Helmholtz coordinate transformation matrix to magnetometer_cos_trans_matrix.csv.")
try:
save_dict_list_to_csv('magnetometer_cos_trans_matrix.csv', cos_trans_matrix, query_path=True)
ui_print("Saved MGM to Helmholtz coordinate transformation matrix to magnetometer_cos_trans_matrix.csv.")
except FileNotFoundError:
ui_print('Did not save matrix since incorrect file path specified!')
def export_figure1_to_file(self, figure):
filename = 'MGM_calibration_ellipsoid_fit_3D'
filename = filedialog.asksaveasfilename(initialfile=filename, title="Select location to save figure.",
filetypes=[("PNG", '*.png'), ("PDF", '*.pdf')],
defaultextension=".pdf")
figure.savefig(filename, dpi=2000, transparent=True)
def export_figure2_to_file(self, figure):
filename = 'MGM_calibration_ellipsoid_fit_2D'
filename = filedialog.asksaveasfilename(initialfile=filename, title="Select location to save figure.",
filetypes=[("PNG", '*.png'), ("PDF", '*.pdf')],
defaultextension=".pdf")
figure.savefig(filename, dpi=1000, transparent=True)
def put_message(self, command, arg):
self.view_mpi_queue.put({'cmd': command, 'arg': arg})
-1
View File
@@ -41,7 +41,6 @@ def load_dict_list_from_csv(filename, query_path=False):
if query_path:
filename = filedialog.askopenfilename(initialfile=filename, title="Select csv file location...",
filetypes=(("CSV", "*.csv"),))
data = np.genfromtxt(filename, dtype=float, delimiter=',')
data = data[1:len(data), :] # remove header
# Save data point to raw_data list