#!/usr/bin/env python # # file: event_loop.py # # This script implements the event loop of the ISIP Machine Learning Demo # user interface. The event loop runs until the application is quit. #----------------------------------------------------------------------------- # import system modules # import numpy as np import time as t from sklearn.preprocessing import Normalizer from copy import deepcopy import os import traceback # import GUI modules # from PyQt5 import QtGui, QtCore, QtWidgets # import locally defined modules # import imld_gui_window as igw import imld_gui_params as igp from imld_data_gen import DataGenerator import imld_data_io as idio import imld_model as model import nedc_file_tools as nft # import the modified ml tools that includes custom algorithms from # imld_gui_window.py # from imld_gui_window import ml #----------------------------------------------------------------------------- # # define global variables # #----------------------------------------------------------------------------- SELECTED_CLASS = "" TOTAL_CLASSES = [] SELECTED_NAME = "" TOTAL_NAMES = [] STANDARD_COLORS = ["red","blue","yellow","black","orange","purple","green","magenta" ] # this text appears in a pop-up window when users select IMLD > About # ABOUT_TEXT = "This software is intended to be used for \ educational purposes. Please direct any feedback or questions to \ help@nedcdata.org." BREAK = "===============================================" BREAK2 = "-----------------------------------------------" BASE_EXCEPT = "{}:\n{}\n" PREDICT_EXCEPT = "Failed to predict dataset due to exception" TRAIN_EXCEPT = "Failed to train model due to exception" PLOT_EXCEPT = "Failed to plot decisions surface due to exception" ERRORS_EXCEPT = "Failed to calculate errors due to exception" PASS_LOAD_PARAMS = "Sucessfully loaded parameters from {} for {}" FAIL_LOAD_PARAMS = "Unsucessfully loaded parameters from {} for {}" + \ nft.DELIM_NEWLINE + "Reverting to original parameters" PASS_SAVE_PARAMS = "Sucessfully saved parameters for {} to {}" FAIL_SAVE_PARAMS = "Unsucessfully saved parameters for {} to {}" SINGULAR_MATRIX = "Unable to perform {} with a singular covariance matrix" ALGO_HEADER = BREAK + nft.DELIM_NEWLINE + "Algorithm: {}" + nft.DELIM_NEWLINE \ + BREAK + nft.DELIM_NEWLINE IMLD_VERSION = "v3.0.0 beta" #----------------------------------------------------------------------------- # # classes are listed here # #----------------------------------------------------------------------------- class EventHandler(QtCore.QEventLoop): ''' class: EventHandler description: this class contains a variety of methods including those to prompt the user, set up for data to be plotted, and to show data in the train and eval windows of the application ''' def __init__(self): ''' method: EventHandler::constructor arguments: None return: None description: construct the EventHandler class ''' QtCore.QEventLoop.__init__(self) # create instance of the main window user interface and DataPoint # self.ui = igw.MainWindow(self) self.data_points_t = DataGenerator(self.ui.input_display) self.data_points_e = DataGenerator(self.ui.output_display) self.item_now = [None, None] self.io = idio.DataIO(self.ui) self.load_flag = False self.color_bank = [] self.saved_color = 'color' self.standard_colors = ["red","blue","yellow","black","orange", "purple","green","magenta" ] self.is_normalized = False self.trained = False self.print_cw = True # current algorithm # self.algo = None self.data = False self.initialized = False self.t_classes = [] self.classes = None # define variables for gaussian generator # self.mu = np.nan self.cov = np.nan self.points = np.nan self.params = np.nan # exit gracefully # return None # # end of method def display_warning(self, message): ''' method: EventHandler::display_warning arguments: message: a string to display to the user as an warning message return: None description: this method sends warning messages to the user in a pop-up screen ''' # instantiate QMessageBox # self.warning = QtWidgets.QMessageBox() # set title and sub text of pop-up window # self.warning.setText("Warning:") self.warning.setInformativeText(message) # set window size # self.warning.setStyleSheet("QLabel{min-width:200 px;" "min-height:30 px;}") # show window # self.warning.show() # exit gracefully # return None # # end of method def display_error(self, message): ''' method: EventHandler::display_error arguments: message: a string to display to the user as an error message return: None description: this method sends warning messages to the user in a pop-up screen ''' # instantiate QMessageBox # self.error = QtWidgets.QMessageBox() # set title and sub text of pop-up window # self.error.setText("Error:") self.error.setInformativeText(message) # set window size # self.error.setStyleSheet("QLabel{min-width:200 px; min-height:30 px;}") # show window # self.error.show() # exit gracefully # return None # # end of method def about_IMLD(self): ''' method: EventHandler::about_IMLD arguments: None return: None description: this method creates the pop-up window for the IMLD -> About menu option ''' # instantiate QMessageBox # self.dialog = QtWidgets.QMessageBox() # set title and sub text of pop-up window # self.dialog.setText( "ISIP Machine Learning Demonstration") self.dialog.setInformativeText("Version: " + IMLD_VERSION + "\n\n" + ABOUT_TEXT) self.dialog.setWindowTitle("About IMLD") # set window size # self.dialog.setStyleSheet\ ("QLabel{min-width:500 px; min-height:60 px;}") # remove "Ok" button (needs work) # button = self.dialog.defaultButton() self.dialog.removeButton(button) # show window # self.dialog.show() # exit gracefully # return None # # end of method def prompt_for_load_train(self): ''' method: EventHandler::prompt_for_load_train arguments: None return: None description: this method contains a pop-ip window for user to load data into the train window of the ui from a formatted csv file ''' try: # read in the data from the file # classes, colors, limits, self.train = self.io.load_file('train') if not classes: self.ui.process_desc.output.append( "LOAD: Selected file is incompatible") return None # if there is data in the window: # if len(self.ui.input_display.class_info) != 0: check_data = False for class_name in self.ui.input_display.class_info: if np.size\ (self.ui.input_display.class_info[class_name][1]) > 0\ and np.size\ (self.ui.input_display.class_info[class_name][2]) > 0: check_data = True if check_data: message = "Current data is replaced with the loaded data" self.display_warning(message) self.ui.input_display.clear_plot() self.ui.input_display.class_info = {} # get a list of classes # self.train_class = [] # if classes is not declared in file # if classes == []: # find classes from data/self.train # self.train_class = list(self.train.keys()) else: self.train_class = classes # check if classes from the comment doesnt match with data # if set(self.train_class) != set(list(self.train.keys())): # print out error # message = "Classes declared in the comment do not " \ + "match with data, use classes in data." self.display_warning(message) self.train_class = list(self.train.keys()) # get a dictionary of colors # train_color = {} # if color is not declared in file # if colors == []: for class_i in self.train_class: # check if color is declared in eval window # if class_i in list\ (self.ui.output_display.class_info.keys()): new_color = \ self.ui.output_display.class_info[class_i][4] else: new_color = self.preset_color() if class_i not in train_color: train_color[class_i] = [] train_color[class_i] = new_color # if color is declared # else: for idx, class_i in enumerate(self.train_class): if class_i not in train_color: train_color[class_i] = [] if (idx < len(colors)): train_color[class_i] = colors[idx] # if color declared in the comment is not enough # else: if class_i in list\ (self.ui.output_display.class_info.keys()): new_color = \ self.ui.output_display.class_info[class_i][4] else: new_color = self.preset_color() while(new_color in train_color.values()): new_color = self.preset_color() train_color[class_i] = new_color # if limits is not declared, use min and max of each coordinate # if limits == []: limits_for_all_class = [] # find min/max of x and y for each class # for class_name in self.train_class: min_x = min(self.train[class_name], key=lambda x:x[0])[0] max_x = max(self.train[class_name], key=lambda x:x[0])[0] min_y = min(self.train[class_name], key=lambda x:x[1])[1] max_y = max(self.train[class_name], key=lambda x:x[1])[1] limits_for_all_class.append([min_x, max_x, min_y, max_y]) # choose the limits based on all the classes # min_x = min(limits_for_all_class, key=lambda x:x[0])[0] max_x = max(limits_for_all_class, key=lambda x:x[1])[1] min_y = min(limits_for_all_class, key=lambda x:x[2])[2] max_y = max(limits_for_all_class, key=lambda x:x[3])[3] limits = [min_x-1, max_x+1, min_y-1, max_y+1] # set limits in training window # self.ui.input_display.x_axis = [float(limits[0]), float(limits[1])] self.ui.input_display.y_axis = [float(limits[2]), float(limits[3])] self.ui.input_display.initUI() # stores important variables (train_c holds the classes) # if self.train is not None: # set up dictionary variables to store training data # self.current_c = None train_x = np.empty((0, 0)) train_y = np.empty((0, 0)) self.once_c = False self.load_flag = True for class_name in self.train_class: train_x = np.empty((0, 0)) train_y = np.empty((0, 0)) # Add the classes to both the GUI toolbar and # the display dictionary # self.retrieve_class_parameters(class_name, train_color[class_name]) self.ui.input_display.class_info[class_name] = \ [self.current_c, train_x, train_y, self.once_c, train_color[class_name]] # get list of x coordinate from self.train at class_name # train_x = [[point[0] for point in self.train[class_name]]] # get list of y coordinate from self.train at class_name # train_y = [[point[1] for point in self.train[class_name]]] # populate the classes in the dictionary with data # # append train x coordinate to class_info # self.ui.input_display.class_info[class_name][1] = \ np.append(self.ui.input_display.class_info\ [class_name][1], train_x) # append train y coordinate to class_info # self.ui.input_display.class_info[class_name][2] = \ np.append(self.ui.input_display.class_info\ [class_name][2], train_y) # plot the training data in the Input display # self.plot_train_data() self.load_flag = False except: print("Warning: File is not loaded") # exit gracefully # return None # # end of method def prompt_for_load_eval(self): ''' method: EventHandler::prompt_for_load_eval arguments: None return: None description: this method contains a pop-ip window for user to load data into the eval window of the ui from a formatted csv file ''' try: # read in the data from the file # classes, colors, limits, self.eval= self.io.load_file('eval') # clear the window # if not classes: self.ui.process_desc.output.append( "LOAD: Selected file is incompatible") return None # if there is data in the window # if len(self.ui.output_display.class_info) != 0: check_data = False for class_name in self.ui.output_display.class_info: if np.size(self.ui.output_display.class_info\ [class_name][1]) > 0 and np.size\ (self.ui.output_display.class_info\ [class_name][2]) > 0: check_data = True if check_data: message = "Current data is replaced with the loaded data " self.display_warning(message) self.ui.output_display.clear_plot() self.ui.output_display.class_info = {} # get a list of classes # self.eval_class = [] # if classes is not declared in file # if classes == []: # find classes from data/self.eval # self.eval_class = list(self.eval.keys()) else: self.eval_class = classes # check if classes from the comment doesnt match with data # if set(self.eval_class) != set(list(self.eval.keys())): # print out error # message = "Classes declared in the comment do not " \ + "match with data, use classes in data." self.display_warning(message) self.eval_class = list(self.eval.keys()) # get a dict of color # eval_color = {} # if color is not declared in file # if colors == []: for class_i in self.eval_class: # check if color is declared in train window # if class_i in \ list(self.ui.input_display.class_info.keys()): new_color = \ self.ui.input_display.class_info[class_i][4] else: new_color = self.preset_color() if class_i not in eval_color: eval_color[class_i] = [] eval_color[class_i] = new_color # if color is declared # else: for idx, class_i in enumerate(self.eval_class): if class_i not in eval_color: eval_color[class_i] = [] if (idx < len(colors)): eval_color[class_i] = colors[idx] # if color declared in the comment is not enough # else: # check if the color is in the train window # if class_i in list\ (self.ui.input_display.class_info.keys()): new_color = \ self.ui.input_display.class_info[class_i][4] else: new_color = self.preset_color() while(new_color in eval_color.values()): new_color = self.preset_color() eval_color[class_i] = new_color # if limits is not declared, use min and max of each coordinate # if limits == []: limits_for_all_class = [] # find min/max of x and y for each class # for class_name in self.eval_class: min_x = min(self.eval[class_name], key=lambda x:x[0])[0] max_x = max(self.eval[class_name], key=lambda x:x[0])[0] min_y = min(self.eval[class_name], key=lambda x:x[1])[1] max_y = max(self.eval[class_name], key=lambda x:x[1])[1] limits_for_all_class.append([min_x, max_x, min_y, max_y]) # choose the limits based on all the classes # min_x = min(limits_for_all_class, key=lambda x:x[0])[0] max_x = max(limits_for_all_class, key=lambda x:x[1])[1] min_y = min(limits_for_all_class, key=lambda x:x[2])[2] max_y = max(limits_for_all_class, key=lambda x:x[3])[3] limits = [min_x-1, max_x+1, min_y-1, max_y+1] # set limits in eval window # self.ui.output_display.x_axis = [float(limits[0]), float(limits[1])] self.ui.output_display.y_axis = [float(limits[2]), float(limits[3])] self.ui.output_display.initUI() # stores important variables (train_c holds the classes) # if self.eval is not None: # set up dictionary variables to store training data # self.current_c = None eval_x = np.empty((0, 0)) eval_y = np.empty((0, 0)) self.once_c = False self.load_flag = True for class_name in self.eval_class: eval_x = np.empty((0, 0)) eval_y = np.empty((0, 0)) # Add the classes to both the GUI toolbar and the # display dictionary # self.retrieve_class_parameters(class_name, eval_color[class_name]) self.ui.output_display.class_info[class_name] = \ [self.current_c, eval_x, eval_y, self.once_c, eval_color[class_name]] # get list of x coordinate from self.train at class_name # eval_x = [[point[0] for point in self.eval[class_name]]] # get list of y coordinate from self.train at class_name # eval_y = [[point[1] for point in self.eval[class_name]]] # populate the classes in the dictionary with data # # append train x coordinate to class_info # self.ui.output_display.class_info[class_name][1] = \ np.append(self.ui.output_display.class_info\ [class_name][1], eval_x) # append train y coordinate to class_info # self.ui.output_display.class_info[class_name][2] = \ np.append(self.ui.output_display.class_info\ [class_name][2], eval_y) # plot the training data in the Input display # self.plot_eval_data() self.load_flag = False except: # exit gracefully # return None return None # # end of method def prompt_for_save_train(self): ''' method: EventHandler::prompt_for_save_train arguments: None return: None description: this method contains a secondary window that allows the user to save data that is currently being displayed in the train window ''' limits = [self.ui.input_display.x_axis[0], self.ui.input_display.x_axis[-1], self.ui.input_display.y_axis[0], self.ui.input_display.y_axis[-1]] self.io.save_file(self.ui.input_display.class_info, 'train', limits) # exit gracefully # return None # # end of method def prompt_for_save_eval(self): ''' method: EventHandler::prompt_for_save_eval arguments: None return: None description: this method contains a secondary window that allows the user to save data that is currently being displayed in the eval window ''' limits = [self.ui.output_display.x_axis[0], self.ui.output_display.x_axis[-1], self.ui.output_display.y_axis[0], self.ui.output_display.y_axis[-1]] self.io.save_file(self.ui.output_display.class_info, 'eval', limits) # exit gracefully # return None # # end of method def prompt_for_load_model(self): ''' method: EventHandler::prompt_for_load_model arguments: None return: None description: this method contains a secondary window that allows the user to load a previously saved, ML Tools model ''' # get the model file name from the user # fname = self.io.load_model() # if the file is invalid, do nothing and alert the user # if fname is None: self.ui.process_desc.output.append("Selected file is incompatible") # if the file is valid, load it # else: # initialize a ML Tools algorithm, resetting it if one already # exists # self.algo = ml.Alg() # load the algo into the program # if self.algo.load_model(fname): # print the algorithm name to the user # self.ui.process_desc.output.append( ALGO_HEADER.format(self.algo.get())) # initialize the model with GUI and the algorithm # self.model = model.Model(self.algo, TOTAL_NAMES, self.ui.input_display, self.ui.output_display, self.ui.process_desc, self.is_normalized) # initialize the model to the rest of the class # self.data = True self.trained = True # exit gracefully # return None # # end of method def prompt_for_save_model(self): ''' method: EventHandler::prompt_for_save_model arguments: None return: None description: this method contains a secondary window that allows the user to save the model that they are currently working on to a .pkl file ''' # if an algo has been selected # if self.algo is not None: # get the savename from the user # fname = self.io.save_model(self.algo.get()) # if the savename is valid, save the file through ML tools # if fname: self.algo.save_model(fname) # if no algo has been selected, do nothing an alert the user # else: self.ui.process_desc.output.append("There is no model to save\n") # exit gracefully # return None # # end of method def prompt_for_load_params(self): ''' method: EventHandler::prompt_for_load_params arguments: None return: None description: load parameters for a ML Tools algorithm from a formatted txt file ''' # if an algo has been selected # if self.algo is not None: # get the model file name from the user # fname = self.io.load_params() # if the file is invalid, do nothing and alert the user # if fname is None: self.ui.process_desc.output.append( "Selected file is incompatible") # if the file is valid, load it # else: # load the algo into the program, check if the parameters are # valid # if self.algo.load_parameters(fname): # print the algorithm name to the user # self.ui.process_desc.output.append( PASS_LOAD_PARAMS.format(os.path.basename(fname), self.algo.get())) # if the parameters are invalid, do nothing # else: # print the algorithm name to the user # self.ui.process_desc.output.append( FAIL_LOAD_PARAMS.format(os.path.basename(fname), self.algo.get())) # if no algo has been selected, do nothing an alert the user # else: self.ui.process_desc.output.append(\ "There is no model to save load parameters from\n") # exit gracefully # return None # # end of method def prompt_for_save_params(self): ''' method: EventHandler::prompt_for_save_params arguments: None return: None description: save the current algorithms parameters to a formatted txt file ''' # if an algo has been selected # if self.algo is not None: # get the savename from the user # fname = self.io.save_params(self.algo.get()) # if the savename is valid, save the file through ML tools # if fname: if self.algo.save_parameters(fname): # print the algorithm name to the user # self.ui.process_desc.output.append( PASS_SAVE_PARAMS.format(self.algo.get(), os.path.basename(fname))) else: self.ui.process_desc.output.append( FAIL_SAVE_PARAMS.format(self.algo.get(), os.path.basename(fname))) # if no algo has been selected, do nothing an alert the user # else: self.ui.process_desc.output.append(\ "There is no model to save load parameters from\n") # exit gracefully # return None # # end of method def plot_train_data(self): ''' method: EventLoop:plot_train_data arguments: None return: None description: this method is used to plit data that was loaded by the user with the load_train_data method ''' # iterate through the class dictionary and plot the class data # for classes in self.ui.input_display.class_info: self.ui.input_display.class_info[classes][0] = \ self.ui.input_display.canvas.axes.scatter(None, None, s=1) # set the color up for each class # self.ui.input_display.class_info[classes][0].set_color\ (self.ui.input_display.class_info[classes][4]) self.ui.input_display.class_info[classes][0].set_offsets\ (np.column_stack((self.ui.input_display.class_info\ [classes][1], self.ui.input_display.class_info\ [classes][2]))) index = self.train_class.index(classes) self.ui.input_display.class_info[classes][0].set_gid\ (np.full((1, np.shape(self.ui.input_display.class_info\ [classes][1])[0]),index)) self.ui.input_display.canvas.draw_idle() # exit gracefully # return None # # end of method def plot_eval_data(self): ''' method: EventLoop::plot_eval_data arguments: None return: None description: this methid is used to plit the data that was loaded by the user with the load_eval_data method ''' # iterate through the class dictionary # for classes in self.ui.output_display.class_info: # set up the color for each class # self.ui.output_display.class_info[classes][0] =\ self.ui.output_display.canvas.axes.scatter(None, None, s=1) self.ui.output_display.class_info[classes][0].set_color\ (self.ui.output_display.class_info[classes][4]) self.ui.output_display.class_info[classes][0].set_offsets\ (np.column_stack((self.ui.output_display.class_info\ [classes][1], self.ui.output_display.class_info [classes][2]))) index = self.eval_class.index(classes) self.ui.output_display.class_info[classes][0].set_gid \ (np.full((1, np.shape(self.ui.output_display.class_info\ [classes][1])[0]), index)) self.ui.output_display.canvas.draw_idle() # exit gracefully # return None # # end of method def retrieve_class_parameters(self,name,color=None): ''' method: EventLoop:retrieve_class_parameters arguments: name: the name of the targeted class return: None description: this method extracts the parameters from the input window that appears when a new class is being added ''' # call the global variables for class selections # global SELECTED_CLASS global TOTAL_NAMES global SELECTED_NAME global TOTAL_CLASSES # check if the name of the class is not empty, not in used Names # and does not have a Color # if len(name) != 0 and (str(name) not in TOTAL_NAMES) and \ self.ui.input_display.color_c is not False: # create the widget for the new class # classes = QtWidgets.QAction(name, checkable=True) classes.setObjectName(name) # update the global variables # TOTAL_NAMES.append(name) TOTAL_CLASSES.append(classes) SELECTED_CLASS = classes SELECTED_NAME = name # update the input and output display variables # self.ui.input_display.t_current_class = TOTAL_NAMES self.ui.output_display.t_current_class = TOTAL_NAMES self.ui.input_display.current_class = name self.ui.output_display.current_class = name self.ui.input_display.all_classes = TOTAL_CLASSES self.ui.output_display.all_classes = TOTAL_CLASSES self.ui.input_display.class_info[name] = None self.ui.output_display.class_info[name] = None # add the class widget to the menu and trigger it # self.ui.menu_bar.class_menu.addAction\ (self.ui.menu_bar.class_group.addAction(classes)) classes.triggered.connect(self.active_class_data) classes.trigger() # check if a color is chosen, if not use one from preset # if self.ui.input_display.color_c in self.color_bank or \ self.ui.input_display.color_c == None: if self.load_flag == False: col = self.preset_color() self.ui.input_display.color_c = \ self.ui.output_display.color_c = col else: if color is not None: self.color_bank.append(color) self.ui.input_display.colors_used.append(color) self.ui.output_display.colors_used.append(color) if color is None: # set up the class dictionary # self.ui.input_display.class_info[name] = \ [self.ui.input_display.current_class, self.ui.input_display.x, self.ui.input_display.y, self.ui.input_display.once_c, self.ui.input_display.color_c] self.ui.output_display.class_info[name] = \ [self.ui.output_display.current_class, self.ui.output_display.x, self.ui.output_display.y, self.ui.output_display.once_c, self.ui.output_display.color_c] d_values = list(self.ui.input_display.class_info.values()) self.color_bank = [i[-1] for i in d_values] else: self.ui.input_display.class_info[name] = \ [self.ui.input_display.current_class, self.ui.input_display.x, self.ui.input_display.y, self.ui.input_display.once_c, color] self.ui.output_display.class_info[name] = \ [self.ui.output_display.current_class, self.ui.output_display.x, self.ui.output_display.y, self.ui.output_display.once_c, color] self.ui.process_desc.output.append\ ("Classes: added class '%s'" % name) # exit gracefully # return None # # end of method def handled_color(self, name): ''' method: EventLoop::handled_color arguments: name: the name of the color return: None description: this method takes the color input and makes the newly added class that color ''' # check if the name is not color # if name != "color": # check if the color has been used # if name in self.ui.input_display.colors_used : self.ui.process_desc.output.append\ ("Choose a color that has not been picked yet") self.ui.process_desc.output.append\ ("Colors already picked" + \ str(self.ui.input_display.colors_used)) self.ui.input_display.color_c = False self.ui.output_display.color_c = False # update variables with the chosen color # else: self.saved_color = name # choose color if not chosen # else: self.ui.process_desc.output.append("Please choose a color") self.ui.input_display.color_c = False self.ui.output_display.color_c = False # exit gracefully # return None # # end of method def handled_color_saver(self): ''' method: EventLoop::handled_color_saver arguments: None return: None description: this method saves the colors of the classes ''' if self.saved_color != "color": self.ui.input_display.colors_used.append(self.saved_color) self.ui.output_display.colors_used.append(self.saved_color) self.ui.input_display.color_c = self.saved_color self.ui.output_display.color_c = self.saved_color self.saved_color = 'color' # exit gracefully # return None # # end of method def preset_color(self): ''' method: EventLoop::preset_color arguments: None return: the preset color description: this method sets up the preset color ''' # pop color from color stack and check if its in the color bank # if so keep going until a valid color is chosen # color = self.standard_colors.pop() if color in self.color_bank: col = self.preset_color() else: self.color_bank.append(color) self.ui.input_display.colors_used.append(color) self.ui.output_display.colors_used.append(color) return color # exit gracefully # return col # # end of method def reset_color(self): ''' method: EventLoop::reset_color arguments: None return: None description: this method resets the colors chosen ''' self.ui.input_display.color_c = None self.ui.output_display.color_c = None # exit gracefully # return None # # end of method def handled_surface_color(self, name): ''' method: EventLoop:handled_surface_color arguments: name: the name of the color return: None description: this method checks the surface color ''' if name not in igw.colormaps(): self.ui.input_display.surface_color = 'winter' else: self.ui.input_display.surface_color = name # exit gracefully # return None # # end of method def handled_signal(self, action): ''' method:: EventLoop:handled_signal arguments: action: the button that is being checked return: None description: this method makes the action and records its signal ''' # update current class with the triggered item # self.item_now[0]= action self.item_now[1]= action.objectName() self.ui.input_display.current_class = self.item_now[1] self.ui.output_display.current_class = self.item_now[1] # exit gracefully # return None # # end of method def remove_classes(self, all=None): ''' method: EventLoop::remove_classes arguments: all: if None, execute an action return: None description: this method removes the chosen class ''' # remove all info from chosen class # if self.ui.output_display.class_info and \ self.ui.input_display.class_info: self.ui.menu_bar.class_menu.removeAction(self.item_now[0]) self.item_now[0].deleteLater() self.ui.process_desc.output.append\ ("Classes: deleted class '%s'" % self.item_now[1]) removed_color = self.ui.input_display.class_info\ [self.item_now[1]][-1] if len(self.standard_colors) != len(STANDARD_COLORS): self.standard_colors.append(removed_color) self.color_bank.remove(removed_color) self.ui.input_display.remove_class(self.item_now[1]) self.ui.output_display.remove_class(self.item_now[1]) if all == None: self.ui.menu_bar.class_group.actions()[0].trigger() else: pass # exit gracefully # return None # # end of method def clear_input(self): ''' method: EventHandler::clear_input arguments: None return: None description: this method clears all present information visible on input plot ''' self.ui.input_display.clear_plot() # exit gracefully # return None # # end of method def clear_output(self): ''' method: EventHandler::clear_output arguments: None return: None description: this method clears all present information visible on output plot ''' self.ui.output_display.clear_plot() # exit gracefully # return None # # end of method def clear_input_result(self): ''' method: EventHandler::clear_input_result arguments: None return: None description: this method clears the results visible on input plot ''' self.ui.input_display.clear_result_plot() # exit gracefully # return None # # end of method def clear_output_result(self): ''' method: EventLoop:ckear_output_result arguments: None return: None description: this method lcears the results visible on output plot ''' self.ui.output_display.clear_result_plot() # exit gracefully # return None # # end of method def reset_window(self): ''' method: EventHandler::reset_window arguments: None return: None description: this method resets the app externally and internally ''' class_list = self.ui.menu_bar.class_group.actions() all = True for i in class_list: i.triggered.connect(lambda: self.remove_classes(all)) i.trigger() self.ui.input_display.class_info = {} self.ui.output_display.class_info = {} self.color_bank = [] self.reset_color() self.standard_colors = STANDARD_COLORS.copy() # exit gracefully # return None # # end of method def active_class_data(self): ''' method: EventHandler::active_class_data arguments: None return: None description: this method selects the active lcass when it is either added or selected from the menu ''' self.classes = True # exit gracefully # return None # # end of method def plot_two_gaus(self, window): ''' method: EventLoop:plot_two_gaus arguments: window: the input window sleected by the user (train or eval) return: None description: this method pliots the two gaussian preset pattern ''' # retrieve user submitted parameters # if window == igp.WINDOW_TRAIN: self.ui.menu_bar.clear_train_all.trigger() else: self.ui.menu_bar.clear_eval_all.trigger() self.retrieve_parameters() self.retrieve_class_parameters("Class0") self.retrieve_class_parameters("Class1") self.ui.process_desc.output.append(nft.DELIM_NEWLINE) # if user selects train option, plot in train window # if window == igp.WINDOW_TRAIN: self.data_points_t.set_two_gaussian(self.points, self.mu, self.cov) # otherwise plot in eval window # else: self.data_points_e.set_two_gaussian(self.points, self.mu, self.cov) # exit gracefully # return None # # end of method def plot_four_gaus(self, window): ''' method: EventHandler::plot_for_gauss arguments: window: the input window sleected by the user (train or eval) return: None description: this method plots the four gaussian preset pattern ''' # retrieve user submitted parameters # if window == igp.WINDOW_TRAIN: self.ui.menu_bar.clear_train_all.trigger() else: self.ui.menu_bar.clear_eval_all.trigger() self.retrieve_parameters() self.retrieve_class_parameters("Class0") self.retrieve_class_parameters("Class1") self.retrieve_class_parameters("Class2") self.retrieve_class_parameters("Class3") self.ui.process_desc.output.append(nft.DELIM_NEWLINE) # if user selects train option, plot in train window # if window == igp.WINDOW_TRAIN: self.ui.input_display.clear_plot() self.data_points_t.set_four_gaussian(self.points, self.mu, self.cov) # otherwise plot in eval window # else: self.ui.output_display.clear_plot() self.data_points_e.set_four_gaussian(self.points, self.mu, self.cov) # exit gracefully # return None # # end of method def plot_ovlp_gaussian(self, window): ''' method: EventHandler::plot_ovlp_gaus arguments: window: the inpit window selected by the user (train or eval) return: None description: this method plots the over gaussian preset pattern ''' # retrieve user submitted parameters # if window == igp.WINDOW_TRAIN: self.ui.menu_bar.clear_train_all.trigger() else: self.ui.menu_bar.clear_eval_all.trigger() self.retrieve_parameters() self.retrieve_class_parameters("Class0") self.retrieve_class_parameters("Class1") self.ui.process_desc.output.append(nft.DELIM_NEWLINE) # if user selects train option, plot in train window # if window == igp.WINDOW_TRAIN: self.ui.input_display.clear_plot() self.data_points_t.set_ovlp_gaussian(self.points, self.mu, self.cov) # otherwise plot in eval window # else: self.ui.output_display.clear_plot() self.data_points_e.set_ovlp_gaussian(self.points, self.mu, self.cov) # exit gracefully # return None # # end of method def plot_two_ellip(self, window): ''' method: EventHandler::plot_two_ellip arguments: window: the input window slected by the user (train or eval) return: None description: this method plots the two ellipse preset pattern ''' # retrieve user submitted parameters # if window == igp.WINDOW_TRAIN: self.ui.menu_bar.clear_train_all.trigger() else: self.ui.menu_bar.clear_eval_all.trigger() self.retrieve_parameters() self.retrieve_class_parameters("Class0") self.retrieve_class_parameters("Class1") self.ui.process_desc.output.append(nft.DELIM_NEWLINE) # if user selects train option, plot in train window # if window == igp.WINDOW_TRAIN: self.ui.input_display.clear_plot() self.data_points_t.set_two_ellipses(self.points, self.mu, self.cov) # otherwise, plot in eval window # else: self.ui.output_display.clear_plot() self.data_points_e.set_two_ellipses(self.points, self.mu, self.cov) # exit gracefully # return None # # end of method def plot_four_ellip(self, window): ''' method: EventHandler::plot_four_ellipse arguments: window: the input window sleected by the user (train or eval) return: None description: this method plits the four ellipse preset pattern ''' # retrieve user submitted parameters # if window == igp.WINDOW_TRAIN: self.ui.menu_bar.clear_train_all.trigger() else: self.ui.menu_bar.clear_eval_all.trigger() self.retrieve_parameters() self.retrieve_class_parameters("Class0") self.retrieve_class_parameters("Class1") self.retrieve_class_parameters("Class2") self.retrieve_class_parameters("Class3") self.ui.process_desc.output.append(nft.DELIM_NEWLINE) # if user selects train option, plot in train window # if window == igp.WINDOW_TRAIN: self.ui.input_display.clear_plot() self.data_points_t.set_four_ellipses(self.points, self.mu, self.cov) # otherwise plot in eval window # else: self.ui.output_display.clear_plot() self.data_points_e.set_four_ellipses(self.points, self.mu, self.cov) # exit gracefully # return None # # end of method def plot_rotated_ellips(self, window): ''' method: EvnetHandler::plot_rotated_ellips arguments: window: the input window slected by the user (train or eval) return: None description: this method plots the rotated ellipse preset pattern ''' # retrieve user defined parameters # if window == igp.WINDOW_TRAIN: self.ui.menu_bar.clear_train_all.trigger() else: self.ui.menu_bar.clear_eval_all.trigger() self.retrieve_parameters() self.retrieve_class_parameters("Class0") self.retrieve_class_parameters("Class1") self.ui.process_desc.output.append(nft.DELIM_NEWLINE) # if user selects train option, plot in train window # if window == igp.WINDOW_TRAIN: self.ui.input_display.clear_plot() self.data_points_t.set_rotated_ellipse(self.points, self.mu, self.cov) # otherwise plot in eval window # else: self.ui.output_display.clear_plot() self.data_points_e.set_rotated_ellipse(self.points, self.mu, self.cov) # exit gracefully # return None # # end of method def plot_toroidal(self, window): ''' method: EvnetHandler::plot_toroidal arguments: window: the input window selected by the user (train or eval) return: None description: this method plots the toroidal preset pattern ''' # retrieve user defined parameters # if window == igp.WINDOW_TRAIN: self.ui.menu_bar.clear_train_all.trigger() else: self.ui.menu_bar.clear_eval_all.trigger() self.retrieve_parameters_mod() self.retrieve_class_parameters("Class0") self.retrieve_class_parameters("Class1") self.ui.process_desc.output.append(nft.DELIM_NEWLINE) # if user selects train option, plot in train window # if window == igp.WINDOW_TRAIN: self.ui.input_display.clear_plot() self.data_points_t.set_toroidal(self.params, self.mu, self.cov) # otherwise plot in eval window # else: self.ui.output_display.clear_plot() self.data_points_e.set_toroidal(self.params, self.mu, self.cov) # exit gracefully # return None # # end of method def plot_yin_yang(self, window): ''' method: EvnetHandler::plot_ying_yang arguments: window: the input window sleected by the user (train or eval) return: None description: this method plots the ying yang preset pattern ''' # retrieve user defined parameters # if window == igp.WINDOW_TRAIN: self.ui.menu_bar.clear_train_all.trigger() else: self.ui.menu_bar.clear_eval_all.trigger() self.retrieve_parameters_mod() self.retrieve_class_parameters("Class0") self.retrieve_class_parameters("Class1") self.ui.process_desc.output.append(nft.DELIM_NEWLINE) # if user selects train option, plot in train window # if window == igp.WINDOW_TRAIN: #self.ui.input_display.clear_plot() self.data_points_t.set_yin_yang(self.params) # otherwise plot in eval window # else: #self.ui.output_display.clear_plot() self.data_points_e.set_yin_yang(self.params) # exit gracefully # return None # # end of method #------------------------------------------------------------------------------ # # show pattern methods: # These methods use the sender method to determine the signal source, call # the igp.Second class from Parameters.py to open a *second window prompting # users to input parameters with defaults in place for each class and PyQt # method show() to bring up the parameter window for the user # #------------------------------------------------------------------------------ def add_class_show(self): sender = self.sender() self.second = igp.Second(self) self.second.set_title("Add Class") self.second.add_classes(sender) self.second.show() def two_gauss_show(self): sender = self.sender() self.second = igp.Second(self) self.second.set_title("Two Gaussian (%s)" % sender.text()) self.second.two_gaussian(sender.text()) self.second.show() def four_gauss_show(self): sender = self.sender() self.second = igp.Second(self) self.second.set_title("Four Gaussian (%s)" % sender.text()) self.second.four_gaussian(sender.text()) self.second.show() def over_gauss_show(self): sender = self.sender() self.second = igp.Second(self) self.second.set_title("Over Gaussian (%s)" % sender.text()) self.second.over_gaussian(sender.text()) self.second.show() def two_ellipse_show(self): sender = self.sender() self.second = igp.Second(self) self.second.set_title("Two Ellipses (%s)" % sender.text()) self.second.two_ellipses(sender.text()) self.second.show() def four_ellipse_show(self): sender = self.sender() self.second = igp.Second(self) self.second.set_title("Four Ellipses (%s)" % sender.text()) self.second.four_ellipses(sender.text()) self.second.show() def rotated_ellipse_show(self): sender = self.sender() self.second = igp.Second(self) self.second.set_title("Rotated Ellipses (%s)" % sender.text()) self.second.rotated_ellipses(sender.text()) self.second.show() def toroidal_show(self): sender = self.sender() self.second = igp.Second(self) self.second.set_title("Toroidal (%s)" % sender.text()) self.second.toroidal(sender.text()) self.second.show() def yin_yang_show(self): sender = self.sender() self.second = igp.Second(self) self.second.set_title("Yin-Yang (%s)" % sender.text()) self.second.yin_yang(sender.text()) self.second.show() def surface_color_show(self): ''' method: EventHandler::surface_color_show arguments: None return: None description: this method calls the second window for choosing the decision surface color map ''' sender = self.sender() self.second = igp.Second(self) self.second.set_title("Pick a Surface Color Map") self.second.set_surface_color(sender) self.second.show() # exit gracefully # return None # # end of method def set_plot_ranges(self): ''' method: EventHandler::set_plot_ranges arguments: None return: None description: this method class the plot_ranges() method which brings up a secondary window to prompt the user to input ranges for the X and Y aces of the train and eval windows and then makes these changes in the ui ''' self.settings = igp.Settings(self) # bring up pop-up window to get user input # self.settings.plot_ranges() # show new axes # self.settings.show() # exit gracefully # return None # # end of method def prompt_set_gauss_prop(self): ''' method: EventHandler::prompt_set_gauss_prop arguments: None return: None description: this method calls the igp.Second.gauss_pattern() method which brings up a secondary window to prompt the user to input cov of the gaussian ''' sender = self.sender() self.second = igp.Second(self) self.second.set_title("Gaussian Pattern(%s)" % sender.text()) self.second.gauss_pattern(sender.text()) self.second.show() # exit gracefully # return None # # end of method def set_gauss_pattern(self): ''' method: EventHandler::set_guass_pattern arguments: None return: None description: this method brings up a secondary window to prompt the user to input cov of the gaussian ''' self.retrieve_parameters() # update cov in draw_gauss in both train and eval window # self.ui.input_display.cov = self.cov[0] self.ui.input_display.num_points = self.points self.ui.output_display.cov = self.cov[0] self.ui.output_display.num_points = self.points # exit gracefully # return None # # end of method def change_range(self): ''' method: EventHandler::change_range arguments: None return: None description: this method changes the ranges of the X and Y axes of the train and eval windows to the users specifications ''' ranges = np.empty((0, 0)) # number of items in layout # index = self.settings.windowLayout.count() - 1 for i in range(index): current_layout = self.settings.windowLayout.itemAt(i).layout() widget_count = current_layout.count() for widgets in range(widget_count): current_widget = current_layout.itemAt(widgets).widget() children = current_widget.findChildren(QtWidgets.QLineEdit) for params in range(len(children)): try: ranges = np.append(ranges, \ float(children[params].text())) except: ranges = np.append(ranges, np.nan) ranges = np.reshape(ranges, (2, 2, 2)) # sets range for train plot # if True not in np.isnan(ranges[0][0]): if ranges[0][0][0] > ranges[0][0][1]: ranges[0][0][0], ranges[0][0][1] = \ self.change_ranges_inverted_bound(ranges[0][0][0], ranges[0][0][1]) self.ui.input_display.canvas.axes.set_xlim(ranges[0][0]) self.ui.input_display.x_axis = np.linspace(ranges[0][0][0], ranges[0][0][1], 9) self.ui.input_display.canvas.axes.set_xticks\ (self.ui.input_display.x_axis) t_x = ranges[0][0] if True not in np.isnan(ranges[0][1]): if ranges[0][1][0] > ranges[0][1][1]: ranges[0][1][0], ranges[0][1][1] = \ self.change_ranges_inverted_bound(ranges[0][1][0], ranges[0][1][1]) self.ui.input_display.canvas.axes.set_ylim(ranges[0][1]) self.ui.input_display.y_axis = np.linspace(ranges[0][1][0], ranges[0][1][1], 9) self.ui.input_display.canvas.axes.set_yticks\ (self.ui.input_display.y_axis) t_y = ranges[0][1] # sets range for eval plot # if True not in np.isnan(ranges[1][0]): if ranges[1][0][0] > ranges[1][0][1]: ranges[1][0][0], ranges[1][0][1] = \ self.change_ranges_inverted_bound(ranges[1][0][0], ranges[1][0][1]) self.ui.output_display.canvas.axes.set_xlim(ranges[1][0]) self.ui.output_display.x_axis = np.linspace(ranges[1][0][0], ranges[1][0][1], 9) self.ui.output_display.canvas.axes.set_xticks\ (self.ui.output_display.x_axis) e_x = ranges[1][0] if True not in np.isnan(ranges[1][1]): if ranges[1][1][0] > ranges[1][1][1]: ranges[1][1][0], ranges[1][1][1] = \ self.change_ranges_inverted_bound(ranges[1][1][0], ranges[1][1][1]) self.ui.output_display.canvas.axes.set_ylim(ranges[1][1]) self.ui.output_display.y_axis = \ np.linspace(ranges[1][1][0], ranges[1][1][1], 9) self.ui.output_display.canvas.axes.set_yticks\ (self.ui.output_display.y_axis) e_y = ranges[1][1] self.ui.input_display.canvas.draw_idle() self.ui.output_display.canvas.draw_idle() # exit gracefully # return None # # end of method def change_ranges_inverted_bound(self, min, max): ''' method: EventHandler::change_ranges_inverted_bound arguments: min: the minimum bound max: the maximum bound return: min: the inverted minimum bound max: the inverted maximum bound description: this method inverts the given ranges bounds ''' temp = min min = max max = temp message = "Invalid entry: Maximum bound was less than Minimum bound " \ "\n\nBounds were reversed to keep Minimum less than Maximum" self.display_warning(message) # exit gracefully # return min, max # # end of method def initialize_algo(self): """ method: EventLoop::initialize_algo arguments: None return: None description: this function will display the algorithm parameter menu, get the parameters, then call the correct function with the right params """ # get the layouts dictionary internal data from # "Second::gen_params_window" # sender = self.sender() layouts = sender.property("layouts") abv_name = sender.property("abv_name") # initialize a parameter block to give to ML Tools # param_block = {} param_block['name'] = abv_name param_block['params'] = {} # generate the parameter block from the user selections # param_block['params']['name'] = abv_name for param, widget in layouts.items(): # check if the widget is a drop-down or a text box, and get # its value # if isinstance(widget, QtWidgets.QComboBox): param_block['params'][param] = widget.currentText() elif isinstance(widget, QtWidgets.QGroupBox): value = [] for item in widget.children(): if isinstance(item, QtWidgets.QDoubleSpinBox): value.append(item.text()) param_block['params'][param] = value else: param_block['params'][param] = widget.text() # create an encompassing ML Tools Alg class # self.algo = ml.Alg() # set the algortihm # self.algo.set(abv_name) # set the parameters for the model and options # self.algo.set_parameters(param_block) # print the algorithm name to the display # self.ui.process_desc.output.append(ALGO_HEADER.format(abv_name)) # initialize the model with GUI and the algorithm # self.model = model.Model(self.algo, TOTAL_NAMES, self.ui.input_display, self.ui.output_display, self.ui.process_desc, self.is_normalized) self.initialized = False # exit gracefully # return None # # end of method def prompt_algo(self): """ method: EventLoop::prompt_algo arguments: None return: None description: this method generates and displays the algorithm parameter window when the user selects it from the dropdown """ # get the sender signal (drop-down algo button) # sender = self.sender() # retrieve the parameters of the selected algo because they are # internal data in the sender # params = sender.data()['params'] abv_name = sender.data()['abv_name'] # create a "second" window class, which will be the window that shows # the algorithm parameters # self.second = igp.Second(self) # set the name of the parameter window as the same name as the sender # (drop-down menu button) # self.second.set_title("%s" % sender.text()) # generate the parameter window automatically with the given parameters # self.second.gen_params_window(abv_name, params) # display the parameter window # self.second.show() # exit gracefully # return None # # end of method def train_complete(self): ''' method: EventLoop::train_complete arguments: None return: None description: this function runs the model through its training phases. prepare training data -> train model -> plot training decision surface -> calculate training errors. is run when user clicks process -> train ''' # if an algorithm exists, proceed with training # if self.algo is not None: # if the training data is successfully prepared # if self.model.prepare_train(): # print a header for the start of training # self.ui.process_desc.output.append(BREAK2+\ f"\nTraining ({self.algo.get()}):") # train the model # try: self.model.process_train() self.trained = True except Exception as e: self.display_error(BASE_EXCEPT.format(TRAIN_EXCEPT, traceback.format_exc())) self.ui.process_desc.output.append(nft.DELIM_NEWLINE) return None # predict labels on the train set # try: self.model.predict_labels(model.TRAIN) except: self.display_error(BASE_EXCEPT.format(PREDICT_EXCEPT, traceback.format_exc())) self.ui.process_desc.output.append(nft.DELIM_NEWLINE) return None # plot the training decision surface # try: self.model.prepare_plot(model.TRAIN) except ValueError: self.display_error(SINGULAR_MATRIX.format(self.algo.get())) self.ui.process_desc.output.append(nft.DELIM_NEWLINE) return None except Exception as e: self.display_error(BASE_EXCEPT.format(PLOT_EXCEPT, traceback.format_exc())) self.ui.process_desc.output.append(nft.DELIM_NEWLINE) return None # calculate the training errors # try: self.model.prepare_errors(model.TRAIN, self.print_cw) except Exception as e: self.display_error(BASE_EXCEPT.format(ERRORS_EXCEPT, traceback.format_exc())) self.ui.process_desc.output.append(nft.DELIM_NEWLINE) return None # if user runs without selecting an algorithm first, # print message in the process description window # else: self.ui.process_desc.output.append(\ "Status: No algorithm is currently selected.\n") # exit gracefully # return None # # end of method def eval_complete(self): ''' method: EventHandler::eval_complete arguments: None return: None description: this method evaluates the evaluation data on the already initialized algorithm. it prepares eval data -> plots the eval decision surface -> calculate the eval errors. This method is called when the user presses Process -> Evaluate ''' # run the model until last step is triggered # if self.algo: # check if the algorithm is trained # if self.trained: # try to prepare the evaluation data # if self.model.prepare_eval(): # print a evaluation header # self.ui.process_desc.output.append(BREAK2+\ f"\nEvaluating ({self.algo.get()}):") # make predictions on the eval set # try: self.model.predict_labels(model.EVAL) except: self.display_error(BASE_EXCEPT.format(PREDICT_EXCEPT, traceback.format_exc())) self.ui.process_desc.output.append(nft.DELIM_NEWLINE) return None # plot the training decision surface # try: self.model.prepare_plot(model.EVAL) except ValueError: self.display_error(SINGULAR_MATRIX.format(self.algo.get())) self.ui.process_desc.output.append(nft.DELIM_NEWLINE) return None except Exception as e: self.display_error(BASE_EXCEPT.format(PLOT_EXCEPT, traceback.format_exc())) self.ui.process_desc.output.append(nft.DELIM_NEWLINE) return None # calculate the error of the evaluation data # try: self.model.prepare_errors(model.EVAL, self.print_cw) except: self.display_error(BASE_EXCEPT.format(ERRORS_EXCEPT, traceback.format_exc())) self.ui.process_desc.output.append(nft.DELIM_NEWLINE) return None # if eval data cannot be prepared, reset # else: pass # if the algorithm is not marked as trained, alert the user and do # nothing # else: self.ui.process_desc.output.append(\ "Algorithm is not trained. Please train before evaluating.\n") # if user runs without selecting an algorithm first, # print message in the process description window # else: self.ui.process_desc.output.append(\ "No algorithm is currently selected.\n") # exit gracefully # return None # # end of method def set_point(self): ''' method: EventHandler::set_point arguments: None return: None description: this method enables the user to draw points on the train and eval windows ''' # remove checkmark from Draw Gaussian if it's checked # self.ui.menu_bar.draw_points_menu.setChecked(True) self.ui.menu_bar.draw_gauss_menu.setChecked(False) self.ui.input_display.set_point() self.ui.output_display.set_point() # if user tries to draw before selecting a class raise an error # if self.classes == None: # define message to display to user # message = "Warning: Please select an input class." # display warning message in process description window # self.display_warning(message) # exit gracefully # return None # # end of method def set_gauss(self): ''' method: EventHandler::set_gauss arguments: None return: None description: this method enables the user to draw gaussian plots on the train and eval windows ''' # remove checkmark from Draw Points if it's checked # self.ui.menu_bar.draw_points_menu.setChecked(False) self.ui.menu_bar.draw_gauss_menu.setChecked(True) self.ui.input_display.set_gauss() self.ui.output_display.set_gauss() # if user tries to draw before selecting a class raise an error # if self.classes == None: # define message to display to user # message = "Warning: Please select an input class." # display message in process description window # self.display_warning(message) # exit gracefully # return None # # end of method def normalize_data(self): ''' method: EventHandler::normalize_data arguments: None return: None description: this method calls the process of normalize data in train and eval window ''' # if the 'Normalize Data' is checked # if self.ui.menu_bar.set_normalize_menu.isChecked(): self.is_normalized = True self.ui.process_desc.output.append("Select Normalize Data") else: self.is_normalized = True self.ui.process_desc.output.append("Unselect Normalize Data") # exit gracefully # return None # # end of method def retrieve_parameters(self): ''' method: EventHandler::retrieve_parameters arguments: None return: None description: this method extracts the parameters from the input window that appears when a pattern is selected ''' # set up mean, covariance and points variables # self.mu = np.nan self.cov = np.nan self.points = np.nan # find how many child widgets there are in the main GUI # index = self.second.windowLayout.count() - 1 # set up the mean and covariance depending on the index # mu = np.empty((index - 1, 2, 1)) * np.nan cov = np.empty((index - 1, 2, 2)) * np.nan # iterate through the child widgets to find number of inputs # for i in range(index): current_layout = self.second.windowLayout.itemAt(i).layout() if type(current_layout) == QtWidgets.QHBoxLayout: widget_count = current_layout.count() # iterate through widgets to find the extracted info # for widgets in range(widget_count): current_widget = current_layout.itemAt(widgets).widget() children = current_widget.findChildren(QtWidgets.QLineEdit) if len(children)==1: try: self.points = int(self.second.num_size.text()) continue except: try: # get number of points from Set Gaussian # self.points = int(self.second.num_points.text()) except: print("Errors: Cannot set number of points") # if there are two input boxes, try mean # if len(children) == 2: try: for extract_mu in range(len(children)): mu[i - 1][extract_mu] = \ float(children[extract_mu].text()) except: pass # 4 boxes are for covariance matrices # elif len(children) == 4: temp = np.empty((0, 0)) for extract_cov in range(len(children)): try: temp = np.append(temp,\ float(children[extract_cov].text())) except: pass try: cov[i - 1] = np.reshape(temp, (-1, 2)) except: pass self.mu = mu self.cov = cov self.mu = self.mu.reshape(len(self.mu), -1) # exit gracefully # return None # # end of method def retrieve_parameters_mod(self): ''' method: EventHandler::retrieve_parameters_tor arguments: None return: None description: this method retrieves parameters for the toroidal pattern ''' # declare local variables # self.mu = np.nan self.cov = np.nan self.points = np.nan params = np.empty([0, 0]) index = self.second.windowLayout.count() - 1 mu = np.empty((2, 1)) * np.nan cov = np.empty((2, 2)) * np.nan for i in range(index): current_layout = self.second.windowLayout.itemAt(i).layout() if type(current_layout) == QtWidgets.QHBoxLayout: widget_count = current_layout.count() for widgets in range(widget_count): current_widget = current_layout.itemAt(widgets).widget() children = current_widget.findChildren(QtWidgets.QLineEdit) # check if the paramters is not 4 for the number of points # and radius inputs # if params.size != 4: try: for extract in range(len(children)): if children[extract].text(): params = np.append(params,\ float(children[extract].text())) else: params = np.append(params, np.nan) continue except: pass if len(children) == 2: try: for extract_mu in range(len(children)): mu[extract_mu][0] = \ float(children[extract_mu].text()) except: pass elif len(children) == 4: temp = np.empty((0, 0)) for extract_cov in range(len(children)): try: temp = np.append(temp, \ float(children[extract_cov].text())) except: pass try: if temp.size == 4: cov = np.reshape(temp, (-1, 2)) else: cov = np.empty((2, 2)) * np.nan except: pass self.mu = mu self.cov = cov self.params = params # exit gracefully # return None # # end of method def set_confusion_matrix(self): ''' method: EventHandler::set_confusion_matrix arguments: None return: None description: toggle the View > "Print Confusion Matrix" option ''' self.print_cw ^= True def error_log(self): ''' method: EventHandler::error_log arguments: None return: None description: print the previous excpetion to the terminal for error logging purposes ''' print(f"ERROR:\n\n{traceback.format_exc()}\n") # exit gracefully # return None # # end of method # # end of class # # end of file