def load_new_file_db(self, file_loc): #TODO: this should be called by init too so opening a new file_db # will load all the preferences from that file_db (like what happens in # init now #load everything if file_loc is None: return self.directory = op.expanduser(file_loc) file_db = quick_sqlite(op.join(self.directory, 'aston.sqlite')) def_group = simple_auth(file_db) read_directory(self.directory, file_db, group=def_group) self.pal_tab = PaletteTreeModel(file_db, self.ui.paletteTreeView, self) self.file_tab = FileTreeModel(file_db, self.ui.fileTreeView, self) ## add settings widget in #TODO: this will happen multiple times self.settings = SettingsWidget(self, db=file_db) self.ui.verticalLayout_settings.addWidget(self.settings)
class AstonWindow(QtWidgets.QMainWindow): state = {} def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) # my icon! icn_path = resfile('aston/qtgui', 'icons/logo.png') self.setWindowIcon(QtGui.QIcon(icn_path)) # quick fix for Mac OS menus self.ui.actionSettings.setMenuRole(QtWidgets.QAction.NoRole) # set up the list of files in the current directory fdir = get_pref('Default.FILE_DIRECTORY') self.load_new_file_db(fdir) # connect the menu logic self.ui.actionOpen.triggered.connect(self.open_folder) self.ui.actionExportChromatogram.triggered.connect( self.exportChromatogram ) self.ui.actionExportSpectra.triggered.connect(self.exportSpectrum) self.ui.actionExportSelectedItems.triggered.connect(self.exportItems) self.ui.actionIntegrate.triggered.connect(self.integrate) self.ui.actionEditFilters.triggered.connect(self.showFilterWindow) self.ui.actionRevert.triggered.connect(self.revertChromChange) self.ui.actionQuit.triggered.connect(QtWidgets.qApp.quit) self.ui.loadPeakList.triggered.connect(self.load_peaks) # hook up the windows to the menu for ac in [self.ui.actionFiles, self.ui.actionSettings, self.ui.actionSpectra, self.ui.actionMethods, self.ui.actionCompounds, self.ui.actionPalette]: ac.triggered.connect(self.updateWindows) # set up the grouping for the dock widgets and # hook the menus up to the windows for ac in [self.ui.filesDockWidget, self.ui.paletteDockWidget, self.ui.spectraDockWidget, self.ui.settingsDockWidget, self.ui.methodDockWidget, self.ui.compoundDockWidget]: if ac is not self.ui.filesDockWidget: self.tabifyDockWidget(self.ui.filesDockWidget, ac) ac.visibilityChanged.connect(self.updateWindowsMenu) self.ui.filesDockWidget.raise_() self.ui.settingsDockWidget.setVisible(False) self.ui.compoundDockWidget.setVisible(False) self.ui.methodDockWidget.setVisible(False) # create the things that keep track of how the plots should look self.plotter = Plotter(self) self.specplotter = SpecPlotter(self) # FIXME # hook up the search box # self.ui.lineEdit.textChanged.connect(self.updateSearch) # make integrator options def set_peak_find(x): self.state['peak_finder'] = x peak_find_menu = QtWidgets.QMenu(self.ui.menuChromatogram) v = list(aston.qtgui.MenuOptions.peak_finders.keys())[0] set_peak_find(v) add_opts_to_menu(peak_find_menu, aston.qtgui.MenuOptions.peak_finders.keys(), set_peak_find, v) self.ui.actionPeak_Finder.setMenu(peak_find_menu) def set_integrator(x): self.state['integrator'] = x integrator_menu = QtWidgets.QMenu(self.ui.menuChromatogram) v = list(aston.qtgui.MenuOptions.integrators.keys())[0] set_integrator(v) add_opts_to_menu(integrator_menu, aston.qtgui.MenuOptions.integrators.keys(), set_integrator, v) self.ui.actionIntegrator.setMenu(integrator_menu) menu_gp = QtWidgets.QActionGroup(self) for ac in self.ui.menuIntegrand.actions(): menu_gp.addAction(ac) ## hook up spectrum menu #for m in [self.ui.actionSpecLibDisp, self.ui.actionSpecLibLabel,\ # self.ui.actionSpecMainDisp, self.ui.actionSpecMainLabel, \ # self.ui.actionSpecPrevDisp, self.ui.actionSpecPrevLabel]: # m.triggered.connect(self.specplotter.plot) #self.ui.actionSpecMainSave.triggered.connect( \ # self.specplotter.save_main_spec) #self.ui.actionSpecPrevSave.triggered.connect( \ # self.specplotter.save_prev_spec) #flesh out the settings menu color_menu = QtWidgets.QMenu(self.ui.menuSettings) v_cs = self.settings.get_key('color_scheme', dflt='Spectral') v = aston_field_opts['color-2d'][v_cs] c_opts = list(aston_field_opts['color-2d'].values()) add_opts_to_menu(color_menu, c_opts, self.set_color_scheme, v) self.ui.actionColor_Scheme.setMenu(color_menu) self.ui.actionLegend.triggered.connect(self.set_legend) self.ui.actionGraphGrid.triggered.connect(self.set_legend) self.ui.actionGraphLogYAxis.triggered.connect(self.set_legend) #self.ui.actionGraphFxnCollection.triggered.connect(self.set_legend) #self.ui.actionGraphFIA.triggered.connect(self.set_legend) #self.ui.actionGraphIRMS.triggered.connect(self.set_legend) #self.ui.actionGraph_Peaks_Found.triggered.connect(self.set_legend) #style_menu = QtWidgets.QMenu(self.ui.menuSettings) #v_gs = self.settings.get_key('graph_style', dflt='default') #v = self.plotter._styles[v_gs] #self.plotter.setStyle(v) #add_opts_to_menu(style_menu, \ # self.plotter.availStyles(), self.set_graph_style, v) #self.ui.actionGraph_Style.setMenu(style_menu) # plot data self.plot_data() ##set up the compound database #cmpd_loc = self.settings.get_key('db_compound', dflt='') #if cmpd_loc != '': # cmpd_db = get_compound_db(cmpd_loc) # self.cmpd_tab = FileTreeModel(cmpd_db, self.ui.compoundTreeView, \ # self) def updateWindows(self): """ Update the tab windows to match the menu. """ self.ui.filesDockWidget.setVisible(self.ui.actionFiles.isChecked()) self.ui.settingsDockWidget.setVisible( self.ui.actionSettings.isChecked() ) self.ui.spectraDockWidget.setVisible(self.ui.actionSpectra.isChecked()) self.ui.methodDockWidget.setVisible(self.ui.actionMethods.isChecked()) self.ui.compoundDockWidget.setVisible( self.ui.actionCompounds.isChecked() ) self.ui.paletteDockWidget.setVisible(self.ui.actionPalette.isChecked()) def updateWindowsMenu(self): """ Update the windows menu to match the tab. """ self.ui.actionFiles.setChecked(self.ui.filesDockWidget.isVisible()) self.ui.actionSettings.setChecked( self.ui.settingsDockWidget.isVisible() ) self.ui.actionSpectra.setChecked(self.ui.spectraDockWidget.isVisible()) self.ui.actionMethods.setChecked(self.ui.methodDockWidget.isVisible()) self.ui.actionCompounds.setChecked( self.ui.compoundDockWidget.isVisible() ) self.ui.actionPalette.setChecked(self.ui.paletteDockWidget.isVisible()) def show_status(self, msg): self.statusBar().showMessage(msg, 2000) def open_folder(self): folder = str(QtWidgets.QFileDialog.getExistingDirectory(self, tr("Open Folder"))) # noqa if folder == '': return #need to discard old connections #self.ui.fileTreeView.clicked.disconnect() #self.ui.fileTreeView.selectionModel().currentChanged.disconnect() #self.ui.fileTreeView.customContextMenuRequested.disconnect() #self.ui.fileTreeView.header().customContextMenuRequested.disconnect() #self.ui.fileTreeView.header().sectionMoved.disconnect() #self.ui.paletteTreeView.clicked.disconnect() self.ui.paletteTreeView.selectionModel().currentChanged.disconnect() #self.ui.paletteTreeView.customContextMenuRequested.disconnect() #self.ui.paletteTreeView.header().customContextMenuRequested.disconnect() #self.ui.paletteTreeView.header().sectionMoved.disconnect() self.load_new_file_db(folder) def load_new_file_db(self, file_loc): #TODO: this should be called by init too so opening a new file_db # will load all the preferences from that file_db (like what happens in # init now #load everything if file_loc is None: return self.directory = op.expanduser(file_loc) file_db = quick_sqlite(op.join(self.directory, 'aston.sqlite')) def_group = simple_auth(file_db) read_directory(self.directory, file_db, group=def_group) self.pal_tab = PaletteTreeModel(file_db, self.ui.paletteTreeView, self) self.file_tab = FileTreeModel(file_db, self.ui.fileTreeView, self) ## add settings widget in #TODO: this will happen multiple times self.settings = SettingsWidget(self, db=file_db) self.ui.verticalLayout_settings.addWidget(self.settings) #self.plot_data() #cmpd_loc = file_db.get_key('db_compound', dflt='') #if cmpd_loc != '': # cmpd_db = get_compound_db(cmpd_loc) # self.cmpd_tab = FileTreeModel(cmpd_db, self.ui.compoundTreeView, \ # self) def load_peaks(self): ftypes = 'AMDIS (*.*);;Isodat (*.*)' fname = QtWidgets.QFileDialog.getOpenFileName(self, tr("Open File"), '', ftypes) if str(fname) == '': return from aston.peaks.PeakReader import read_peaks read_peaks(self.obj_tab.db, str(fname)) self.plot_data(updateBounds=False) def set_color_scheme(self): v = self.plotter.setColorScheme(self.sender().data()) self.obj_tab.db.set_key('color_scheme', v) self.plot_data(updateBounds=False) def set_legend(self): self.plotter.legend = self.ui.actionLegend.isChecked() self.plot_data(updateBounds=False) def set_graph_style(self): v = self.plotter.setStyle(self.sender().data()) self.obj_tab.db.set_key('graph_style', v) self.plot_data() def exportChromatogram(self): fopts = tr('PNG Image (*.png);;PGF Image (*.pgf);;RAW Image (*.raw);;' 'RGBA Image (*.rgba);;SVG Image (*.svg);;' 'EMF Image (*.emf);;EPS Image (*.eps);;' 'Portable Document Format (*.pdf);;' 'Postscript Image (*.ps);;Compressed SVG File (*.svgz);;' 'Comma-Delimited Text (*.csv)') fname = str(QtWidgets.QFileDialog.getSaveFileNameAndFilter( self, tr("Save As..."), filter=fopts )[0]) if fname == '': return elif fname[-4:].lower() == '.csv': dt = self.obj_tab.active_file() ts = None for ion in dt.info['traces'].split(','): if ts is None: ts = dt.trace(ion) else: ts &= dt.trace(ion) with open(fname, 'w') as f: f.write(tr('Time') + ',' + ','.join(ts.ions) + ',\n') for t, d in zip(ts.times, ts.data): f.write(str(t) + ',' + ','.join(str(i) for i in d) + '\n') else: self.plotter.plt.get_figure().savefig(fname, transparent=True) def exportSpectrum(self): # TODO: this needs to be updated when SpecPlot becomes better fopts = tr('PNG Image (*.png);;PGF Image (*.pgf);;RAW Image (*.raw);;' 'RGBA Image (*.rgba);;SVG Image (*.svg);;' 'EMF Image (*.emf);;EPS Image (*.eps);;' 'Portable Document Format (*.pdf);;' 'Postscript Image (*.ps);;Compressed SVG File (*.svgz);;' 'Comma-Delimited Text (*.csv)') fname = str(QtWidgets.QFileDialog.getSaveFileNameAndFilter( self, tr("Save As..."), filter=fopts )[0]) if fname == '': return elif fname[-4:].lower() == '.csv': if '' not in self.specplotter.scans: return with open(fname, 'w') as f: scan = self.specplotter.scans[''] f.write(tr('mz') + ',' + tr('abun') + '\n') for mz, abun in scan.T: f.write(str(mz) + ',' + str(abun) + '\n') else: self.specplotter.plt.get_figure().savefig(fname, transparent=True) def exportItems(self): #TODO: options for exporting different delimiters (e.g. tab) or #exporting select items as pictures (e.g. selected spectra) fopts = tr('Comma-Delimited Text (*.csv)') fname = str(QtWidgets.QFileDialog.getSaveFileNameAndFilter(self, \ tr("Save As..."), filter=fopts)[0]) if fname == '': return sel = self.obj_tab.returnSelFiles() with codecs.open(fname, 'w', encoding='utf-8') as f: f.write(self.obj_tab.items_as_csv(sel)) def get_f_opts(self, f): gf = lambda k, df: float(self.settings.get_key(k, dflt=str(df))) gv = lambda k, df: str(self.settings.get_key(k, dflt=str(df))) p = {} fname = f.__name__ if fname == 'simple_peak_find': p['init_slope'] = gf('peakfind_simple_initslope', 500) p['start_slope'] = gf('peakfind_simple_startslope', 500) p['end_slope'] = gf('peakfind_simple_endslope', 200) p['min_peak_height'] = gf('peakfind_simple_minheight', 50) p['max_peak_width'] = gf('peakfind_simple_maxwidth', 1.5) elif fname == 'wavelet_peak_find': p['min_snr'] = gf('peakfind_wavelet_minsnr', 1) p['assume_sig'] = gf('peakfind_wavelet_asssig', 4) elif fname == 'event_peak_find': p['adjust_times'] = gv('peakfind_event_adjust', False) elif fname == 'leastsq_integrate': p['f'] = gv('integrate_leastsq_f', 'gaussian') elif fname == 'periodic_integrate': p['offset'] = gf('integrate_periodic_offset', 0.) p['period'] = gf('integrate_periodic_period', 1.) return p def find_peaks(self, tss, plot, isomode=False, mp=False): opt = self.state['peak_finder'] pf_f = aston.qtgui.MenuOptions.peak_finders[opt] pf_fopts = self.get_f_opts(pf_f) #TODO: this should be smarter? if pf_f.__name__ == 'event_peak_find': evts = [] for n in ('fia', 'fxn', 'refgas'): evts += plot.events(n) pf_fopts['events'] = evts if isomode: return find_peaks_as_first(tss, pf_f, pf_fopts, mp) else: return find_peaks(tss, pf_f, pf_fopts, mp) def integrate_peaks(self, tss, found_peaks, isomode=False, mp=False): opt = self.state['integrator'] int_f = aston.qtgui.MenuOptions.integrators[opt] int_fopts = self.get_f_opts(int_f) return integrate_peaks(tss, found_peaks, int_f, int_fopts, isomode, mp) def integrate(self): plot = self.pal_tab.active_plot() mp = self.settings.get_key('multiprocessing', dflt=True) mp = False isomode = False if self.ui.actionIntegrandActiveTrace.isChecked(): tss = [plot.trace()] elif self.ui.actionIntegrandAsFirst.isChecked(): #plot.frame tss = plot.frame().traces isomode = True elif self.ui.actionIntegrandIndependent.isChecked(): #plot.frame tss = plot.frame().traces else: tss = [] #TODO: all traces in palette? found_peaks = self.find_peaks(tss, plot, isomode, mp) mrg_pks = self.integrate_peaks(tss, found_peaks, isomode, mp) with self.pal_tab.add_rows(plot, len(mrg_pks)): for pk in mrg_pks: pk.dbplot = plot self.pal_tab.db.add_all(mrg_pks) self.pal_tab.db.commit() self.plot_data(update_bounds=False) def showFilterWindow(self): if self.obj_tab.active_file() is not None: self.dlg = FilterWindow(self) self.dlg.show() def revertChromChange(self): """ Delete all of the info keys related to display transformations. """ for dt in self.obj_tab.returnSelFiles('file'): dt.info.del_items('t-') self.plot_data() def plot_data(self, **kwargs): plots = [] for pr in self.pal_tab._children: plots += [t for t in pr.plots if t.vis > 0 and t.is_valid] if 'update_bounds' in kwargs: self.plotter.plot_data(plots, kwargs['update_bounds']) else: self.plotter.plot_data(plots) def updateSearch(self, text): """ If the search box changes, update the file table. """ self.obj_tab.proxyMod.setFilterFixedString(text)