def create_file_options(self, frame): ''' ''' self.vertFrame = VerticalScrolledFrame(frame) self.vertFrame.grid(sticky=tk.NSEW) self.vertFrame.grid_columnconfigure(0, weight=1, minsize=200) self.vertFrame.grid_columnconfigure(3, weight=1) lab = tk.Label(self.vertFrame.interior, text='Select a folder. Txt files will be shown here ..', bg=MAC_GREY) lab.grid(sticky=tk.EW + tk.W) for n, textLabel in enumerate([ 'File Name', 'Columns', 'Columnd\nIndex', 'Concatenate\nIndex', 'Ignore', 'Settings' ]): lab = tk.Label(self.vertFrame.interior, text=textLabel, bg=MAC_GREY) lab.grid(row=1, column=n, padx=8, sticky=tk.EW) ttk.Separator(self.vertFrame.interior, orient=tk.HORIZONTAL).grid(row=1, sticky=tk.EW + tk.S, columnspan=6)
def create_setting_options(self): ''' ''' type = self.type.get() if type not in allSettings: return self.settingFrame = VerticalScrolledFrame(self.contSettings) self.settingFrame.pack(expand=True, fill=tk.BOTH) self.build_type_specific_widgets(type)
def create_widgets_for_dimRed(self): ''' ''' self.dimRed_cbs_var = dict() vertFrame = VerticalScrolledFrame(self.contClust) vertFrame.pack(expand=True, fill=tk.BOTH) for id, props in self.dimRedModelResults.items(): varCb = tk.BooleanVar(value=False) textInfo = self.dimRedModelResults[id]['data'][ 'Predictor'].get_params() columnsInDimRed = self.dimRedModelResults[id]['numericColumns'] modelName = self.dimRedModelResults[id]['name'] cb = ttk.Checkbutton(vertFrame.interior, text=modelName, variable=varCb) self.dimRed_cbs_var[id] = varCb if len(columnsInDimRed) != len(self.numericColumns): cb.configure(state=tk.DISABLED) title_ = ' == Number of selected columns/features does NOT match the\nnumber of columns/features used in model creation! == ' else: title_ = 'Dimensional Reduction Model\nMethod: {}\nColumns: {}'.format( self.dimRedModelResults[id]['method'], get_elements_from_list_as_string(columnsInDimRed)) CreateToolTip(cb, text=str(textInfo).replace("'", ''), title_=title_) cb.grid(sticky=tk.W, column=0, padx=3, pady=3) vertFrame.grid_rowconfigure(len(self.dimRedModelResults) + 1, weight=1)
def create_widgets_for_clustClasses(self): ''' ''' self.clust_cbs_var = dict() vertFrame = VerticalScrolledFrame(self.contClust) vertFrame.pack(expand=True, fill=tk.BOTH) for clustClass in self.availableClusterClasses: varCb = tk.BooleanVar(value=False) textInfo = self.clusterCollection.clusterClasses[ clustClass].get_params() infoDict = self.clusterCollection.clusterProperties[clustClass] columnsInClustClass = infoDict['numericColumns'] cb = ttk.Checkbutton(vertFrame.interior, text=clustClass, variable=varCb) self.clust_cbs_var[clustClass] = varCb if 'Spectral Clustering' in clustClass: cb.configure(state=tk.DISABLED) title_ = '== Spectral Clustering does not support predictions. ==' elif 'Agglomerative' in clustClass: cb.configure(state=tk.DISABLED) title_ = '== Agglomerative Clustering does not support predictions. ==' elif len(columnsInClustClass) != len(self.numericColumns): cb.configure(state=tk.DISABLED) title_ = ' == Number of selected columns/features does NOT match the\nnumber of columns/features used in cluster class creation! == ' else: title_ = 'Cluster settings\nColumns: {}\n\nSilhouette-Score: {}\nCalinski-Score: {}'.format( get_elements_from_list_as_string(columnsInClustClass), round(infoDict['silhouette-score'], 3), round(infoDict['calinski-score'], 2)) CreateToolTip(cb, text=str(textInfo).replace("'", ''), title_=title_) cb.grid(sticky=tk.W, column=0, padx=3, pady=3) vertFrame.grid_rowconfigure(len(self.availableClusterClasses) + 1, weight=1)
class settingsDialog(object): def __init__(self, plotter, colorHelper, dimRedCollection): self.plotter = plotter self.dimRedCollection = dimRedCollection self.colorPalettes = colorHelper.get_all_color_palettes() self.define_variables() self.build_toplevel() self.build_widgets() def close(self, event=None): ''' Close toplevel ''' self.toplevel.destroy() def build_toplevel(self): ''' Builds the toplevel to put widgets in ''' popup = tk.Toplevel(bg=MAC_GREY) popup.wm_title('Settings') popup.bind('<Escape>', self.close) popup.bind('<Tab>', self.switch_settings) popup.protocol("WM_DELETE_WINDOW", self.close) w = 450 h = 500 self.toplevel = popup self.center_popup((w, h)) def build_widgets(self): ''' Defines and grids widgets on toplevel ''' self.cont = tk.Frame(self.toplevel, background=MAC_GREY) self.cont.pack(expand=True, fill=tk.BOTH) labelTitle = tk.Label(self.cont, text='Main settings\n', **titleLabelProperties) labelType = tk.Label(self.cont, text='Type: ', bg=MAC_GREY) comboSettingType = ttk.Combobox(self.cont, textvariable=self.type, values=list(allSettings.keys())) comboSettingType.bind('<<ComboboxSelected>>', self.refresh_settings) labelTitle.grid() labelType.grid(row=1, column=0, padx=2) comboSettingType.grid(row=1, column=1, padx=2, sticky=tk.EW) ttk.Separator(self.cont, orient=tk.HORIZONTAL).grid(row=2, sticky=tk.EW, columnspan=2, pady=5) self.contSettings = tk.Frame(self.cont) self.contSettings.grid(row=5, sticky=tk.NSEW, columnspan=2, pady=5) self.cont.grid_rowconfigure(5, weight=1) self.cont.grid_columnconfigure(1, weight=1) self.create_setting_options() applyButton = ttk.Button(self.cont, text='Save & Close', command=self.change_settings) closeButton = ttk.Button(self.cont, text='Discard & Close', command=self.close) applyButton.grid(row=6, column=0, padx=5, pady=4, sticky=tk.W) closeButton.grid(row=6, column=1, padx=5, pady=4, sticky=tk.E) def create_setting_options(self): ''' ''' type = self.type.get() if type not in allSettings: return self.settingFrame = VerticalScrolledFrame(self.contSettings) self.settingFrame.pack(expand=True, fill=tk.BOTH) self.build_type_specific_widgets(type) def build_type_specific_widgets(self, type): ''' ''' self.settingsVar = dict() n = 0 for option, values in allSettings[type].items(): valueList = self.get_values(values) var = tk.StringVar() label = tk.Label(self.settingFrame.interior, text='{}: '.format(option), bg=MAC_GREY) if option in tooltipText: CreateToolTip(label, text=tooltipText[option]) combo = ttk.Combobox(self.settingFrame.interior, textvariable=var, values=valueList) var.set(self.set_default_value(option)) label.grid(row=n, column=0, sticky=tk.E) combo.grid(row=n, column=1, padx=5, sticky=tk.EW) self.settingsVar[option] = var n += 1 self.settingFrame.interior.grid_columnconfigure(1, weight=1, minsize=100) self.settingFrame.interior.grid_columnconfigure(0, weight=1, minsize=150) def refresh_settings(self, event=None): ''' ''' clear_frame(self.contSettings) self.create_setting_options() def get_values(self, option): ''' This functions checks for strings. And if there is a string (colorScheme) it will return the current set of palettes. We need to check this before, because users can add new user defined color palettes. ''' if isinstance(option, str): return self.colorPalettes else: return option def define_variables(self): ''' ''' self.type = tk.StringVar(value='Hierarchical Clustering') def set_default_value(self, option): ''' ''' if self.type.get() == 'Hierarchical Clustering': return getattr(self.plotter, attrNames[option]) elif self.type.get() == 'Dimensional Reduction': if option == 'Components': return self.dimRedCollection.nComponents elif self.type.get() == 'General Settings': if option == 'Error bar': return self.plotter.errorBar elif option == 'Arrow Style': return arrow_args['connectionstyle'] elif option == 'Aggegrate num. encoding colors': return self.plotter.aggMethod elif self.type.get() == 'Binned Scatter': if option == 'Number of bins': return self.plotter.numbBins elif option == 'Scale counts (1-0)': return str(self.plotter.scaleBinsInScatter) def change_settings(self): ''' ''' type = self.type.get() if type == 'Hierarchical Clustering': for key, var in self.settingsVar.items(): setattr(self.plotter, attrNames[key], var.get()) elif type == 'General Settings': self.error_bar_adjustment() self.adjust_agg_method() self.adjust_arrow_style() elif type == 'Dimensional Reduction': ncomps = self.get_number_from_string( self.settingsVar['Components'].get()) if ncomps is None: return elif ncomps < 3: tk.messagebox.showinfo( 'Error..', 'Minimum number of calculated components is 3. Falling back to the default = 3' ) ncomps = 3 self.dimRedCollection.set_max_comps(ncomps) elif type == 'Binned Scatter': self.binned_scatter_adjustment() self.close() def get_number_from_string(self, input, type='int', addErrorString=''): ''' ''' try: if type == 'int': out = int(float(input)) else: out = float(input) return out except: tk.messagebox.showinfo( 'Error ..', 'Could not convert input to float/integer.' + addErrorString, parent=self.toplevel) def binned_scatter_adjustment(self): ''' ''' for key, var in self.settingsVar.items(): if key == 'Number of bins': value = int(float(var.get())) elif key in ['Scale counts (1-0)', 'Color encode counts']: value = stringBool[var.get()] setattr(self.plotter, attrNames[key], value) def adjust_agg_method(self): ''' ''' input = self.settingsVar['Aggegrate num. encoding colors'].get() if input not in ['mean', 'sum']: tk.messagebox.showinfo('Error ..', 'Cannot interpret agg. method input.', parent=self.toplevel) return else: setattr(self.plotter, 'aggMethod', input) def adjust_arrow_style(self): global arrow_args input = self.settingsVar['Arrow Style'].get() if input not in arrowOptions: tk.messagebox.showinfo('Error.', 'Unknwon arrow option', parent=self.toplevel) return else: arrow_args['connectionstyle'] = input def error_bar_adjustment(self): ''' ''' input = self.settingsVar['Error bar'].get() if input in abbrError: self.plotter.errorBar = abbrError[input] else: ciValue = self.get_number_from_string( input, type='int', addErrorString= 'Valid inputs are (0-100] or any option from the drop-down menu.' ) if ciValue is None: return if ciValue <= 100: self.plotter.errorBar = ciValue def switch_settings(self, event): ''' ''' type = self.type.get() if type in allSettings: idx = list(allSettings.keys()).index(self.type.get()) if idx == len(allSettings) - 1: idx = -1 self.type.set(list(allSettings.keys())[idx + 1]) self.refresh_settings() def center_popup(self, size): ''' Casts poup and centers in screen mid ''' w_screen = self.toplevel.winfo_screenwidth() h_screen = self.toplevel.winfo_screenheight() x = w_screen / 2 - size[0] / 2 y = h_screen / 2 - size[1] / 2 self.toplevel.geometry('%dx%d+%d+%d' % (size + (x, y)))
class multipleTxtFileLoader(object): def __init__(self): self.generalLoadSettings = comboBoxToGetInputFromUser #self.define_variables() self.create_toplevel() self.create_widgets() self.toplevel.wait_window() def close(self,event=None): ''' ''' self.toplevel.destroy() def create_toplevel(self): ''' ''' self.toplevel = tk.Toplevel() self.toplevel.wm_title('Multiple file loader...') self.toplevel.protocol("WM_DELETE_WINDOW", self.close) self.toplevel.bind('<Escape>', self.close) cont = tk.Frame(self.toplevel, background =MAC_GREY) cont.pack(expand=True, fill='both') cont.grid_rowconfigure(4,weight = 1) cont.grid_columnconfigure(1,weight = 1) self.cont = cont def create_widgets(self): ''' ''' labelTitle = tk.Label(self.cont,text = 'Load multiple txt files.',**titleLabelProperties) labelTitle.grid() dirButton = ttk.Button(self.cont, text = 'Select folder', command = self.select_dir) settingButton = ttk.Button(self.cont, text = 'General Settings', command = self.get_upload_settings) fileFrame = tk.Frame(self.cont, bg = MAC_GREY) fileFrame.grid_rowconfigure(0,weight=1) fileFrame.grid_columnconfigure(0,weight=1) self.create_file_options(fileFrame) loadButton = ttk.Button(self.cont, text = 'Load', command = self.upload_files) closeButton = ttk.Button(self.cont, text = 'Close', command = self.close) dirButton.grid(row=1,column = 0, sticky = tk.W, padx = 5, pady = 2) settingButton.grid(row=1,column = 1, sticky = tk.E, padx = 5, pady = 2) fileFrame.grid(row = 4, columnspan = 2,sticky = tk.NSEW) loadButton.grid(row=5,column = 0, sticky = tk.W, padx = 5, pady = 2) closeButton.grid(row=5,column = 1, sticky = tk.E, padx = 5, pady = 2) def create_file_options(self,frame): ''' ''' self.vertFrame = VerticalScrolledFrame(frame) self.vertFrame.grid(sticky = tk.NSEW) self.vertFrame.grid_columnconfigure(0,weight=1,minsize=200) self.vertFrame.grid_columnconfigure(3,weight=1) lab = tk.Label(self.vertFrame.interior, text = 'Select a folder. Txt files will be shown here ..', bg = MAC_GREY) lab.grid(sticky = tk.EW+tk.W) for n,textLabel in enumerate(['File Name','Columns','Columnd\nIndex','Concatenate\nIndex','Ignore','Settings']): lab = tk.Label(self.vertFrame.interior, text = textLabel, bg = MAC_GREY) lab.grid(row=1, column = n, padx=8, sticky = tk.EW) ttk.Separator(self.vertFrame.interior, orient = tk.HORIZONTAL).grid(row = 1, sticky = tk.EW+tk.S,columnspan=6) def insert_files_in_frame(self,txtFiles): ''' ''' self.fileWidgets = dict() self.vars = dict() for n,file in enumerate(txtFiles): self.fileWidgets[file] = dict() lab = tk.Label(self.vertFrame.interior, text = '{} - {}'.format(n+1,file), bg = MAC_GREY) lab.grid(row = n+2, sticky = tk.EW,pady=2) columnButton = ttk.Button(self.vertFrame.interior, text = '..', width = 2) columnButton.grid(row = n+2, column = 1,pady=2, padx = 10, sticky = tk.W) ent = ttk.Entry(self.vertFrame.interior, width = 6) ent.grid(row = n+2, column = 2,pady=2, padx = 10, sticky = tk.W) ent.insert(0,'all') self.fileWidgets[file]['fileLabel'] = lab self.fileWidgets[file]['columnButton'] = columnButton self.fileWidgets[file]['columnIndex'] = ent self.fileWidgets[file]['ignore'] = tk.BooleanVar(value = False) cb = ttk.Checkbutton(self.vertFrame.interior, variable = self.fileWidgets[file]['ignore'], command = lambda file = file: self.ignore_df(file)) cb.grid(row = n+2, column = 4, pady = 2, padx = 10) ent = ttk.Entry(self.vertFrame.interior,width=2) ent.grid(row = n + 2, column = 3, padx = 10) ent.insert(0,'0') but = ttk.Button(self.vertFrame.interior, text = '..', width = 2, command = lambda file=file: self.get_upload_settings(general=False, file = file)) but.grid(row = n + 2 , column = 5, padx = 10) self.fileWidgets[file]['concatIndex'] = ent ttk.Separator(self.vertFrame.interior, orient = tk.HORIZONTAL).grid(row = n+2, sticky = tk.EW+tk.S,columnspan=6) def define_variables(self, csvFilesOnly = False): ''' ''' self.fileColumns = OrderedDict() self.loadSettings = self.adjust_setting_names( dict([k,v[0]] for k,v in self.generalLoadSettings.items())) self.collectDfs = OrderedDict() self.fileSpecificSettings = dict() self.fileSpecificUserSettings = dict() def select_dir(self): ''' ''' self.define_variables() dir = tf.askdirectory() if dir is None or dir == '': return txtFiles = self.get_txt_files(dir) if txtFiles is None: return self.insert_files_in_frame(txtFiles) self.get_file_columns(dir,txtFiles) self.dir = dir def get_upload_settings(self, general = True, file = None): ''' ''' if file in self.fileSpecificSettings: prevSettings = OrderedDict([(k,[v]) for k,v in self.fileSpecificUserSettings[file].items()]) else: prevSettings = self.generalLoadSettings dialog = simpleUserInputDialog(list(prevSettings.keys()), [x[0] for x in prevSettings.values()], list(self.generalLoadSettings.values()), 'Upload Settings', 'Settings have to be define for all files that should be uploaded.') if len(dialog.selectionOutput) == len(comboBoxToGetInputFromUser): if general: self.loadSettings = self.adjust_setting_names(dialog.selectionOutput) if len(self.fileSpecificSettings) != 0: quest = tk.messagebox.askquestion('Overwrite?', 'File specific upload paramters were given. Do you want to discard them?', parent=self.toplevel) if quest == 'yes': self.fileSpecificSettings = dict() elif file is not None and general == False: self.fileSpecificUserSettings[file] = dialog.selectionOutput.copy() self.fileSpecificSettings[file] = self.adjust_setting_names(dialog.selectionOutput) self.get_file_columns(self.dir,list(self.fileColumns.keys())) def get_txt_files(self,dir): ''' ''' files = os.listdir(dir) txtFiles = [file for file in files if file[-3:] =='txt'] csvFiles = [file for file in files if file[-3:] =='csv'] if len(csvFiles) == 0 and len(txtFiles) != 0: pass elif len(csvFiles) != 0 and len(txtFiles) != 0: tk.messagebox.showinfo('Attention ..', 'Found csv and txt files in selected dir. Carefully check the upload settings', parent = self.toplevel) elif len(csvFiles) != 0 and len(txtFiles) == 0: tk.messagebox.showinfo('Attention ..', 'Csv files detected. Please check the upload parameter.', parent=self.toplevel) txtFiles = txtFiles + csvFiles if len(txtFiles) == 0: tk.messagebox.showinfo('Error .', 'No text files found in directory.', parent = self.toplevel) return else: return txtFiles def get_settings(self,file): if file in self.fileSpecificSettings: settings = self.fileSpecificSettings[file] else: settings = self.loadSettings return settings def get_file_columns(self,dir,txtFiles): ''' Gets column headers of files. ''' for file in txtFiles: try: settings = self.get_settings(file) df = pd.read_table(os.path.join(dir,file),nrows = 1,**settings) columns = df.columns.values.tolist() except: columns = [] self.fileColumns[file] = columns self.fileWidgets[file]['columnButton'].configure(command = lambda file=file: self.custom_column_select(file)) def custom_column_select(self,file): ''' ''' dialog = simpleListboxSelection('Select columns for upload. Please note that if you want to'+ ' upload always the same column index (e.g. at the same position of each file'+ ' you can also just enter the index in the main window.', self.fileColumns[file]) selection = dialog.selection if len(selection) != 0: index = [self.fileColumns[file].index(x)+1 for x in selection] if len(index) == 1: indexStr = index[0] else: indexStr = get_elements_from_list_as_string(index, addString = '', newLine = False, maxStringLength = None) self.fileWidgets[file]['columnIndex'].delete(0,tk.END) self.fileWidgets[file]['columnIndex'].insert(0,indexStr) def ignore_df(self,file): ''' ''' for widgetID in ['columnButton','columnIndex','concatIndex']: if self.fileWidgets[file]['ignore'].get(): self.fileWidgets[file][widgetID].configure(state=tk.DISABLED) else: self.fileWidgets[file][widgetID].configure(state=tk.ACTIVE) if self.fileWidgets[file]['ignore'].get(): self.fileWidgets[file]['fileLabel'].configure(fg = 'darkgrey') else: self.fileWidgets[file]['fileLabel'].configure(fg = 'black') def upload_files(self): ''' ''' if hasattr(self,'fileWidgets') == False: tk.messagebox.showinfo('Error..','No dir selected yet',parent=self.toplevel) return pb = Progressbar('Multiple Files') txtFiles = list(self.fileColumns.keys()) dir = self.dir concatKeys = [self.fileWidgets[file]['concatIndex'].get() for file in txtFiles] concats = OrderedDict([(key,{'dfs':[],'columns':[],'files':[]}) for key in concatKeys]) for n,file in enumerate(txtFiles): if self.fileWidgets[file]['ignore'].get(): continue else: indexStr = self.fileWidgets[file]['columnIndex'].get() if indexStr != 'all': try: indexCols = [int(float(n))-1 for n in indexStr.split(',')] columns = [self.fileColumns[file][n] for n in indexCols] except: columns = self.fileColumns[file] else: columns = self.fileColumns[file] settings = self.get_settings(file) df = pd.read_table(os.path.join(dir,file),usecols = columns, **settings) concatKey = self.fileWidgets[file]['concatIndex'].get() concats[concatKey]['dfs'].append(df) concats[concatKey]['files'].append(file) concats[concatKey]['columns'].extend(['{}_{}'.format(col,n) for col in columns]) pb.update_progressbar_and_label(n/len(txtFiles) * 100, 'File {} of {} loaded.'.format(n,len(txtFiles))) for key, dfsAndColumns in concats.items(): if len(dfsAndColumns['dfs']) == 1: self.collectDfs[dfsAndColumns['files'][0]] = dfsAndColumns['dfs'][0] else: dfs = pd.concat(dfsAndColumns['dfs'], ignore_index=True, axis=1) dfs.columns = dfsAndColumns['columns'] self.collectDfs['ConcatFiles_({})'.format(len(dfsAndColumns['files']))] = dfs pb.close() self.close() def get_results(self): ''' ''' if hasattr(self,'collectDfs') : return self.collectDfs, '' ,self.naString else: return dict(),None,None def adjust_setting_names(self,settingDict): ''' ''' self.naString = settingDict['Replace NaN in Object Columns:'] settingDict = dict([(pandasInstantTranslate[k],v) for k,v in settingDict.items() if k in pandasInstantTranslate]) if settingDict['sep'] in ['tab','space']: if settingDict['sep'] == 'tab': settingDict['sep'] = '\t' else: settingDict['sep'] = '\s+' if settingDict['thousands'] == 'None': settingDict['thousands'] = None settingDict['skiprows'] = int(float(settingDict['skiprows'])) return settingDict