import numpy as np import pandas as pd import matplotlib # matplotlib.use("agg") import matplotlib.pyplot as plt # matplotlib.rcParams['text.usetex'] = True import directories import dbscan_ratio from dbscan_ratio import niceplot # Manage directories ########################################################### dirs = directories.directories() ################################################################################ # Import the data ############################################################## stellar_parameters = pd.read_csv( dirs.data + 'stellar_parameters_duchenekrauspopulation.csv') mask_singles = stellar_parameters['binarity'] == 0 mask_binaries = stellar_parameters['binarity'] == 1 ################################################################################ # Triggers and such ########################################################### plot_perplexity_variation = 0 plot_snr_variation = 0 plot_comparison_tsne_perplexity = 0 plot_comparison_tsne_noise = 0 plot_binaries_independent = 0 plot_histograms_stellar_parameters = 1 ################################################################################
class dbscan_method(): ratio = 0.9 iterations = 10 normalization_constant = 10 use_normalized_data = True colormap = 'plasma' # matplotlib.rcParams['text.usetex'] = True save_plots = True save_plots_dir = directories.directories().figures # DBSCAN parameters - can be overwritten from within the class min_eps = 0.1 max_eps = 0.75 min_minpts = 25 max_minpts = 125 """ Apply DBSCAN to the results from the t-SNE analysis. The iterations parameter corresponds to how many values of epsilon and min pts will be used for the exploration of the parameter space The following parameters will be added to the instance after the main algorithm is run once (names are self-explanatory): self.parameter_space self.optimized_eps self.optimized_minpts self.dbscan_labels self.recovery_ratio_optimized """ def __init__(self, tsne_x, tsne_y, real_labels, stellar_parameters, spectral_range, SNR, perplexity): self.tsne_x = tsne_x self.tsne_y = tsne_y self.real_labels = real_labels # self.min_eps = min_eps # self.max_eps = max_eps # self.min_minpts = min_minpts # self.max_minpts = max_minpts self.stellar_parameters = stellar_parameters self.spectral_ranges = spectral_range self.SNR = SNR self.perplexity = perplexity # These parameters will only be available after running the corresponding # functions, which are defined underneath self.normalized_tsne_x = [] self.normalized_tsne_y = [] def normalize_data_tSNE(self): """ Returns the t-SNE coordinates normalized between -1 and 1 times a predefined constant k. """ self.normalized_tsne_x = (2 * (self.tsne_x - np.min(self.tsne_x)) / (np.max(self.tsne_x) - np.min(self.tsne_x)) - 1) * self.normalization_constant self.normalized_tsne_y = (2 * (self.tsne_y - np.min(self.tsne_y)) / (np.max(self.tsne_y) - np.min(self.tsne_y)) - 1) * self.normalization_constant def find_binaries_ratio_dbscan(self, labels_DBSCAN): """ Find binaries from within the t-SNE maps using the ratio prescription. Input has to be a value of epsilon and minPts, possibly optimized using the function below. """ # Create the DBSCAN labels to search binaries for # Find all the unique labels found by DBSCAN unique_labelsDBSCAN = np.unique(labels_DBSCAN) # Initialize array to save the corrected labels ratioLabels = np.zeros(len(self.real_labels)) # Loop over the unique labels and compare them to the ones manually defined for DBSCANLabel in unique_labelsDBSCAN: # To avoid the points DBSCAN marked as noise if DBSCANLabel != -1: # Get the real labels corresponding to the elements of DBSCANLabel filtered_realLabels = self.real_labels[labels_DBSCAN == DBSCANLabel] # Get the indexes to save the corrected label in the corrected spot indexes_filtered_realLabels = np.argwhere( [labels_DBSCAN == DBSCANLabel])[:, 1] # Get the amount of real singles and real binaries in the filtered array filtered_singles = len( filtered_realLabels[filtered_realLabels == 0]) filtered_binaries = len( filtered_realLabels[filtered_realLabels == 1]) # Get the ratio try: ratio_ = float(filtered_binaries) / \ float((filtered_singles + filtered_binaries)) except ZeroDivisionError: pass if ratio_ >= self.ratio: # 1 as the binary label np.add.at(ratioLabels, indexes_filtered_realLabels, 1) elif filtered_singles == 0: # 1 as the binary label np.add.at(ratioLabels, indexes_filtered_realLabels, 1) elif filtered_binaries == 0: # 0 as the binary label np.add.at(ratioLabels, indexes_filtered_realLabels, 0) else: # 0 as the binary label np.add.at(ratioLabels, indexes_filtered_realLabels, 0) else: # Mark noise as singles np.add.at(ratioLabels, np.argwhere(labels_DBSCAN == -1), 0) return ratioLabels def explore_parameter_space(self): """ Find binary stars from within the t-SNE maps using DBSCAN and a predefined ratio of binaries per cluster. """ # Define the arrays to loop epsilon_explore_parameter_space = np.linspace(self.min_eps, self.max_eps, self.iterations) minpts_explore_parameter_space = np.linspace(self.min_minpts, self.max_minpts, self.iterations) # The sum of the normalized arrays must be zero if nothing has been # assigned to them, as they are initialized as empty lists. if (self.use_normalized_data == True and len(self.normalized_tsne_x) + len(self.normalized_tsne_y) == 0): # Call the function as it hadn't been called before self.normalize_data_tSNE() tSNEData_ = pd.DataFrame({ 'x': self.normalized_tsne_x, 'y': self.normalized_tsne_y }) print('Exploring DBSCAN using the normalized data...') # If the data has been normalized before, then the sum won't be zero # and the normalized data will be used directly without calling the function elif (self.use_normalized_data == True and len(self.normalized_tsne_x) + len(self.normalized_tsne_y) != 0): tSNEData_ = pd.DataFrame({ 'x': self.normalized_tsne_x, 'y': self.normalized_tsne_y }) print('Exploring DBSCAN using the normalized data...') elif self.use_normalized_data == False: tSNEData_ = pd.DataFrame({'x': self.tsne_x, 'y': self.tsne_y}) print('Exploring DBSCAN...') # Initialize the counting exploration_results = [] i = 0 # Loop over all of the possible combinations in order to obtain better statistics for epsilon in epsilon_explore_parameter_space: for min_pts in minpts_explore_parameter_space: # Calculate DBSCAN labelsDBSCAN = DBSCAN( eps=epsilon, min_samples=min_pts).fit(tSNEData_).labels_ # Get the labels from the above function ratioLabels = self.find_binaries_ratio_dbscan(labelsDBSCAN) # Need to count the amount of singles and binaries after the DBSCAN ratio method amountSingles = len(ratioLabels[ratioLabels == 0]) amountBinary = len(ratioLabels[ratioLabels == 1]) exploration_results.append( (amountSingles, amountBinary, epsilon, min_pts)) recovery = amountBinary / \ len(self.real_labels[self.real_labels == 1]) # Counter i += 1 if i % 100 == 0: print( 'Step', i, ':: current mode: epsilon %.2f and min pts %.2f' % (epsilon, min_pts)) # Convert the results into a dataframe for easier handling self.parameter_space = pd.DataFrame(exploration_results) self.parameter_space.columns = ['Singles', 'binaries', 'eps', 'minpts'] # Add the column for the recovery ratio self.parameter_space['recovery_ratio'] = self.parameter_space['binaries'] / \ len(self.real_labels[self.real_labels == 1]) # Even if this throws an error, the file saving is alrerady done try: # Prepare variables for the return self.optimized_recovery_ratio = max( self.parameter_space['recovery_ratio']) mask_optimize = self.parameter_space[ 'recovery_ratio'] == self.optimized_recovery_ratio self.optimized_eps = float( self.parameter_space['eps'][mask_optimize].values) self.optimized_minpts = float( self.parameter_space['minpts'][mask_optimize].values) print("Saving the labels for the optimized method...") self.labels_dbscan = DBSCAN( eps=self.optimized_eps, min_samples=self.optimized_minpts).fit(tSNEData_).labels_ self.ratio_labels = self.find_binaries_ratio_dbscan( self.labels_dbscan) except: print( "There was an error calcualting the optimized parameter: to be done manually" ) def get_variables_from_imported_data(self): best_dbscan_mode = self.parameter_space[ self.parameter_space['recovery_ratio'] == np.max( self.parameter_space['recovery_ratio'])] self.labels_dbscan = DBSCAN( eps=best_dbscan_mode['eps'].values[0], min_samples=best_dbscan_mode['minpts'].values[0]).fit( np.array((self.normalized_tsne_x, self.normalized_tsne_y)).T).labels_ self.ratio_labels = self.find_binaries_ratio_dbscan(self.labels_dbscan) self.optimized_eps = best_dbscan_mode['eps'].values[0] self.optimized_minpts = best_dbscan_mode['minpts'].values[0] self.optimized_recovery_ratio = best_dbscan_mode[ 'recovery_ratio'].values[0] def plot_parameter_space(self): """ Plots a 2-D map of the explore DBSCAN's parameter space. """ self.get_variables_from_imported_data() # x = eps, y = min samples x, y = np.meshgrid( np.linspace(self.min_eps, self.max_eps, self.iterations), np.linspace(self.min_minpts, self.max_minpts, self.iterations)) z = (self.parameter_space['recovery_ratio'].values).reshape(x.shape) mask_recovery = self.parameter_space['recovery_ratio'] == np.max( self.parameter_space['recovery_ratio']) fig, ax = plt.subplots(2, 2, figsize=[20, 10]) plt.suptitle( ('DBSCAN parameter space: {} iterations in {} range, perplexity' + ' {} and SNR of {}. Mode eps = {}, min pts = {} and ratio {}' ).format(self.iterations, self.spectral_ranges, self.perplexity, self.SNR, np.round(self.optimized_eps, 2), np.round(self.optimized_minpts, 3), self.ratio)) max_recovery_per_epsilon = [ np.max(z[i]) for i in range(self.iterations) ] ax[0, 0].plot(y[:, 0], max_recovery_per_epsilon, lw=1.25, alpha=0.85, c='k') ax[0, 0].set_xlabel('min pts') ax[0, 0].set_ylabel('Recovery') ax[0, 0].grid() max_recovery_per_minpts = [ np.max(z[:, i]) for i in range(self.iterations) ] ax[1, 1].plot(x[0], max_recovery_per_minpts, lw=1.25, alpha=0.85, c='k') ax[1, 1].set_xlabel('epsilon') ax[1, 1].set_ylabel('Recovery') ax[1, 1].grid() contour = ax[1, 0].contourf(y, x, z.T, 75, cmap='plasma') ax[1, 0].plot(self.optimized_minpts, self.optimized_eps, marker='x', c='k', alpha=0.85) # cbaxes = fig.add_axes([0.8, 0.1, 0.03, 0.8]) # cb = plt.colorbar(ax1, cax = cbaxes) plt.colorbar(contour, ax=ax[1, 0]) ax[1, 0].set_ylabel('epsilon') ax[1, 0].set_xlabel('min pts') fig.delaxes(ax[0, 1]) # Removes the extra plot niceplot(fig) if self.save_plots == True: plt.savefig(self.save_plots_dir + ('DBSCAN_parameter_space_range_{}_perplexity_{}' + '_SNRof{}_iterations_{}_ratio_{}.png').format( self.spectral_ranges, self.perplexity, self.SNR, self.iterations, self.ratio), dpi=150) def plot_tsne_maps(self): """ Plots a selection of the t-SNE maps, parameter file needs to be input as well. """ self.get_variables_from_imported_data() mask_noise = self.labels_dbscan == -1 mask_cluster = self.labels_dbscan != -1 mask_singles = self.real_labels == 0 mask_binaries = self.real_labels == 1 mask_recovered_binaries = self.ratio_labels == 1 mask_non_recovered_binaries = self.ratio_labels == 0 matplotlib.rcParams.update({'font.size': 18}) fig, ax = plt.subplots(2, 3, figsize=[30, 20], tight_layout=True) # plt.suptitle((r't-SNE analysis of {} single and {} binary stars' + # ', with perplexity {} in the {} spectral' + # 'range, SNR = {} and ratio {}').format(len(self.tsne_x[mask_singles]), # len(self.tsne_x[mask_binaries]), self.perplexity, # self.spectral_ranges, self.SNR, self.ratio)) ax[0, 0].set_title(r't-SNE map') ax[0, 0].scatter(self.tsne_x[mask_singles], self.tsne_y[mask_singles], c='grey', s=2, label='Single') ax[0, 0].scatter(self.tsne_x[mask_binaries], self.tsne_y[mask_binaries], c='red', s=2, label='Binary') legend1 = ax[0, 0].legend(loc='lower right') legend1.legendHandles[0]._sizes = [30] legend1.legendHandles[1]._sizes = [30] ax[0, 1].set_title((r'Recovered binary' + ' systems: {} of {}').format( len(self.tsne_x[mask_recovered_binaries]), len(self.real_labels[self.real_labels == 1]))) ax[0, 1].scatter(self.tsne_x[mask_non_recovered_binaries], self.tsne_y[mask_non_recovered_binaries], s=2, marker='.', c='grey', label='Noise') ax[0, 1].scatter(self.tsne_x[mask_recovered_binaries], self.tsne_y[mask_recovered_binaries], s=2, marker='.', c=self.ratio_labels[mask_recovered_binaries], label='DBSCAN Clusters') legend2 = ax[0, 1].legend(loc='lower right') legend2.legendHandles[0]._sizes = [30] # ax[0, 2].set_title('$L_{B} \, / \, L_{A}$') ax[0, 2].scatter(self.tsne_x[mask_singles], self.tsne_y[mask_singles], cmap=self.colormap, c='grey', s=2, label='Single') a = ax[0, 2].scatter( self.tsne_x[mask_binaries], self.tsne_y[mask_binaries], c=self.stellar_parameters['lum ratio'][mask_binaries], s=2, cmap=self.colormap, label='Single') cbar_1 = plt.colorbar(a, ax=ax[0, 2]) cbar_1.ax.set_ylabel(r'$L_{B} \, / \, L_{A}$', labelpad=20) # ax[1, 0].set_title('T$_{eff} \, \, [K]$ primary') b = ax[1, 0].scatter(self.tsne_x[mask_singles], self.tsne_y[mask_singles], c=self.stellar_parameters['teff_A'][mask_singles], cmap=self.colormap, s=2, label='Single') ax[1, 0].scatter(self.tsne_x[mask_binaries], self.tsne_y[mask_binaries], c=self.stellar_parameters['teff_A'][mask_binaries], cmap=self.colormap, s=2, label='Single') cbar_2 = plt.colorbar(b, ax=ax[1, 0]) cbar_2.ax.set_ylabel(r'T$_{eff} \, \, [K]$ primary', labelpad=20) # ax[1, 1].set_title('$log \, g \, \, [dex]$ primary') c = ax[1, 1].scatter(self.tsne_x[mask_singles], self.tsne_y[mask_singles], c=self.stellar_parameters['logg_A'][mask_singles], cmap=self.colormap, s=2, label='Single') ax[1, 1].scatter(self.tsne_x[mask_binaries], self.tsne_y[mask_binaries], c=self.stellar_parameters['logg_A'][mask_binaries], cmap=self.colormap, s=2, label='Single') cbar_3 = plt.colorbar(c, ax=ax[1, 1]) cbar_3.ax.set_ylabel(r'$log \, g \, \, [dex]$ primary', labelpad=20) # ax[1, 2].set_title('$|\Delta v _{rad}| \, \, [m/s] $') ax[1, 2].scatter(self.tsne_x[mask_singles], self.tsne_y[mask_singles], c='grey', s=2, label='Single') d = ax[1, 2].scatter(self.tsne_x[mask_binaries], self.tsne_y[mask_binaries], c=self.stellar_parameters['rad_vel'][mask_binaries], cmap=self.colormap, s=2, label='Single') cbar_4 = plt.colorbar(d, ax=ax[1, 2]) cbar_4.ax.set_ylabel(r'$|\Delta v _{rad}| \, \, [m/s] $', labelpad=20) niceplot(fig) if self.save_plots == True: plt.savefig( (self.save_plots_dir + ('tSNEmaps+DBSCAN_range_{}' + '_perplexity_{}_SNRof{}_iterations_{}_ratio_{}.png')).format( self.spectral_ranges, self.perplexity, self.SNR, self.iterations, self.ratio), dpi=200) def plot_tsne_maps_raw(self): """ Plots a selection of the t-SNE maps, parameter file needs to be input as well. """ self.get_variables_from_imported_data() mask_noise = self.labels_dbscan == -1 mask_cluster = self.labels_dbscan != -1 mask_singles = self.real_labels == 0 mask_binaries = self.real_labels == 1 mask_recovered_binaries = self.ratio_labels == 1 mask_non_recovered_binaries = self.ratio_labels == 0 print(len(self.tsne_x[mask_singles]), len(self.tsne_x[mask_binaries])) matplotlib.rcParams.update({'font.size': 18}) fig, ax = plt.subplots(1, 2, figsize=[30, 15], tight_layout=True) ax[0].scatter(self.tsne_x[mask_singles], self.tsne_y[mask_singles], c='grey', s=2, label='Single') ax[0].scatter(self.tsne_x[mask_binaries], self.tsne_y[mask_binaries], c='red', s=2, label='Binary') legend1 = ax[0].legend(loc='lower right') legend1.legendHandles[0]._sizes = [30] legend1.legendHandles[1]._sizes = [30] ax[1].set_title((r'Recovered binary' + ' systems: {} of {}').format( len(self.tsne_x[mask_recovered_binaries]), len(self.real_labels[self.real_labels == 1]))) ax[1].scatter(self.tsne_x[mask_non_recovered_binaries], self.tsne_y[mask_non_recovered_binaries], s=2, c='grey', label='Noise') ax[1].scatter(self.tsne_x[mask_recovered_binaries], self.tsne_y[mask_recovered_binaries], s=2, c=self.ratio_labels[mask_recovered_binaries], label='DBSCAN Clusters') legend2 = ax[1].legend(loc='lower right') legend2.legendHandles[0]._sizes = [30] niceplot(fig, 18) if self.save_plots == True: plt.savefig( (self.save_plots_dir + ('tSNEmaps_raw_range_{}' + '_perplexity_{}_SNRof{}_iterations_{}_ratio_{}.png')).format( self.spectral_ranges, self.perplexity, self.SNR, self.iterations, self.ratio), dpi=150) def plot_tsne_maps_stellar_parameters(self): """ Plots a selection of the t-SNE maps, parameter file needs to be input as well. """ self.get_variables_from_imported_data() mask_noise = self.labels_dbscan == -1 mask_cluster = self.labels_dbscan != -1 mask_singles = self.real_labels == 0 mask_binaries = self.real_labels == 1 mask_recovered_binaries = self.ratio_labels == 1 mask_non_recovered_binaries = self.ratio_labels == 0 matplotlib.rcParams.update({'font.size': 18}) fig, ax = plt.subplots(2, 2, figsize=[25, 20], tight_layout=True) ax[0, 0].scatter(self.tsne_x[mask_singles], self.tsne_y[mask_singles], cmap=self.colormap, c='grey', s=2, label='Single') a = ax[0, 0].scatter( self.tsne_x[mask_binaries], self.tsne_y[mask_binaries], c=self.stellar_parameters['lum ratio'][mask_binaries], s=2, cmap=self.colormap, label='Single') cbar_1 = plt.colorbar(a, ax=ax[0, 0]) cbar_1.ax.set_ylabel(r'$L_{B} \, / \, L_{A}$', labelpad=20) # ax[1, 0].set_title('T$_{eff} \, \, [K]$ primary') b = ax[1, 0].scatter(self.tsne_x[mask_singles], self.tsne_y[mask_singles], c=self.stellar_parameters['teff_A'][mask_singles], cmap=self.colormap, s=2, label='Single') ax[1, 0].scatter(self.tsne_x[mask_binaries], self.tsne_y[mask_binaries], c=self.stellar_parameters['teff_A'][mask_binaries], cmap=self.colormap, s=2, label='Single') cbar_2 = plt.colorbar(b, ax=ax[1, 0]) cbar_2.ax.set_ylabel(r'T$_{eff} \, \, [K]$ primary', labelpad=20) # ax[1, 1].set_title('$log \, g \, \, [dex]$ primary') c = ax[1, 1].scatter(self.tsne_x[mask_singles], self.tsne_y[mask_singles], c=self.stellar_parameters['logg_A'][mask_singles], cmap=self.colormap, s=2, label='Single') ax[1, 1].scatter(self.tsne_x[mask_binaries], self.tsne_y[mask_binaries], c=self.stellar_parameters['logg_A'][mask_binaries], cmap=self.colormap, s=2, label='Single') cbar_3 = plt.colorbar(c, ax=ax[1, 1]) cbar_3.ax.set_ylabel(r'$log \, g \, \, [dex]$ primary', labelpad=20) # ax[1, 2].set_title('$|\Delta v _{rad}| \, \, [m/s] $') ax[0, 1].scatter(self.tsne_x[mask_singles], self.tsne_y[mask_singles], c='grey', s=2, label='Single') d = ax[0, 1].scatter(self.tsne_x[mask_binaries], self.tsne_y[mask_binaries], c=self.stellar_parameters['rad_vel'][mask_binaries], cmap=self.colormap, s=2, label='Single') cbar_4 = plt.colorbar(d, ax=ax[0, 1]) cbar_4.ax.set_ylabel(r'$|\Delta v _{rad}| \, \, [m/s] $', labelpad=20) niceplot(fig) if self.save_plots == True: plt.savefig( (self.save_plots_dir + ('tSNEmaps_stellarparamters_range_{}' + '_perplexity_{}_SNRof{}_iterations_{}_ratio_{}.png')).format( self.spectral_ranges, self.perplexity, self.SNR, self.iterations, self.ratio), dpi=150) def plot_histograms(self): self.normalize_data_tSNE() self.get_variables_from_imported_data() retrieved_binaries = self.stellar_parameters[self.ratio_labels == 1] # Get the binaries that were not properly retrieved non_retrievedBinaries = self.stellar_parameters[ (self.stellar_parameters['binarity'] == 1) & (self.ratio_labels == 0)] all_Binaries = self.stellar_parameters[ self.stellar_parameters['binarity'] == 1] fig, ax = plt.subplots(2, 4, figsize=(30, 18)) plt.subplots_adjust(wspace=0.3, hspace=0.3) fontsize = 26 ax[0, 0].set_xlabel(r'T$_{{\mathrm{{eff}}}} \, \, [K] $ (A)', fontsize=fontsize) ax[0, 0].hist(retrieved_binaries['teff_A'], density=False, color='grey', alpha=0.5, bins=25, label='Recovered binaries') ax[0, 0].hist(non_retrievedBinaries['teff_A'], density=False, histtype='step', color='black', bins=25, label='Non-recovered binaries') ax[0, 0].hist(all_Binaries['teff_A'], density=False, histtype='step', color='blue', bins=25, label='Whole binary sample') ax[1, 0].set_xlabel(r'T$_{{\mathrm{{eff}}}} \, \, [K] $ (B)', fontsize=fontsize) ax[1, 0].hist(retrieved_binaries['teff_B'], density=False, color='grey', alpha=0.5, bins=25) ax[1, 0].hist(non_retrievedBinaries['teff_B'], density=False, histtype='step', color='black', bins=25) ax[1, 0].hist(all_Binaries['teff_B'], density=False, histtype='step', color='blue', bins=25) ax[0, 1].set_xlabel(r'[Fe / H] [dex] (A)', fontsize=fontsize) ax[0, 1].hist(retrieved_binaries['feh_A'], density=False, color='grey', alpha=0.5, bins=25) ax[0, 1].hist(non_retrievedBinaries['feh_A'], density=False, histtype='step', color='black', bins=25) ax[0, 1].hist(all_Binaries['feh_A'], density=False, histtype='step', color='blue', bins=25) ax[1, 1].set_xlabel('[Fe / H] [dex](B)', fontsize=fontsize) ax[1, 1].hist(retrieved_binaries['feh_B'], density=False, color='grey', alpha=0.5, bins=25) ax[1, 1].hist(non_retrievedBinaries['feh_B'], density=False, histtype='step', color='black', bins=25) ax[1, 1].hist(all_Binaries['feh_B'], density=False, histtype='step', color='blue', bins=25) ax[0, 2].set_xlabel('$log \, g \, \, [dex]$ (A)', fontsize=fontsize) ax[0, 2].hist(retrieved_binaries['logg_A'], density=False, color='grey', alpha=0.5, bins=25) ax[0, 2].hist(non_retrievedBinaries['logg_A'], density=False, histtype='step', color='black', bins=25) ax[0, 2].hist(all_Binaries['logg_A'], density=False, histtype='step', color='blue', bins=25) ax[1, 2].set_xlabel(r'$log \, g \, \, [dex]$ (B)', fontsize=fontsize) ax[1, 2].hist(retrieved_binaries['logg_B'], density=False, color='grey', alpha=0.5, bins=25) ax[1, 2].hist(non_retrievedBinaries['logg_B'], density=False, histtype='step', color='black', bins=25) ax[1, 2].hist(all_Binaries['logg_B'], density=False, histtype='step', color='blue', bins=25) ax[0, 3].set_xlabel(r'$L_{B} \, / \, L_{A}$', fontsize=fontsize) ax[0, 3].hist(retrieved_binaries['lum ratio'], density=False, color='grey', alpha=0.5, bins=25) ax[0, 3].hist(non_retrievedBinaries['lum ratio'], density=False, histtype='step', color='black', bins=25) ax[0, 3].hist(all_Binaries['lum ratio'], density=False, histtype='step', color='blue', bins=25) ax[1, 3].set_xlabel(r'$|\Delta v _{rad}| \, \, [km/s] $', fontsize=fontsize) ax[1, 3].hist(np.abs(retrieved_binaries['rad_vel']), color='grey', alpha=0.5, bins=25) ax[1, 3].hist(np.abs(non_retrievedBinaries['rad_vel']), density=False, histtype='step', color='black', bins=25) ax[1, 3].hist(np.abs(all_Binaries['rad_vel']), density=False, histtype='step', color='blue', bins=25) handles, labels = ax[0, 0].get_legend_handles_labels() ax[1, 2].legend(handles, labels, edgecolor='inherit', fontsize=20, loc='upper left') # plt.subplots_adjust(bottom=0.1) matplotlib.rcParams.update({'font.size': fontsize}) niceplot(fig, labelsize=fontsize, tight_layout=True) matplotlib.rcParams.update({'font.size': 26}) if self.save_plots == True: # plt.savefig(self.save_plots_dir + ('DBSCAN_histograms'+ # '_range_{}_perplexity_{}_SNRof{}_iterations_{}_ratio_{}.png').format(self.spectral_ranges, # self.perplexity, self.SNR, self.iterations, self.ratio), dpi=300) plt.savefig( ('DBSCAN_histograms' + '_range_{}_perplexity_{}_SNRof{}_iterations_{}_ratio_{}.png' ).format(self.spectral_ranges, self.perplexity, self.SNR, self.iterations, self.ratio), dpi=300)