def custom_append(lst, item): """ # FUNCTION: custom_append(self, item) # INPUT: The list where to append and the item to append # OUTPUT: None # DESCRIPTION: This function appends an element to a list removing the elements that exceeds the maximum size # AUTHOR: Jayro Martinez Cervero """ samples_per_trial = global_variables.get_samples_per_trial() lst.append(item) if len(lst) > samples_per_trial: lst[:1] = []
def to_trials(hor, ver, lab): """ # FUNCTION: to_trials(hor, ver, lab) # INPUT: Horizontal and Vertical components of each timepoint and its label & # the number of samples per trial # OUTPUT: Horizontal and Vertical components of trial and its label # DESCRIPTION: Splits the timpoints into samples taking into account sample rate # & length of each trial. For old datasets also removes the actions # that we don't want to use in our system. After that it's doing # standarization over each sample # AUTHOR: Jayro Martinez Cervero """ samples_per_trial = global_variables.get_samples_per_trial() # Split intro trials split_indx = range(samples_per_trial, len(lab), samples_per_trial) trial_hor = np.split(hor, split_indx) trial_ver = np.split(ver, split_indx) trial_lab = np.split(lab, split_indx) # Remove 'beep' trials tri = 0 while tri < len(trial_lab): if (trial_lab[tri][0] == "'beep'"): del trial_lab[tri] del trial_ver[tri] del trial_hor[tri] else: tri += 1 # Standarize over samples for s in (range(0, len(trial_lab))): #Reduce the labels to only one trial_lab[s] = trial_lab[s][0] # STANDARIZATION OVER SAMPLES ver_mean = np.mean(trial_ver[s]) ver_sd = np.std(trial_ver[s]) hor_mean = np.mean(trial_hor[s]) hor_sd = np.std(trial_hor[s]) for t in (range(0, len(trial_ver[s]))): trial_ver[s][t] = (trial_ver[s][t] - ver_mean) / ver_sd trial_hor[s][t] = (trial_hor[s][t] - hor_mean) / hor_sd return trial_hor, trial_ver, trial_lab
def online_calculations(online_data_hor, online_data_ver): """ # FUNCTION: online_calculations(online_data_hor, online_data_ver) # INPUT: Horizontal and Vertical data # OUTPUT: None # DESCRIPTION: Performs all the desired calculations over the data # and predicts the label # AUTHOR: Jayro Martinez Cervero """ samples_per_trial = global_variables.get_samples_per_trial() lab = global_variables.get_lab() model_name = global_variables.get_model() model = pickle.load(open(model_name, 'rb')) # Pre-processing filtered_hor = filt.online_filter(online_data_hor) filtered_ver = filt.online_filter(online_data_ver) # Feature Extraction features = feat.features([filtered_hor], [filtered_ver]) # Check if there's a movement or not probs = model.predict_proba(features) lab.sort() max_pos = int(np.where(probs[0] == np.max(probs[0]))[0]) movement = lab[max_pos] print("\n********************************************") if np.max(probs) > 0.5: print(lab) print(np.max(probs)) print("MOVEMENT DETECTED: ", movement) file_name = global_variables.get_online_data_file() new_file_name = "./data/" + file_name + ".txt" file = open(new_file_name, 'a') str_write = str([online_data_hor, online_data_ver]) + "\n" file.write(str_write) file.close()
def derivative_signal(trial_hor, trial_ver, trial_lab): """ # FUNCTION: derivative_signal(trial_hor, trial_ver, trial_lab) # INPUT: Horizontal & Vertical components of each trial and its labels # OUTPUT: Lineplot # DESCRIPTION: Generate the plots for horizontal and vertical derivative # values and shows the division over samples # AUTHOR: Jayro Martinez Cervero """ der_hor = [] der_ver = [] samples_per_trial = global_variables.get_samples_per_trial() for i in range(0, len(trial_hor)): hor = [] ver = [] for j in range(0, len(trial_hor[i])): hor.append(trial_hor[i][j]) ver.append(trial_ver[i][j]) der_hor.extend(np.gradient(hor, 5)) der_ver.extend(np.gradient(ver,5)) plt.subplot(211) plt.plot(range(0, len(der_ver)),der_ver) plt.title("Ver") plt.xticks(np.arange(samples_per_trial/2,len(der_ver)+samples_per_trial/2, step=samples_per_trial),trial_lab, rotation=45, fontsize = 8) for j in range(0,len(der_ver), samples_per_trial): plt.axvline(x=j, color='tab:gray', linestyle=':') plt.subplot(212) plt.plot(range(0, len(der_hor)),der_hor) plt.title("Hor") plt.xticks(np.arange(samples_per_trial/2,len(der_hor)+samples_per_trial/2, step=samples_per_trial),trial_lab, rotation=45, fontsize = 8) for j in range(0,len(der_hor), samples_per_trial): plt.axvline(x=j, color='tab:gray', linestyle=':') plt.show()
def handle_streamed_data(sample): """ # FUNCTION: handle_streamed_data(sample) # INPUT: Sample object # OUTPUT: None # DESCRIPTION: Reads the data and saves it on a .txt file, # also plays audio files with actions when its necessary # AUTHOR: Jayro Martinez Cervero """ global online_data_hor, online_data_ver, cont cont = global_variables.get_cont() samples_per_trial = global_variables.get_samples_per_trial() evaluation_time = global_variables.get_evaluation_time() sample_rate = global_variables.get_sample_rate() lab = global_variables.get_lab() # If we are before first seconds or not exactly every half second if (cont < samples_per_trial or cont % (sample_rate * evaluation_time) != 0): custom_append(online_data_hor, sample.channel_data[1]) custom_append(online_data_ver, sample.channel_data[6]) global_variables.set_cont(cont + 1) # Every half second we evaluate the data else: new_process = Process(target=online_calculations, args=( online_data_hor, online_data_ver, )) new_process.start() custom_append(online_data_hor, sample.channel_data[1]) custom_append(online_data_ver, sample.channel_data[6]) global_variables.set_cont(cont + 1)
def trial_plot(trial_hor, trial_ver, trial_lab): """ # FUNCTION: trial_plot(trial_hor, trial_ver) # INPUT: Horizontal & Vertical components of each trial # OUTPUT: Lineplot # DESCRIPTION: Generate the plots for horizontal and vertical values and # shows the division over samples # TODO: Add labels or colors based on labels # AUTHOR: Jayro Martinez Cervero """ hor = [] ver = [] samples_per_trial = global_variables.get_samples_per_trial() for i in range(0, len(trial_hor)): for j in range(0, len(trial_hor[i])): hor.append(trial_hor[i][j]/8) ver.append(trial_ver[i][j]/8) plt.subplot(211) plt.plot(range(0, len(ver)), ver) plt.title(" Ver") plt.xticks(np.arange(250,len(ver)+250, step=samples_per_trial),trial_lab, rotation=45, fontsize = 8) plt.ylabel('mV') for j in range(0,len(ver), samples_per_trial): plt.axvline(x=j, color='tab:gray', linestyle=':') plt.subplot(212) plt.plot(range(0, len(hor)), hor) plt.title(" Hor") plt.xticks(np.arange(250,len(hor)+250, step=samples_per_trial),trial_lab, rotation=45, fontsize = 8) plt.ylabel('mV') for j in range(0,len(hor), samples_per_trial): plt.axvline(x=j, color='tab:gray', linestyle=':') plt.show()
def movement_plot(trial_hor, trial_ver, trial_lab, movement): """ # FUNCTION: movement_plot(trial_hor, trial_ver, trial_lab, movement) # INPUT: Horizontal & Vertical components of each trial, its labels # & the movement to be shown # OUTPUT: Lineplot # DESCRIPTION: Generate the plots for horizontal and vertical values and # shows the division over samples corresponding to the desired movement # AUTHOR: Jayro Martinez Cervero """ hor = [] ver = [] samples_per_trial = global_variables.get_samples_per_trial() for i in range(0, len(trial_lab)): if trial_lab[i] == movement: for j in range(0, len(trial_hor[i])): hor.append(trial_hor[i][j]/8) ver.append(trial_ver[i][j]/8) plt.subplot(211) plt.plot(range(0, len(ver)), ver) plt.title(movement+" Ver") # plt.xticks(np.arange(250,len(hor)+250, step=samples_per_trial),movement, rotation=45, fontsize = 8) plt.xticks(np.arange(0,len(hor), step=samples_per_trial),[], rotation=45, fontsize = 8) for j in range(0,len(ver), samples_per_trial): plt.axvline(x=j, color='tab:gray', linestyle=':') plt.subplot(212) plt.plot(range(0, len(hor)), hor) plt.title(movement+" Hor") # plt.xticks(np.arange(250,len(hor)+250, step=samples_per_trial),movement, rotation=45, fontsize = 8) plt.xticks(np.arange(0,len(hor), step=samples_per_trial),[], rotation=45, fontsize = 8) for j in range(0,len(hor), samples_per_trial): plt.axvline(x=j, color='tab:gray', linestyle=':') plt.show()
def handle_streamed_data(sample): """ # FUNCTION: handle_streamed_data(sample) # INPUT: Sample object # OUTPUT: None # DESCRIPTION: Reads the data and saves it on a .txt file, # also plays audio files with actions when its necessary # AUTHOR: Jayro Martinez-Cervero """ labels = global_variables.get_labels() filename = global_variables.get_save_file() samples_per_trial = global_variables.get_samples_per_trial() global iter, cont tmp_lab = labels[iter] # Open file were we are going to save the data file = open(filename, 'a') if cont == 0: # FIRST SAMPLE IN A TRIAL if tmp_lab == 'EXIT': # BLOCK FINISHED file.close() print("**********************************") print("**********************************") print("** TRAINNING BLOCK FINISHED **") print("**********************************") print("**********************************") cont = 0 iter = 0 global_variables.reset_labels() time.sleep(3) if not global_variables.get_interface(): menu() else: stop_disconnect() else: audio = AudioSegment.from_mp3("./audio/"+tmp_lab+".mp3") play(audio) if tmp_lab != 'beep': beep = AudioSegment.from_mp3("./audio/beep.mp3") play(beep) cont+=1 sample.channel_data.insert(0,tmp_lab) str_chn_dta = ' '.join([str(sample.channel_data)]) file.write(str_chn_dta) file.write('\n') elif cont < samples_per_trial-1: cont+=1 sample.channel_data.insert(0,tmp_lab) str_chn_dta = ' '.join([str(sample.channel_data)]) file.write(str_chn_dta) file.write('\n') else: # LAST SAMPLE IN A TRIAL cont = 0 iter += 1 sample.channel_data.insert(0,tmp_lab) str_chn_dta = ' '.join([str(sample.channel_data)]) file.write(str_chn_dta) file.write('\n')
model = input("\nSelect the model for classification: ") global_variables.set_model(models_list[int(model)]) os.system('clear') print("Online classification started. \nModel selected: ", global_variables.get_model(), "\n") # Online Classification online.online_classif() elif option == '0': # EXIT os.system('clear') print("###############################") print("## SEE YOU SOON!!!!!! ##") print("###############################") time.sleep(3) os.system('clear') sys.exit() else: # Wrong option print("\nYou selected a wrong option. ARE YOU KIDDING ME?") time.sleep(2) menu() if __name__ == '__main__': files_to_process = global_variables.get_files_to_process() samples_per_trial = global_variables.get_samples_per_trial() sample_rate = global_variables.get_sample_rate() menu()
def filter(): """ # FUNCTION: filter() # INPUT: None # OUTPUT: Vertical & horizontal components of the data divided by trials # and a list containing the label of each trial # DESCRIPTION: Applies a Butterworth filter and a smoothing filter over the data # in each file. Then calls to_trials() to standardize and split into trials # AUTHOR: Jayro Martinez-Cervero """ lowcut = global_variables.get_lowcut() highcut = global_variables.get_highcut() fs = global_variables.get_sample_rate() order = global_variables.get_order() samples_per_trial = global_variables.get_samples_per_trial() files = global_variables.get_files_to_process() hor_tmp = [] ver_tmp = [] labels_tmp = [] hor_file = [] ver_file = [] lab_file = [] hor_bnd = [] ver_bnd = [] hor_sm = [] ver_sm = [] # Arrays with horizontal and vertical components & labels of each sample hor = [] ver = [] lab = [] print("\nStart filtering. \n\n Cut Frequency: ", highcut, "\n Order: ", order) # Read file by file for file_name in files: hor_tmp, ver_tmp, labels_tmp = read.read_file(file_name) hor_file.extend(hor_tmp) ver_file.extend(ver_tmp) lab_file.extend(labels_tmp) # Split all data into trials & standardize over trials trial_hor, trial_ver, trial_lab = tri.to_trials(hor_file, ver_file, lab_file) # Data Padding with the sample for iter in range(0, len(trial_hor)): new_hor = np.repeat(trial_hor[iter], 3) new_ver = np.repeat(trial_ver[iter], 3) # Butterworth lowpass filter file by file sos = signal.butter(order, highcut, 'lowpass', analog=False, output='sos', fs=fs) hor_bnd = signal.sosfilt(sos, new_hor) ver_bnd = signal.sosfilt(sos, new_ver) #Removing Data Padding hor_bnd = hor_bnd[len(trial_hor[iter]):len(hor_bnd) - len(trial_hor[iter])] ver_bnd = ver_bnd[len(trial_ver[iter]):len(ver_bnd) - len(trial_ver[iter])] # Smoothing filter file by file hor_sm = signal.medfilt(hor_bnd, kernel_size=35) ver_sm = signal.medfilt(ver_bnd, kernel_size=35) # Concatenate the results into ver and hor variables & labels hor.append(hor_sm) ver.append(ver_sm) lab = trial_lab return hor, ver, lab
def derivative_plots(trial_hor, trial_ver, trial_lab): """ # FUNCTION: derivative_plots(trial_hor, trial_ver, trial_lab) # INPUT: Horizontal & Vertical components of each trial and its labels # OUTPUT: Multiple dot plots # DESCRIPTION: Generate the plots for horizontal and vertical derivative features # AUTHOR: Jayro Martinez Cervero """ up_hor_amp = [] up_ver_amp = [] up_hor_min = [] up_ver_min = [] up_hor_max = [] up_ver_max = [] up_hor_median = [] up_ver_median = [] up_hor_sum = [] up_ver_sum = [] up_tot_sum = [] down_hor_amp = [] down_ver_amp = [] down_hor_min = [] down_ver_min = [] down_hor_max = [] down_ver_max = [] down_hor_median = [] down_ver_median = [] down_hor_sum = [] down_ver_sum = [] down_tot_sum = [] left_hor_amp = [] left_ver_amp = [] left_hor_min = [] left_ver_min = [] left_hor_max = [] left_ver_max = [] left_hor_median = [] left_ver_median = [] left_hor_sum = [] left_ver_sum = [] left_tot_sum = [] right_hor_amp = [] right_ver_amp = [] right_hor_min = [] right_ver_min = [] right_hor_max = [] right_ver_max = [] right_hor_median = [] right_ver_median = [] right_hor_sum = [] right_ver_sum = [] right_tot_sum = [] none_hor_amp = [] none_ver_amp = [] none_hor_min = [] none_ver_min = [] none_hor_max = [] none_ver_max = [] none_hor_median = [] none_ver_median = [] none_hor_sum = [] none_ver_sum = [] none_tot_sum = [] blink_hor_amp = [] blink_ver_amp = [] blink_hor_min = [] blink_ver_min = [] blink_hor_max = [] blink_ver_max = [] blink_hor_median = [] blink_ver_median = [] blink_hor_sum = [] blink_ver_sum = [] blink_tot_sum = [] close_hor_amp = [] close_ver_amp = [] close_hor_min = [] close_ver_min = [] close_hor_max = [] close_ver_max = [] close_hor_median = [] close_ver_median = [] close_hor_sum = [] close_ver_sum = [] close_tot_sum = [] der_hor = [] der_ver = [] amp_hor = [] amp_ver = [] sum_hor = [] sum_ver = [] amp_up = [] amp_down = [] amp_left = [] amp_right = [] amp_none = [] amp_blink = [] amp_close = [] for i in range(0, len(trial_hor)): hor = [] ver = [] for j in range(0, len(trial_hor[i])): hor.append(trial_hor[i][j]) ver.append(trial_ver[i][j]) der_hor.extend(np.gradient(hor,5)) der_ver.extend(np.gradient(ver,5)) samples_per_trial = global_variables.get_samples_per_trial() split_indx = range(samples_per_trial, len(der_hor), samples_per_trial) der_hor = np.split(der_hor, split_indx) der_ver = np.split(der_ver, split_indx) for j in range(0, len(trial_hor)): amp_hor.append(np.max(der_hor[j]) - np.min(der_hor[j])) amp_ver.append(np.max(der_ver[j]) - np.min(der_ver[j])) sum_hor.append(sum(abs(der_hor[j]))) sum_ver.append(sum(abs(der_ver[j]))) for iter in range(0, len(trial_lab)): if trial_lab[iter] == "'Up'": up_hor_amp.append(amp_hor[iter]) up_ver_amp.append(amp_ver[iter]) up_hor_min.append(np.min(der_hor[iter])) up_ver_min.append(np.min(der_ver[iter])) up_hor_max.append(np.max(der_hor[iter])) up_ver_max.append(np.max(der_ver[iter])) up_hor_median.append(np.median(der_hor[iter])) up_ver_median.append(np.median(der_ver[iter])) amp_up.append(amp_hor[iter]+amp_ver[iter]) up_hor_sum.append(sum_hor[iter]) up_ver_sum.append(sum_ver[iter]) up_tot_sum.append(sum_hor[iter]+sum_ver[iter]) elif trial_lab[iter] == "'Down'": down_hor_amp.append(amp_hor[iter]) down_ver_amp.append(amp_ver[iter]) down_hor_min.append(np.min(der_hor[iter])) down_ver_min.append(np.min(der_ver[iter])) down_hor_max.append(np.max(der_hor[iter])) down_ver_max.append(np.max(der_ver[iter])) down_hor_median.append(np.median(der_hor[iter])) down_ver_median.append(np.median(der_ver[iter])) amp_down.append(amp_hor[iter]+amp_ver[iter]) down_hor_sum.append(sum_hor[iter]) down_ver_sum.append(sum_ver[iter]) down_tot_sum.append(sum_hor[iter]+sum_ver[iter]) elif trial_lab[iter] == "'Left'": left_hor_amp.append(amp_hor[iter]) left_ver_amp.append(amp_ver[iter]) left_hor_min.append(np.min(der_hor[iter])) left_ver_min.append(np.min(der_ver[iter])) left_hor_max.append(np.max(der_hor[iter])) left_ver_max.append(np.max(der_ver[iter])) left_hor_median.append(np.median(der_hor[iter])) left_ver_median.append(np.median(der_ver[iter])) amp_left.append(amp_hor[iter]+amp_ver[iter]) left_hor_sum.append(sum_hor[iter]) left_ver_sum.append(sum_ver[iter]) left_tot_sum.append(sum_hor[iter]+sum_ver[iter]) elif trial_lab[iter] == "'Right'": right_hor_amp.append(amp_hor[iter]) right_ver_amp.append(amp_ver[iter]) right_hor_min.append(np.min(der_hor[iter])) right_ver_min.append(np.min(der_ver[iter])) right_hor_max.append(np.max(der_hor[iter])) right_ver_max.append(np.max(der_ver[iter])) right_hor_median.append(np.median(der_hor[iter])) right_ver_median.append(np.median(der_ver[iter])) amp_right.append(amp_hor[iter]+amp_ver[iter]) right_hor_sum.append(sum_hor[iter]) right_ver_sum.append(sum_ver[iter]) right_tot_sum.append(sum_hor[iter]+sum_ver[iter]) elif trial_lab[iter] == "'None'" or trial_lab[iter] == "'No_Movement'": none_hor_amp.append(amp_hor[iter]) none_ver_amp.append(amp_ver[iter]) none_hor_min.append(np.min(der_hor[iter])) none_ver_min.append(np.min(der_ver[iter])) none_hor_max.append(np.max(der_hor[iter])) none_ver_max.append(np.max(der_ver[iter])) none_hor_median.append(np.median(der_hor[iter])) none_ver_median.append(np.median(der_ver[iter])) amp_none.append(amp_hor[iter]+amp_ver[iter]) none_hor_sum.append(sum_hor[iter]) none_ver_sum.append(sum_ver[iter]) none_tot_sum.append(sum_hor[iter]+sum_ver[iter]) elif trial_lab[iter] == "'Blink'": blink_hor_amp.append(amp_hor[iter]) blink_ver_amp.append(amp_ver[iter]) blink_hor_min.append(np.min(der_hor[iter])) blink_ver_min.append(np.min(der_ver[iter])) blink_hor_max.append(np.max(der_hor[iter])) blink_ver_max.append(np.max(der_ver[iter])) blink_hor_median.append(np.median(der_hor[iter])) blink_ver_median.append(np.median(der_ver[iter])) amp_blink.append(amp_hor[iter]+amp_ver[iter]) blink_hor_sum.append(sum_hor[iter]) blink_ver_sum.append(sum_ver[iter]) blink_tot_sum.append(sum_hor[iter]+sum_ver[iter]) elif trial_lab[iter] == "'Close_Eyes'": close_hor_amp.append(amp_hor[iter]) close_ver_amp.append(amp_ver[iter]) close_hor_min.append(np.min(der_hor[iter])) close_ver_min.append(np.min(der_ver[iter])) close_hor_max.append(np.max(der_hor[iter])) close_ver_max.append(np.max(der_ver[iter])) close_hor_median.append(np.median(der_hor[iter])) close_ver_median.append(np.median(der_ver[iter])) amp_close.append(amp_hor[iter]+amp_ver[iter]) close_hor_sum.append(sum_hor[iter]) close_ver_sum.append(sum_ver[iter]) close_tot_sum.append(sum_hor[iter]+sum_ver[iter]) data_hor = [up_hor_amp, down_hor_amp, left_hor_amp, right_hor_amp, none_hor_amp, blink_hor_amp, close_hor_amp] data_ver = [up_ver_amp, down_ver_amp, left_ver_amp, right_ver_amp, none_ver_amp, blink_ver_amp, close_ver_amp] data_total = [amp_up, amp_down, amp_left, amp_right, amp_none, amp_blink, amp_close] data_hor_sum = [up_hor_sum, down_hor_sum, left_hor_sum, right_hor_sum, none_hor_sum, blink_hor_sum, close_hor_sum] data_ver_sum = [up_ver_sum, down_ver_sum, left_ver_sum, right_ver_sum, none_ver_sum, blink_ver_sum, close_ver_sum] data_tot_sum = [up_tot_sum, down_tot_sum, left_tot_sum, right_tot_sum, none_tot_sum, blink_tot_sum, close_tot_sum] plot_labels = ["Up", "Down", "Left", "Right", "None", "Blink", "Closed"] plt.figure(1) ax = plt.gca() ticks = ax.get_xticklabels() ax.boxplot(data_hor) ax.set_xticklabels(plot_labels, rotation = 45, fontsize = 8) ax.set_title("Horizontal Derivative Amplitude") plt.figure(2) ax = plt.gca() ticks = ax.get_xticklabels() ax.boxplot(data_ver) ax.set_xticklabels(plot_labels, rotation = 45, fontsize = 8) ax.set_title("Vertical Derivative Amplitude") plt.figure(3) ax = plt.gca() ticks = ax.get_xticklabels() ax.boxplot(data_total) ax.set_xticklabels(plot_labels, rotation = 45, fontsize = 8) ax.set_title("Total (Hor+Ver) Derivative Amplitude") plt.figure(4) ax = plt.gca() ticks = ax.get_xticklabels() ax.boxplot(data_hor_sum) ax.set_xticklabels(plot_labels, rotation = 45, fontsize = 8) ax.set_title("Derivative Horizontal Sum") plt.figure(5) ax = plt.gca() ticks = ax.get_xticklabels() ax.boxplot(data_ver_sum) ax.set_xticklabels(plot_labels, rotation = 45, fontsize = 8) ax.set_title("Derivative Vertical Sum") plt.figure(6) ax = plt.gca() ticks = ax.get_xticklabels() ax.boxplot(data_tot_sum) ax.set_xticklabels(plot_labels, rotation = 45, fontsize = 8) ax.set_title("Derivative Vertical+Horizontal Sum") fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.scatter(up_hor_min, up_hor_max, up_hor_amp, color='r', label='Up') ax.scatter(down_hor_min, down_hor_max, down_hor_amp, color='r', label='Down') ax.scatter(left_hor_min, left_hor_max, left_hor_amp, color='g', label='Left') ax.scatter(right_hor_min, right_hor_max, right_hor_amp, color='g', label='Right') ax.scatter(none_hor_min, none_hor_max, none_hor_amp, color='k', label='No Movement') ax.scatter(blink_hor_min, blink_hor_max, blink_hor_amp, color='c', label='Blink') ax.scatter(close_hor_min, close_hor_max, close_hor_amp, color='w', label='Closed') ax.set_xlabel('Derivative Min') ax.set_ylabel('Derivative Max') ax.set_zlabel('Derivative Amplitude') leg = ax.legend(loc='lower left') ax.set_title("Horizontal") fig2 = plt.figure() ax2 = fig2.add_subplot(111, projection='3d') ax2.scatter(up_ver_min, up_ver_max, up_ver_amp, color='g', label='Up') ax2.scatter(down_ver_min, down_ver_max, down_ver_amp, color='g', label='Down') ax2.scatter(left_ver_min, left_ver_max, left_ver_amp, color='r', label='Left') ax2.scatter(right_ver_min, right_ver_max, right_ver_amp, color='r', label='Right') ax2.scatter(none_ver_min, none_ver_max, none_ver_amp, color='k', label='No Movement') ax2.scatter(blink_ver_min, blink_ver_max, blink_ver_amp, color='c', label='Blink') ax2.scatter(close_ver_min, close_ver_max, close_ver_amp, color='w', label='Closed') ax2.set_xlabel('Derivative Min') ax2.set_ylabel('Derivative Max') ax2.set_zlabel('Derivative Amplitude') leg2 = ax2.legend(loc='lower left') ax2.set_title("Vertical") plt.show()