From f58d17be1415bcfca10820118ec60cb7b7512d1f Mon Sep 17 00:00:00 2001 From: Marcel Paffrath Date: Thu, 11 May 2017 17:15:20 +0200 Subject: [PATCH 01/12] WIP restructuring fig_dict to be created inside Qt Main Thread --- QtPyLoT.py | 51 ++++++++++++++++++-- autoPyLoT.py | 4 +- pylot/RELEASE-VERSION | 2 +- pylot/core/pick/autopick.py | 78 +++++++++++++++---------------- pylot/core/pick/picker.py | 26 +++++++---- pylot/core/pick/utils.py | 9 ++-- pylot/core/util/map_projection.py | 46 +++++++++--------- pylot/core/util/widgets.py | 29 ++++++++---- 8 files changed, 156 insertions(+), 89 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 5b0db609..8561a1df 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -41,6 +41,13 @@ from PySide.QtGui import QMainWindow, QInputDialog, QIcon, QFileDialog, \ import numpy as np from obspy import UTCDateTime +try: + from matplotlib.backends.backend_qt4agg import FigureCanvas +except ImportError: + from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas +from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar +from matplotlib.figure import Figure + from pylot.core.analysis.magnitude import RichterMagnitude, MomentMagnitude from pylot.core.io.data import Data from pylot.core.io.inputs import FilterOptions, AutoPickParameter @@ -59,7 +66,7 @@ from pylot.core.util.utils import fnConstructor, getLogin, \ from pylot.core.io.location import create_creation_info, create_event from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \ WaveformWidget, PropertiesDlg, HelpForm, createAction, PickDlg, \ - getDataType, ComparisonDialog + getDataType, ComparisonDialog, TuneAutopicker from pylot.core.util.map_projection import map_projection from pylot.core.util.structure import DATASTRUCTURE from pylot.core.util.thread import AutoPickThread, Thread @@ -90,6 +97,7 @@ class MainWindow(QMainWindow): self._inputs = AutoPickParameter(infile) self.project = Project() + self.tap = None self.array_map = None self._metadata = None self._eventChanged = [False, False] @@ -416,9 +424,9 @@ class MainWindow(QMainWindow): self.addActions(componentToolBar, componentActions) self.auto_pick = self.createAction(parent=self, text='autoPick', - slot=self.autoPick, shortcut='Alt+Ctrl+A', - icon=auto_icon, tip='Automatically pick' - ' the displayed waveforms.') + slot=self.tune_autopicker, shortcut='Alt+Ctrl+A', + icon=auto_icon, tip='Tune autopicking algorithm.') + self.auto_pick.setEnabled(False) autoPickToolBar = self.addToolBar("autoPyLoT") @@ -1141,6 +1149,26 @@ class MainWindow(QMainWindow): self.listWidget.addItem(text) self.listWidget.scrollToBottom() + def tune_autopicker(self): + self.fig_dict = { + 'mainFig':, + 'aicFig':, + 'slength':, + 'checkZ4s':, + 'refPpick':, + 'el_Ppick':, + 'fm_picker':, + 'el_S1pick':, + 'el_S2pick':, + 'refSpick':, + 'aicARHfig', + } + + ap = self._inputs + if not self.tap: + self.tap = TuneAutopicker(ap, self.fig_dict, self) + self.tap.show() + def autoPick(self): self.autosave = QFileDialog().getExistingDirectory(caption='Select autoPyLoT output') if not os.path.exists(self.autosave): @@ -1354,10 +1382,25 @@ class MainWindow(QMainWindow): self.get_metadata() if not self.metadata: return + self.am_figure = Figure() + self.am_canvas = FigureCanvas(self.am_figure) + self.am_toolbar = NavigationToolbar(self.am_canvas, self) self.array_map = map_projection(self) + #self.array_map_thread() self.array_layout.addWidget(self.array_map) self.tabs.setCurrentIndex(index) self.refresh_array_map() + + def array_map_thread(self): + self.amt = Thread(self, self.array_map.init_map, arg=None, progressText='Generating map...') + self.amt.finished.connect(self.finish_array_map) + self.amt.start() + + def finish_array_map(self): + self.array_map = self.amt.data + self.array_layout.addWidget(self.array_map) + #self.tabs.setCurrentIndex(index) + #self.refresh_array_map() def refresh_array_map(self): if not self.array_map: diff --git a/autoPyLoT.py b/autoPyLoT.py index f4192f5c..de8d00bf 100755 --- a/autoPyLoT.py +++ b/autoPyLoT.py @@ -29,7 +29,7 @@ from pylot.core.util.version import get_git_version as _getVersionString __version__ = _getVersionString() -def autoPyLoT(parameter=None, inputfile=None, fnames=None, savepath=None, iplot=0): +def autoPyLoT(parameter=None, inputfile=None, fnames=None, savepath=None, iplot=0, fig_dict=None): """ Determine phase onsets automatically utilizing the automatic picking algorithms by Kueperkoch et al. 2010/2012. @@ -166,7 +166,7 @@ def autoPyLoT(parameter=None, inputfile=None, fnames=None, savepath=None, iplot= print(data) ########################################################## # !automated picking starts here! - picks, mainFig = autopickevent(wfdat, parameter, iplot=iplot) + picks, mainFig = autopickevent(wfdat, parameter, iplot=iplot, fig_dict=fig_dict) ########################################################## # locating if locflag == 1: diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index 5c1a3758..a2a47e0c 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -dc65-dirty +d135-dirty diff --git a/pylot/core/pick/autopick.py b/pylot/core/pick/autopick.py index 1acc7871..a9b6ad1f 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -21,10 +21,9 @@ from pylot.core.util.utils import getPatternLine, gen_Pool from pylot.core.io.data import Data -def autopickevent(data, param, iplot=0): +def autopickevent(data, param, iplot=0, fig_dict=None): stations = [] all_onsets = {} - fig_dict = {} input_tuples = [] # get some parameters for quality control from @@ -45,22 +44,22 @@ def autopickevent(data, param, iplot=0): if not iplot: input_tuples.append((topick, param, apverbose)) if iplot>0: - all_onsets[station], fig_dict[station] = autopickstation(topick, param, verbose=apverbose, iplot=iplot) + all_onsets[station] = autopickstation(topick, param, verbose=apverbose, iplot=iplot, fig_dict=fig_dict) if iplot>0: print('iPlot Flag active: NO MULTIPROCESSING possible.') - return all_onsets, fig_dict # changing structure of autopicking and figure generation MP MP + return all_onsets pool = gen_Pool() result = pool.map(call_autopickstation, input_tuples) pool.close() - for pick, fig_dict in result: + for pick in result: station = pick['station'] pick.pop('station') all_onsets[station] = pick - return all_onsets, fig_dict # changing structure of autopicking and figure generation MP MP + return all_onsets # quality control # median check and jackknife on P-onset times @@ -172,8 +171,6 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): Ao = None # Wood-Anderson peak-to-peak amplitude picker = 'auto' # type of picks - fig_dict = {} - # split components zdat = wfstream.select(component="Z") if len(zdat) == 0: # check for other components @@ -235,9 +232,8 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): ############################################################## # get prelimenary onset time from AIC-HOS-CF using subclass AICPicker # of class AutoPicking - aicpick = AICPicker(aiccf, tsnrz, pickwinP, iplot, None, tsmoothP) key = 'aicFig' - fig_dict[key] = aicpick.fig + aicpick = AICPicker(aiccf, tsnrz, pickwinP, iplot, None, tsmoothP, fig_dict[key]) ############################################################## if aicpick.getpick() is not None: # check signal length to detect spuriously picked noise peaks @@ -252,9 +248,10 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): '{1}'.format(minsiglength, minsiglength / 2) if verbose: print(msg) key = 'slength' - Pflag, fig_dict[key] = checksignallength(zne, aicpick.getpick(), tsnrz, - minsiglength / 2, - nfacsl, minpercent, iplot) + Pflag = checksignallength(zne, aicpick.getpick(), tsnrz, + minsiglength / 2, + nfacsl, minpercent, iplot, + fig_dict[key]) else: # filter and taper horizontal traces trH1_filt = edat.copy() @@ -270,9 +267,10 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): zne += trH1_filt zne += trH2_filt key = 'slenght' - Pflag, fig_dict[key] = checksignallength(zne, aicpick.getpick(), tsnrz, - minsiglength, - nfacsl, minpercent, iplot) + Pflag = checksignallength(zne, aicpick.getpick(), tsnrz, + minsiglength, + nfacsl, minpercent, iplot, + fig_dict[key]) if Pflag == 1: # check for spuriously picked S onset @@ -284,8 +282,8 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): else: if iplot>1: key = 'checkZ4S' - Pflag, fig_dict[key] = checkZ4S(zne, aicpick.getpick(), zfac, - tsnrz[3], iplot) + Pflag = checkZ4S(zne, aicpick.getpick(), zfac, + tsnrz[3], iplot, fig_dict[key]) if Pflag == 0: Pmarker = 'SinsteadP' Pweight = 9 @@ -332,10 +330,9 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): 'correctly: maybe the algorithm name ({algoP}) is ' \ 'corrupted'.format( algoP=algoP) - refPpick = PragPicker(cf2, tsnrz, pickwinP, iplot, ausP, tsmoothP, - aicpick.getpick()) key = 'refPpick' - fig_dict[key] = refPpick.fig + refPpick = PragPicker(cf2, tsnrz, pickwinP, iplot, ausP, tsmoothP, + aicpick.getpick(), fig_dict[key]) mpickP = refPpick.getpick() ############################################################# if mpickP is not None: @@ -343,8 +340,8 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): # get earliest/latest possible pick and symmetrized uncertainty if iplot: key = 'el_Ppick' - epickP, lpickP, Perror, fig_dict[key] = earllatepicker(z_copy, nfacP, tsnrz, - mpickP, iplot) + epickP, lpickP, Perror = earllatepicker(z_copy, nfacP, tsnrz, + mpickP, iplot, fig_dict[key]) else: epickP, lpickP, Perror = earllatepicker(z_copy, nfacP, tsnrz, mpickP, iplot) @@ -370,7 +367,7 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): if Pweight <= minfmweight and SNRP >= minFMSNR: if iplot: key = 'fm_picker' - FM, fig_dict[key] = fmpicker(zdat, z_copy, fmpickwin, mpickP, iplot) + FM = fmpicker(zdat, z_copy, fmpickwin, mpickP, iplot, fig_dict[key]) else: FM = fmpicker(zdat, z_copy, fmpickwin, mpickP, iplot) else: @@ -471,10 +468,9 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): ############################################################## # get prelimenary onset time from AIC-HOS-CF using subclass AICPicker # of class AutoPicking - aicarhpick = AICPicker(haiccf, tsnrh, pickwinS, iplot, None, - aictsmoothS) key = 'aicARHfig' - fig_dict[key] = aicarhpick.fig + aicarhpick = AICPicker(haiccf, tsnrh, pickwinS, iplot, None, + aictsmoothS, fig_dict[key]) ############################################################### # go on with processing if AIC onset passes quality control if (aicarhpick.getSlope() >= minAICSslope and @@ -528,10 +524,9 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): addnoise) # instance of ARHcf # get refined onset time from CF2 using class Picker - refSpick = PragPicker(arhcf2, tsnrh, pickwinS, iplot, ausS, - tsmoothS, aicarhpick.getpick()) key = 'refSpick' - fig_dict[key] = refSpick.fig + refSpick = PragPicker(arhcf2, tsnrh, pickwinS, iplot, ausS, + tsmoothS, aicarhpick.getpick(), fig_dict[key]) mpickS = refSpick.getpick() ############################################################# if mpickS is not None: @@ -540,9 +535,10 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): h_copy[0].data = trH1_filt.data if iplot: key = 'el_S1pick' - epickS1, lpickS1, Serror1, fig_dict[key] = earllatepicker(h_copy, nfacS, - tsnrh, - mpickS, iplot) + epickS1, lpickS1, Serror1 = earllatepicker(h_copy, nfacS, + tsnrh, + mpickS, iplot, + fig_dict[key]) else: epickS1, lpickS1, Serror1 = earllatepicker(h_copy, nfacS, tsnrh, @@ -551,9 +547,10 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): h_copy[0].data = trH2_filt.data if iplot: key = 'el_S2pick' - epickS2, lpickS2, Serror2, fig_dict[key] = earllatepicker(h_copy, nfacS, - tsnrh, - mpickS, iplot) + epickS2, lpickS2, Serror2 = earllatepicker(h_copy, nfacS, + tsnrh, + mpickS, iplot, + fig_dict[key]) else: epickS2, lpickS2, Serror2 = earllatepicker(h_copy, nfacS, tsnrh, @@ -649,7 +646,10 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): ############################################################## if iplot > 0: # plot vertical trace - fig = plt.figure() + if not fig_dict: + fig = plt.figure() + else: + fig = fig_dict['mainFig'] ax1 = fig.add_subplot(311) tdata = np.arange(0, zdat[0].stats.npts / tr_filt.stats.sampling_rate, tr_filt.stats.delta) @@ -792,8 +792,6 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): ax3.set_xlabel('Time [s] after %s' % tr_filt.stats.starttime) ax3.set_ylabel('Normalized Counts') ax3.set_title(trH2_filt.stats.channel) - key = 'mainFig' - fig_dict[key] = fig ########################################################################## # calculate "real" onset times if lpickP is not None and lpickP == mpickP: @@ -840,7 +838,7 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): snrdb=SNRSdB, weight=Sweight, fm=None, picker=picker, Ao=Ao) # merge picks into returning dictionary picks = dict(P=ppick, S=spick, station=zdat[0].stats.station) - return picks, fig_dict + return picks def iteratepicker(wf, NLLocfile, picks, badpicks, pickparameter): diff --git a/pylot/core/pick/picker.py b/pylot/core/pick/picker.py index 663f8da1..c1d0d2a6 100644 --- a/pylot/core/pick/picker.py +++ b/pylot/core/pick/picker.py @@ -34,7 +34,7 @@ class AutoPicker(object): warnings.simplefilter('ignore') - def __init__(self, cf, TSNR, PickWindow, iplot=None, aus=None, Tsmooth=None, Pick1=None): + def __init__(self, cf, TSNR, PickWindow, iplot=None, aus=None, Tsmooth=None, Pick1=None, fig=None): ''' :param: cf, characteristic function, on which the picking algorithm is applied :type: `~pylot.core.pick.CharFuns.CharacteristicFunction` object @@ -72,7 +72,7 @@ class AutoPicker(object): self.setaus(aus) self.setTsmooth(Tsmooth) self.setpick1(Pick1) - self.fig = self.calcPick() + self.fig = fig def __str__(self): return '''\n\t{name} object:\n @@ -152,7 +152,6 @@ class AICPicker(AutoPicker): self.Pick = None self.slope = None self.SNR = None - fig = None # find NaN's nn = np.isnan(self.cf) if len(nn) > 1: @@ -227,7 +226,10 @@ class AICPicker(AutoPicker): print('AICPicker: Maximum for slope determination right at the beginning of the window!') print('Choose longer slope determination window!') if self.iplot > 1: - fig = plt.figure() #self.iplot) ### WHY? MP MP + if not self.fig: + fig = plt.figure() #self.iplot) ### WHY? MP MP + else: + fig = self.fig ax = fig.add_subplot(111) x = self.Data[0].data ax.plot(self.Tcf, x / max(x), 'k', legend='(HOS-/AR-) Data') @@ -236,7 +238,7 @@ class AICPicker(AutoPicker): ax.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime) ax.set_yticks([]) ax.set_title(self.Data[0].stats.station) - return fig + return islope = islope[0][0:imax] dataslope = self.Data[0].data[islope] # calculate slope as polynomal fit of order 1 @@ -253,7 +255,10 @@ class AICPicker(AutoPicker): self.slope = None if self.iplot > 1: - fig = plt.figure()#self.iplot) + if not self.fig: + fig = plt.figure()#self.iplot) + else: + fig = self.fig ax1 = fig.add_subplot(211) x = self.Data[0].data ax1.plot(self.Tcf, x / max(x), 'k', label='(HOS-/AR-) Data') @@ -282,7 +287,7 @@ class AICPicker(AutoPicker): if self.Pick == None: print('AICPicker: Could not find minimum, picking window too short?') - return fig + return class PragPicker(AutoPicker): @@ -375,7 +380,10 @@ class PragPicker(AutoPicker): pickflag = 0 if self.getiplot() > 1: - fig = plt.figure()#self.getiplot()) + if not self.fig: + fig = plt.figure()#self.getiplot()) + else: + fig = self.fig ax = fig.add_subplot(111) ax.plot(Tcfpick, cfipick, 'k', label='CF') ax.plot(Tcfpick, cfsmoothipick, 'r', label='Smoothed CF') @@ -385,7 +393,7 @@ class PragPicker(AutoPicker): ax.set_yticks([]) ax.set_title(self.Data[0].stats.station) ax.legend() - return fig + return else: print('PragPicker: No initial onset time given! Check input!') diff --git a/pylot/core/pick/utils.py b/pylot/core/pick/utils.py index a9d41a37..baab079e 100644 --- a/pylot/core/pick/utils.py +++ b/pylot/core/pick/utils.py @@ -14,7 +14,7 @@ import numpy as np from obspy.core import Stream, UTCDateTime -def earllatepicker(X, nfac, TSNR, Pick1, iplot=None, stealth_mode=False): +def earllatepicker(X, nfac, TSNR, Pick1, iplot=None, stealth_mode=False, fig=None): ''' Function to derive earliest and latest possible pick after Diehl & Kissling (2009) as reasonable uncertainties. Latest possible pick is based on noise level, @@ -104,7 +104,8 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=None, stealth_mode=False): PickError = symmetrize_error(diffti_te, diffti_tl) if iplot > 1: - fig = plt.figure()#iplot) + if not fig: + fig = plt.figure()#iplot) ax = fig.add_subplot(111) ax.plot(t, x, 'k', label='Data') ax.plot(t[inoise], x[inoise], label='Noise Window') @@ -133,7 +134,7 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=None, stealth_mode=False): return EPick, LPick, PickError -def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=None): +def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=None, fig_dict): ''' Function to derive first motion (polarity) of given phase onset Pick. Calculation is based on zero crossings determined within time window pickwin @@ -620,7 +621,7 @@ def wadaticheck(pickdic, dttolerance, iplot): return checkedonsets -def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot): +def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot=0, fig_dict=None): ''' Function to detect spuriously picked noise peaks. Uses RMS trace of all 3 components (if available) to determine, diff --git a/pylot/core/util/map_projection.py b/pylot/core/util/map_projection.py index 2bfd3ed4..29a2cf7e 100644 --- a/pylot/core/util/map_projection.py +++ b/pylot/core/util/map_projection.py @@ -12,41 +12,44 @@ from pylot.core.util.widgets import PickDlg plt.interactive(False) class map_projection(QtGui.QWidget): - def __init__(self, mainwindow, figure=None): + def __init__(self, parent, figure=None): ''' :param: picked, can be False, auto, manual :value: str ''' QtGui.QWidget.__init__(self) - self.pyl_mainwindow = mainwindow - self.parser = mainwindow.metadata[1] + self._parent = parent + self.parser = parent.metadata[1] self.picks = None self.picks_dict = None self.figure = figure self.init_graphics() + self.init_basemap(projection='mill', resolution='l') + self.init_map() + #self.show() + + def init_map(self): self.init_stations() self.init_lat_lon_dimensions() self.init_lat_lon_grid() - self.init_basemap(projection='mill', resolution='l') self.init_x_y_dimensions() self.connectSignals() self.draw_everything() - #self.show() def onpick(self, event): ind = event.ind if ind == []: return - data = self.pyl_mainwindow.get_data().getWFData() + data = self._parent.get_data().getWFData() for index in ind: station=str(self.station_names[index]) try: - pickDlg = PickDlg(self, infile=self.pyl_mainwindow.getinfile(), + pickDlg = PickDlg(self, infile=self._parent.getinfile(), data=data.select(station=station), station=station, - picks=self.pyl_mainwindow.getPicksOnStation(station, 'manual'), - autopicks=self.pyl_mainwindow.getPicksOnStation(station, 'auto')) - pyl_mw = self.pyl_mainwindow + picks=self._parent.getPicksOnStation(station, 'manual'), + autopicks=self._parent.getPicksOnStation(station, 'auto')) + pyl_mw = self._parent if pickDlg.exec_(): pyl_mw.setDirty(True) pyl_mw.update_status('picks accepted ({0})'.format(station)) @@ -67,6 +70,17 @@ class map_projection(QtGui.QWidget): self.comboBox_phase.currentIndexChanged.connect(self._refresh_drawings) def init_graphics(self): + if not self.figure: + if not hasattr(self._parent, 'am_figure'): + self.figure = plt.figure() + self.toolbar = NavigationToolbar(self.figure.canvas, self) + else: + self.figure = self._parent.am_figure + self.toolbar = self._parent.am_toolbar + + self.main_ax = self.figure.add_subplot(111) + self.canvas = self.figure.canvas + self.main_box = QtGui.QVBoxLayout() self.setLayout(self.main_box) @@ -85,18 +99,9 @@ class map_projection(QtGui.QWidget): self.top_row.addWidget(self.comboBox_phase) self.top_row.setStretch(1,1) #set stretch of item 1 to 1 - if not self.figure: - fig = plt.figure() - else: - fig = self.figure - self.main_ax = fig.add_subplot(111) - self.canvas = fig.canvas self.main_box.addWidget(self.canvas) - - self.toolbar = NavigationToolbar(self.canvas, self) self.main_box.addWidget(self.toolbar) - self.figure = fig - + def init_stations(self): def get_station_names_lat_lon(parser): station_names=[] @@ -186,7 +191,6 @@ class map_projection(QtGui.QWidget): basemap.drawcoastlines() self.basemap = basemap self.figure.tight_layout() - def init_lat_lon_grid(self): def get_lat_lon_axis(lat, lon): diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index bfb171c0..2103223b 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -1,4 +1,4 @@ -[]# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- """ Created on Wed Mar 19 11:27:35 2014 @@ -39,6 +39,7 @@ from pylot.core.util.defaults import OUTPUTFORMATS, FILTERDEFAULTS, LOCTOOLS, \ from pylot.core.util.utils import prepTimeAxis, full_range, scaleWFData, \ demeanTrace, isSorted, findComboBoxIndex, clims from autoPyLoT import autoPyLoT +from pylot.core.util.thread import Thread import icons_rc def getDataType(parent): @@ -1270,11 +1271,12 @@ class PickDlg(QDialog): class TuneAutopicker(QWidget): - def __init__(self, ap, parent=None): - QtGui.QWidget.__init__(self, parent) + def __init__(self, ap, fig_dict, parent=None): + QtGui.QWidget.__init__(self, parent, 1) self.ap = ap - self.station = 'AH11' - self.fd = None + self.parent = parent + self.station = 'AH11' ############# justs for testing + self.fig_dict = fig_dict self.layout = QtGui.QHBoxLayout() self.parameter_layout = QtGui.QVBoxLayout() self.setLayout(self.layout) @@ -1282,6 +1284,9 @@ class TuneAutopicker(QWidget): self.add_parameter() self.add_buttons() self.set_stretch() + self.resize(1280, 720) + self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal) + self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) def init_figure_tabs(self): self.main_tabs = QtGui.QTabWidget() @@ -1302,13 +1307,20 @@ class TuneAutopicker(QWidget): self.parameter_layout.addWidget(self.pick_button) def call_picker(self): - self.parameters.update_params() - picks, fig_dict = autoPyLoT(self.ap, fnames='None', iplot=2) + self.pb_thread = Thread(self, self._hover, arg=None, progressText='Picking trace...') + self.pb_thread.start() + self.ap = self.update_params() + picks = autoPyLoT(self.ap, fnames='None', iplot=2, self.fig_dict) self.main_tabs.setParent(None) - self.fd = fig_dict[self.station] self.init_figure_tabs() self.set_stretch() + def update_params(self): + ap = self.parameters.update_params() + if self.parent: + self.parent._inputs = ap + return ap + def set_stretch(self): self.layout.setStretch(0, 3) self.layout.setStretch(1, 1) @@ -1788,6 +1800,7 @@ class AutoPickParaBox(QtGui.QWidget): value = self.getValue(box) self.ap.checkValue(param, value) self.ap.setParam(param, value) + return self.ap def getValue(self, box): if type(box) == QtGui.QLineEdit: From 184983bc8754c4d67857287314c2bcbe27965046 Mon Sep 17 00:00:00 2001 From: Marcel Paffrath Date: Fri, 12 May 2017 11:03:41 +0200 Subject: [PATCH 02/12] WIP: figure generating in threads partly working --- QtPyLoT.py | 37 ++++++++++++++++++++----------- autoPyLoT.py | 19 ++++++++++++---- pylot/RELEASE-VERSION | 2 +- pylot/core/pick/autopick.py | 8 +++---- pylot/core/pick/picker.py | 1 + pylot/core/pick/utils.py | 23 +++++++++++--------- pylot/core/util/widgets.py | 43 ++++++++++++++++++++++--------------- 7 files changed, 84 insertions(+), 49 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 8561a1df..3e81e0e6 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -1150,24 +1150,35 @@ class MainWindow(QMainWindow): self.listWidget.scrollToBottom() def tune_autopicker(self): - self.fig_dict = { - 'mainFig':, - 'aicFig':, - 'slength':, - 'checkZ4s':, - 'refPpick':, - 'el_Ppick':, - 'fm_picker':, - 'el_S1pick':, - 'el_S2pick':, - 'refSpick':, + self.fig_dict = {} + self.canvas_dict = {} + self.fig_keys = [ + 'mainFig', + 'aicFig', + 'slength', + 'checkZ4s', + 'refPpick', + 'el_Ppick', + 'fm_picker', + 'el_S1pick', + 'el_S2pick', + 'refSpick', 'aicARHfig', - } + ] + for key in self.fig_keys: + fig = Figure() + self.fig_dict[key] = fig ap = self._inputs if not self.tap: self.tap = TuneAutopicker(ap, self.fig_dict, self) - self.tap.show() + self.tap.update.connect(self.update_autopicker) + self.tap.show() + + def update_autopicker(self): + for key in self.fig_dict.keys(): + self.canvas_dict[key] = FigureCanvas(self.fig_dict[key]) + self.tap.fill_tabs(self.canvas_dict) def autoPick(self): self.autosave = QFileDialog().getExistingDirectory(caption='Select autoPyLoT output') diff --git a/autoPyLoT.py b/autoPyLoT.py index de8d00bf..e66a6c04 100755 --- a/autoPyLoT.py +++ b/autoPyLoT.py @@ -29,7 +29,7 @@ from pylot.core.util.version import get_git_version as _getVersionString __version__ = _getVersionString() -def autoPyLoT(parameter=None, inputfile=None, fnames=None, savepath=None, iplot=0, fig_dict=None): +def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, savepath=None, iplot=0): """ Determine phase onsets automatically utilizing the automatic picking algorithms by Kueperkoch et al. 2010/2012. @@ -55,6 +55,16 @@ def autoPyLoT(parameter=None, inputfile=None, fnames=None, savepath=None, iplot= ***********************************'''.format(version=_getVersionString()) print(splash) + if input_dict: + if input_dict.has_key('parameter'): + parameter = input_dict['parameter'] + if input_dict.has_key('fig_dict'): + fig_dict = input_dict['fig_dict'] + if input_dict.has_key('fnames'): + fnames = input_dict['fnames'] + if input_dict.has_key('iplot'): + iplot = input_dict['iplot'] + if not parameter: if inputfile: parameter = AutoPickParameter(inputfile) @@ -166,7 +176,7 @@ def autoPyLoT(parameter=None, inputfile=None, fnames=None, savepath=None, iplot= print(data) ########################################################## # !automated picking starts here! - picks, mainFig = autopickevent(wfdat, parameter, iplot=iplot, fig_dict=fig_dict) + picks = autopickevent(wfdat, parameter, iplot=iplot, fig_dict=fig_dict) ########################################################## # locating if locflag == 1: @@ -317,7 +327,7 @@ def autoPyLoT(parameter=None, inputfile=None, fnames=None, savepath=None, iplot= The Python picking and Location Tool\n ************************************'''.format(version=_getVersionString()) print(endsp) - return picks, mainFig + return picks if __name__ == "__main__": @@ -344,4 +354,5 @@ if __name__ == "__main__": cla = parser.parse_args() - picks, mainFig = autoPyLoT(str(cla.inputfile), str(cla.fnames), str(cla.spath)) + picks, mainFig = autoPyLoT(inputfile=str(cla.inputfile), + fnames=str(cla.fnames), savepath=str(cla.spath)) diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index a2a47e0c..e80b710b 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -d135-dirty +f58d1-dirty diff --git a/pylot/core/pick/autopick.py b/pylot/core/pick/autopick.py index a9b6ad1f..e4c34b6c 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -74,7 +74,7 @@ def call_autopickstation(input_tuple): return autopickstation(wfstream, pickparam, verbose, iplot=0) -def autopickstation(wfstream, pickparam, verbose=False, iplot=0): +def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): """ :param wfstream: `~obspy.core.stream.Stream` containing waveform :type wfstream: obspy.core.stream.Stream @@ -233,7 +233,7 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): # get prelimenary onset time from AIC-HOS-CF using subclass AICPicker # of class AutoPicking key = 'aicFig' - aicpick = AICPicker(aiccf, tsnrz, pickwinP, iplot, None, tsmoothP, fig_dict[key]) + aicpick = AICPicker(aiccf, tsnrz, pickwinP, iplot, None, tsmoothP, fig=fig_dict[key]) ############################################################## if aicpick.getpick() is not None: # check signal length to detect spuriously picked noise peaks @@ -266,7 +266,7 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): trH2_filt.taper(max_percentage=0.05, type='hann') zne += trH1_filt zne += trH2_filt - key = 'slenght' + key = 'slength' Pflag = checksignallength(zne, aicpick.getpick(), tsnrz, minsiglength, nfacsl, minpercent, iplot, @@ -281,7 +281,7 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): if verbose: print(msg) else: if iplot>1: - key = 'checkZ4S' + key = 'checkZ4s' Pflag = checkZ4S(zne, aicpick.getpick(), zfac, tsnrz[3], iplot, fig_dict[key]) if Pflag == 0: diff --git a/pylot/core/pick/picker.py b/pylot/core/pick/picker.py index c1d0d2a6..18ecd410 100644 --- a/pylot/core/pick/picker.py +++ b/pylot/core/pick/picker.py @@ -73,6 +73,7 @@ class AutoPicker(object): self.setTsmooth(Tsmooth) self.setpick1(Pick1) self.fig = fig + self.calcPick() def __str__(self): return '''\n\t{name} object:\n diff --git a/pylot/core/pick/utils.py b/pylot/core/pick/utils.py index baab079e..9d77cc69 100644 --- a/pylot/core/pick/utils.py +++ b/pylot/core/pick/utils.py @@ -129,12 +129,12 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=None, stealth_mode=False, fig=Non ax.legend() if iplot: - return EPick, LPick, PickError, fig + return EPick, LPick, PickError else: return EPick, LPick, PickError -def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=None, fig_dict): +def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=None, fig=None): ''' Function to derive first motion (polarity) of given phase onset Pick. Calculation is based on zero crossings determined within time window pickwin @@ -279,7 +279,8 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=None, fig_dict): print ("fmpicker: Found polarity %s" % FM) if iplot > 1: - fig = plt.figure()#iplot) + if not fig: + fig = plt.figure()#iplot) ax1 = fig.add_subplot(211) ax1.plot(t, xraw, 'k') ax1.plot([Pick, Pick], [max(xraw), -max(xraw)], 'b', linewidth=2, label='Pick') @@ -307,7 +308,7 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=None, fig_dict): ax2.set_yticks([]) if iplot: - return FM, fig + return FM else: return FM @@ -621,7 +622,7 @@ def wadaticheck(pickdic, dttolerance, iplot): return checkedonsets -def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot=0, fig_dict=None): +def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot=0, fig=None): ''' Function to detect spuriously picked noise peaks. Uses RMS trace of all 3 components (if available) to determine, @@ -693,7 +694,8 @@ def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot=0, fi returnflag = 0 if iplot == 2: - fig = plt.figure()#iplot) + if not fig: + fig = plt.figure()#iplot) ax = fig.add_subplot(111) ax.plot(t, rms, 'k', label='RMS Data') ax.plot(t[inoise], rms[inoise], 'c', label='RMS Noise Window') @@ -707,7 +709,7 @@ def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot=0, fi ax.set_title('Check for Signal Length, Station %s' % X[0].stats.station) ax.set_yticks([]) - return returnflag, fig + return returnflag def checkPonsets(pickdic, dttolerance, iplot): @@ -869,7 +871,7 @@ def jackknife(X, phi, h): return PHI_jack, PHI_pseudo, PHI_sub -def checkZ4S(X, pick, zfac, checkwin, iplot): +def checkZ4S(X, pick, zfac, checkwin, iplot, fig=None): ''' Function to compare energy content of vertical trace with energy content of horizontal traces to detect spuriously @@ -963,7 +965,8 @@ def checkZ4S(X, pick, zfac, checkwin, iplot): edat[0].stats.delta) tn = np.arange(0, ndat[0].stats.npts / ndat[0].stats.sampling_rate, ndat[0].stats.delta) - fig = plt.figure() + if not fig: + fig = plt.figure() ax = fig.add_subplot(111) ax.plot(tz, z / max(z), 'k') ax.plot(tz[isignal], z[isignal] / max(z), 'r') @@ -981,7 +984,7 @@ def checkZ4S(X, pick, zfac, checkwin, iplot): ax.set_title('CheckZ4S, Station %s' % zdat[0].stats.station) ax.legend() - return returnflag, fig + return returnflag if __name__ == '__main__': diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 2103223b..5c73ed63 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -1271,11 +1271,13 @@ class PickDlg(QDialog): class TuneAutopicker(QWidget): + update = QtCore.Signal(str) + def __init__(self, ap, fig_dict, parent=None): QtGui.QWidget.__init__(self, parent, 1) self.ap = ap self.parent = parent - self.station = 'AH11' ############# justs for testing + self.station = 'TMO53' ############# justs for testing self.fig_dict = fig_dict self.layout = QtGui.QHBoxLayout() self.parameter_layout = QtGui.QVBoxLayout() @@ -1293,8 +1295,8 @@ class TuneAutopicker(QWidget): self.p_tabs = QtGui.QTabWidget() self.s_tabs = QtGui.QTabWidget() self.layout.insertWidget(0, self.main_tabs) - self.init_tab_names() - self.fill_tabs() + #self.init_tab_names() + #self.fill_tabs(None) def add_parameter(self): self.parameters = AutoPickParaBox(self.ap) @@ -1307,13 +1309,22 @@ class TuneAutopicker(QWidget): self.parameter_layout.addWidget(self.pick_button) def call_picker(self): - self.pb_thread = Thread(self, self._hover, arg=None, progressText='Picking trace...') - self.pb_thread.start() self.ap = self.update_params() - picks = autoPyLoT(self.ap, fnames='None', iplot=2, self.fig_dict) + args = {'parameter': self.ap, + 'fnames': 'None', + 'iplot': 2, + 'fig_dict': self.fig_dict} + self.ap_thread = Thread(self, autoPyLoT, arg=args, progressText='Picking trace...') + self.ap_thread.finished.connect(self.finish_picker) + self.ap_thread.start() + #picks = autoPyLoT(self.ap, fnames='None', iplot=2, fig_dict=self.fig_dict) + + def finish_picker(self): + self.picks = self.ap_thread.data self.main_tabs.setParent(None) self.init_figure_tabs() self.set_stretch() + self.update.emit('Update') def update_params(self): ap = self.parameters.update_params() @@ -1329,37 +1340,35 @@ class TuneAutopicker(QWidget): self.ptb_names = ['aicFig', 'slenght', 'checkZ4S', 'refPpick', 'el_Ppick', 'fm_picker'] self.stb_names = ['aicARHfig', 'refSpick', 'el_S1pick', 'el_S2pick'] - def fill_tabs(self): + def fill_tabs(self, canvas_dict): try: - main_fig = self.fd['mainFig'] - self.main_tabs.addTab(main_fig.canvas, 'Overview') + self.main_tabs.addTab(canvas_dict['mainFig'], 'Overview') except Exception as e: self.main_tabs.addTab(QtGui.QWidget(), 'Overview') self.main_tabs.addTab(self.p_tabs, 'P') self.main_tabs.addTab(self.s_tabs, 'S') - self.fill_p_tabs() - self.fill_s_tabs() + self.fill_p_tabs(canvas_dict) + self.fill_s_tabs(canvas_dict) try: main_fig.tight_layout() except: pass - def fill_p_tabs(self): + def fill_p_tabs(self, canvas_dict): for name in self.ptb_names: try: - figure = self.fd[name] - id = self.p_tabs.addTab(figure.canvas, name) + id = self.p_tabs.addTab(canvas_dict[name], name) self.p_tabs.setTabEnabled(id, True) figure.tight_layout() except Exception as e: id = self.p_tabs.addTab(QtGui.QWidget(), name) self.p_tabs.setTabEnabled(id, False) - def fill_s_tabs(self): + def fill_s_tabs(self, canvas_dict): for name in self.stb_names: try: - figure = self.fd[name] - id = self.s_tabs.addTab(figure.canvas, name) + figure = self.fig_dict[name] + id = self.s_tabs.addTab(canvas_dict[name], name) self.s_tabs.setTabEnabled(id, True) figure.tight_layout() except Exception as e: From 12e6106227d5aa1e1a2ee69496d023756537ec79 Mon Sep 17 00:00:00 2001 From: Marcel Paffrath Date: Fri, 12 May 2017 13:58:05 +0200 Subject: [PATCH 03/12] first working version of threaded tuneAutopicker --- pylot/RELEASE-VERSION | 2 +- pylot/core/pick/autopick.py | 4 ++-- pylot/core/pick/utils.py | 11 +++-------- pylot/core/util/widgets.py | 33 +++++++++++++++------------------ 4 files changed, 21 insertions(+), 29 deletions(-) diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index e80b710b..8d4bba5a 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -f58d1-dirty +1849-dirty diff --git a/pylot/core/pick/autopick.py b/pylot/core/pick/autopick.py index e4c34b6c..67d16c09 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -341,7 +341,7 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): if iplot: key = 'el_Ppick' epickP, lpickP, Perror = earllatepicker(z_copy, nfacP, tsnrz, - mpickP, iplot, fig_dict[key]) + mpickP, iplot, fig=fig_dict[key]) else: epickP, lpickP, Perror = earllatepicker(z_copy, nfacP, tsnrz, mpickP, iplot) @@ -470,7 +470,7 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): # of class AutoPicking key = 'aicARHfig' aicarhpick = AICPicker(haiccf, tsnrh, pickwinS, iplot, None, - aictsmoothS, fig_dict[key]) + aictsmoothS, fig = fig_dict[key]) ############################################################### # go on with processing if AIC onset passes quality control if (aicarhpick.getSlope() >= minAICSslope and diff --git a/pylot/core/pick/utils.py b/pylot/core/pick/utils.py index 9d77cc69..25054668 100644 --- a/pylot/core/pick/utils.py +++ b/pylot/core/pick/utils.py @@ -105,6 +105,7 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=None, stealth_mode=False, fig=Non if iplot > 1: if not fig: + print('New Figure.........................') fig = plt.figure()#iplot) ax = fig.add_subplot(111) ax.plot(t, x, 'k', label='Data') @@ -128,10 +129,7 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=None, stealth_mode=False, fig=Non X[0].stats.station) ax.legend() - if iplot: - return EPick, LPick, PickError - else: - return EPick, LPick, PickError + return EPick, LPick, PickError def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=None, fig=None): @@ -307,10 +305,7 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=None, fig=None): ax2.set_xlabel('Time [s] since %s' % Xraw[0].stats.starttime) ax2.set_yticks([]) - if iplot: - return FM - else: - return FM + return FM def crossings_nonzero_all(data): diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 5c73ed63..f9ccb917 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -1295,7 +1295,7 @@ class TuneAutopicker(QWidget): self.p_tabs = QtGui.QTabWidget() self.s_tabs = QtGui.QTabWidget() self.layout.insertWidget(0, self.main_tabs) - #self.init_tab_names() + self.init_tab_names() #self.fill_tabs(None) def add_parameter(self): @@ -1337,7 +1337,7 @@ class TuneAutopicker(QWidget): self.layout.setStretch(1, 1) def init_tab_names(self): - self.ptb_names = ['aicFig', 'slenght', 'checkZ4S', 'refPpick', 'el_Ppick', 'fm_picker'] + self.ptb_names = ['aicFig', 'slength', 'checkZ4s', 'refPpick', 'el_Ppick', 'fm_picker'] self.stb_names = ['aicARHfig', 'refSpick', 'el_S1pick', 'el_S2pick'] def fill_tabs(self, canvas_dict): @@ -1356,26 +1356,23 @@ class TuneAutopicker(QWidget): def fill_p_tabs(self, canvas_dict): for name in self.ptb_names: + id = self.p_tabs.addTab(canvas_dict[name], name) + self.p_tabs.setTabEnabled(id, bool(self.fig_dict[name].axes)) try: - id = self.p_tabs.addTab(canvas_dict[name], name) - self.p_tabs.setTabEnabled(id, True) - figure.tight_layout() - except Exception as e: - id = self.p_tabs.addTab(QtGui.QWidget(), name) - self.p_tabs.setTabEnabled(id, False) - + self.fig_dict[name].tight_layout() + except: + pass + def fill_s_tabs(self, canvas_dict): for name in self.stb_names: + figure = self.fig_dict[name] + id = self.s_tabs.addTab(canvas_dict[name], name) + self.s_tabs.setTabEnabled(id, bool(self.fig_dict[name].axes)) try: - figure = self.fig_dict[name] - id = self.s_tabs.addTab(canvas_dict[name], name) - self.s_tabs.setTabEnabled(id, True) - figure.tight_layout() - except Exception as e: - id = self.s_tabs.addTab(QtGui.QWidget(), name) - self.s_tabs.setTabEnabled(id, False) - - + self.fig_dict[name].tight_layout() + except: + pass + class PropertiesDlg(QDialog): def __init__(self, parent=None, infile=None): super(PropertiesDlg, self).__init__(parent) From 77b076d560ec7a752b891f7dd68845f1f17f9e6e Mon Sep 17 00:00:00 2001 From: Marcel Paffrath Date: Fri, 12 May 2017 15:37:57 +0200 Subject: [PATCH 04/12] threading for tuneAutopicker working now, to do: change figures (vfill), tight layout? --- QtPyLoT.py | 49 ++++++++++++++++++++++---------------- pylot/RELEASE-VERSION | 2 +- pylot/core/util/widgets.py | 47 +++++++++++++++++++++++++----------- 3 files changed, 63 insertions(+), 35 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 3e81e0e6..e7acb1c3 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -636,13 +636,13 @@ class MainWindow(QMainWindow): def createEventBox(self): qcb = QComboBox() palette = qcb.palette() - palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Highlight, - QtGui.QBrush(QtGui.QColor(0,0,127,127))) - palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Highlight, - QtGui.QBrush(QtGui.QColor(0,0,127,127))) + # change highlight color: + # palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Highlight, + # QtGui.QBrush(QtGui.QColor(0,0,127,127))) + # palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Highlight, + # QtGui.QBrush(QtGui.QColor(0,0,127,127))) qcb.setPalette(palette) return qcb - def init_events(self, new=False): nitems = self.eventBox.count() @@ -651,7 +651,7 @@ class MainWindow(QMainWindow): self.clearWaveformDataPlot() return self.eventBox.setEnabled(True) - self.fill_eventbox() + self.fill_eventbox(self.eventBox) if new: self.eventBox.setCurrentIndex(0) else: @@ -659,8 +659,12 @@ class MainWindow(QMainWindow): self.refreshEvents() tabindex = self.tabs.currentIndex() - def fill_eventbox(self): - index=self.eventBox.currentIndex() + def fill_eventbox(self, eventBox, select_events='all'): + ''' + :param: select_events, can be 'all', 'ref' + :type: str + ''' + index=eventBox.currentIndex() tv=QtGui.QTableView() header = tv.horizontalHeader() header.setResizeMode(QtGui.QHeaderView.ResizeToContents) @@ -669,10 +673,11 @@ class MainWindow(QMainWindow): tv.verticalHeader().hide() tv.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) - self.eventBox.setView(tv) - self.eventBox.clear() - model = self.eventBox.model() + eventBox.setView(tv) + eventBox.clear() + model = eventBox.model() plmax=0 + #set maximum length of path string for event in self.project.eventlist: pl = len(event.path) if pl > plmax: @@ -722,8 +727,11 @@ class MainWindow(QMainWindow): # item2.setForeground(QtGui.QColor('black')) # item2.setFont(font) itemlist = [item_path, item_nmp, item_nap, item_ref, item_test, item_notes] + if event_test and select_events == 'ref': + for item in itemlist: + item.setEnabled(False) model.appendRow(itemlist) - self.eventBox.setCurrentIndex(index) + eventBox.setCurrentIndex(index) def filename_from_action(self, action): if action.data() is None: @@ -1169,11 +1177,12 @@ class MainWindow(QMainWindow): fig = Figure() self.fig_dict[key] = fig - ap = self._inputs if not self.tap: - self.tap = TuneAutopicker(ap, self.fig_dict, self) + self.tap = TuneAutopicker(self) self.tap.update.connect(self.update_autopicker) - self.tap.show() + else: + self.tap.fill_eventbox() + self.tap.show() def update_autopicker(self): for key in self.fig_dict.keys(): @@ -1420,7 +1429,7 @@ class MainWindow(QMainWindow): self.array_map.refresh_drawings(self.picks) self._eventChanged[1] = False - def init_event_table(self, index=2): + def init_event_table(self, tabindex=2): def set_enabled(item, enabled=True, checkable=False): if enabled and not checkable: item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) @@ -1451,12 +1460,12 @@ class MainWindow(QMainWindow): event.setTestEvent(True) elif column == 4 and not item_test.checkState(): event.setTestEvent(False) - self.fill_eventbox() + self.fill_eventbox(self.eventBox) elif column == 5: #update event notes notes = table[row][5].text() event.addNotes(notes) - self.fill_eventbox() + self.fill_eventbox(self.eventBox) if hasattr(self, 'qtl'): self.qtl.setParent(None) @@ -1521,7 +1530,7 @@ class MainWindow(QMainWindow): self.qtl.cellChanged[int, int].connect(cell_changed) self.events_layout.addWidget(self.qtl) - self.tabs.setCurrentIndex(index) + self.tabs.setCurrentIndex(tabindex) def read_metadata_thread(self, fninv): self.rm_thread = Thread(self, read_metadata, arg=fninv, progressText='Reading metadata...') @@ -1710,7 +1719,7 @@ class MainWindow(QMainWindow): self.createNewProject(exists=True) def draw(self): - self.fill_eventbox() + self.fill_eventbox(self.eventBox) self.getPlotWidget().draw() def setDirty(self, value): diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index 8d4bba5a..c676af0a 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -1849-dirty +12e6-dirty diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index f9ccb917..988017a1 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -1273,41 +1273,60 @@ class PickDlg(QDialog): class TuneAutopicker(QWidget): update = QtCore.Signal(str) - def __init__(self, ap, fig_dict, parent=None): + def __init__(self, parent): QtGui.QWidget.__init__(self, parent, 1) - self.ap = ap self.parent = parent - self.station = 'TMO53' ############# justs for testing - self.fig_dict = fig_dict - self.layout = QtGui.QHBoxLayout() - self.parameter_layout = QtGui.QVBoxLayout() - self.setLayout(self.layout) + self.ap = parent._inputs + self.fig_dict = parent.fig_dict + self.init_main_layouts() + self.init_eventlist() self.init_figure_tabs() self.add_parameter() self.add_buttons() self.set_stretch() self.resize(1280, 720) self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal) - self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) + #self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) + def init_main_layouts(self): + self.main_layout = QtGui.QVBoxLayout() + self.tune_layout = QtGui.QHBoxLayout() + self.trace_layout = QtGui.QHBoxLayout() + self.parameter_layout = QtGui.QVBoxLayout() + + self.main_layout.addLayout(self.tune_layout) + self.main_layout.addLayout(self.trace_layout) + self.setLayout(self.main_layout) + + def init_eventlist(self): + self.eventBox = self.parent.createEventBox() + self.fill_eventbox() + self.trace_layout.addWidget(self.eventBox) + + def init_stationlist(self): + pass + def init_figure_tabs(self): self.main_tabs = QtGui.QTabWidget() self.p_tabs = QtGui.QTabWidget() self.s_tabs = QtGui.QTabWidget() - self.layout.insertWidget(0, self.main_tabs) + self.tune_layout.insertWidget(0, self.main_tabs) self.init_tab_names() - #self.fill_tabs(None) def add_parameter(self): self.parameters = AutoPickParaBox(self.ap) self.parameter_layout.addWidget(self.parameters) - self.layout.insertLayout(1, self.parameter_layout) + self.tune_layout.insertLayout(1, self.parameter_layout) def add_buttons(self): self.pick_button = QtGui.QPushButton('Pick Trace') self.pick_button.clicked.connect(self.call_picker) - self.parameter_layout.addWidget(self.pick_button) + self.trace_layout.addWidget(self.pick_button) + self.trace_layout.setStretch(0, 1) + def fill_eventbox(self): + self.parent.fill_eventbox(self.eventBox, 'ref') + def call_picker(self): self.ap = self.update_params() args = {'parameter': self.ap, @@ -1333,8 +1352,8 @@ class TuneAutopicker(QWidget): return ap def set_stretch(self): - self.layout.setStretch(0, 3) - self.layout.setStretch(1, 1) + self.tune_layout.setStretch(0, 3) + self.tune_layout.setStretch(1, 1) def init_tab_names(self): self.ptb_names = ['aicFig', 'slength', 'checkZ4s', 'refPpick', 'el_Ppick', 'fm_picker'] From 4d9c7b02cff4c831929cc4f1902dc89a69936aaf Mon Sep 17 00:00:00 2001 From: Marcel Paffrath Date: Mon, 15 May 2017 11:20:40 +0200 Subject: [PATCH 05/12] autoPyLoT: figure beautification also added nav toolbar to TuneAutopicker --- QtPyLoT.py | 16 +++++++++------- pylot/RELEASE-VERSION | 2 +- pylot/core/pick/autopick.py | 4 ++-- pylot/core/pick/picker.py | 18 ++++++++++++------ pylot/core/pick/utils.py | 16 +++++++--------- pylot/core/util/widgets.py | 22 ++++++++++++++-------- 6 files changed, 45 insertions(+), 33 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index e7acb1c3..f565d22b 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -556,12 +556,14 @@ class MainWindow(QMainWindow): self.drawPicks(picktype=type) self.draw() - def getCurrentEvent(self): - for event in self.project.eventlist: - if event.path == self.getCurrentEventPath(): + def getCurrentEvent(self, eventlist=None): + if not eventlist: + eventlist = self.project.eventlist + for event in eventlist: + if event.path == self.getCurrentEventPath(eventlist): return event - def getCurrentEventPath(self): + def getCurrentEventPath(self, eventlist=None): return str(self.eventBox.currentText().split('|')[0]).strip() def getLastEvent(self): @@ -604,10 +606,10 @@ class MainWindow(QMainWindow): else: return - def getWFFnames_from_eventlist(self): + def getWFFnames_from_eventlist(self, eventlist=None): if self.dataStructure: searchPath = self.dataStructure.expandDataPath() - directory = self.getCurrentEventPath() + directory = self.getCurrentEventPath(eventlist) self.fnames = [os.path.join(directory, f) for f in os.listdir(directory)] else: raise DatastructureError('not specified') @@ -940,7 +942,7 @@ class MainWindow(QMainWindow): # ans = self.data.setWFData(self.getWFFnames()) # else: # ans = False - self.data.setWFData(self.getWFFnames_from_eventlist()) + self.data.setWFData(self.getWFFnames_from_eventlist(self.project.eventlist)) self._stime = full_range(self.get_data().getWFData())[0] def connectWFplotEvents(self): diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index c676af0a..05652c05 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -12e6-dirty +77b07-dirty diff --git a/pylot/core/pick/autopick.py b/pylot/core/pick/autopick.py index 67d16c09..dc36eb69 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -700,7 +700,7 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): if len(edat[0]) > 1 and len(ndat[0]) > 1 and Sflag == 1: # plot horizontal traces - ax2 = fig.add_subplot(312) + ax2 = fig.add_subplot(3,1,2,sharex=ax1) th1data = np.arange(0, trH1_filt.stats.npts / trH1_filt.stats.sampling_rate, @@ -749,7 +749,7 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): ax2.set_ylabel('Normalized Counts') #fig.suptitle(trH1_filt.stats.starttime) - ax3 = fig.add_subplot(313) + ax3 = fig.add_subplot(3,1,3, sharex=ax1) th2data = np.arange(0, trH2_filt.stats.npts / trH2_filt.stats.sampling_rate, diff --git a/pylot/core/pick/picker.py b/pylot/core/pick/picker.py index 18ecd410..b2c34813 100644 --- a/pylot/core/pick/picker.py +++ b/pylot/core/pick/picker.py @@ -268,22 +268,28 @@ class AICPicker(AutoPicker): ax1.plot([self.Pick, self.Pick], [-0.1, 0.5], 'b', linewidth=2, label='AIC-Pick') ax1.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime) ax1.set_yticks([]) - ax1.set_title(self.Data[0].stats.station) ax1.legend() if self.Pick is not None: - ax2 = fig.add_subplot(212) + ax2 = fig.add_subplot(2,1,2, sharex=ax1) ax2.plot(self.Tcf, x, 'k', label='Data') - ax2.plot(self.Tcf[inoise], self.Data[0].data[inoise], label='Noise Window') - ax2.plot(self.Tcf[isignal], self.Data[0].data[isignal], 'r', label='Signal Window') - ax2.plot(self.Tcf[islope], dataslope, 'g--', label='Slope Window') + ax1.axvspan(self.Tcf[inoise[0]],self.Tcf[inoise[-1]], color='y', alpha=0.2, lw=0, label='Noise Window') + ax1.axvspan(self.Tcf[isignal[0]],self.Tcf[isignal[-1]], color='b', alpha=0.2, lw=0, label='Signal Window') + ax1.axvspan(self.Tcf[islope[0]],self.Tcf[islope[-1]], color='g', alpha=0.2, lw=0, label='Slope Window') + + ax2.axvspan(self.Tcf[inoise[0]],self.Tcf[inoise[-1]], color='y', alpha=0.2, lw=0, label='Noise Window') + ax2.axvspan(self.Tcf[isignal[0]],self.Tcf[isignal[-1]], color='b', alpha=0.2, lw=0, label='Signal Window') + ax2.axvspan(self.Tcf[islope[0]],self.Tcf[islope[-1]], color='g', alpha=0.2, lw=0, label='Slope Window') ax2.plot(self.Tcf[islope], datafit, 'g', linewidth=2, label='Slope') - ax2.set_title('Station %s, SNR=%7.2f, Slope= %12.2f counts/s' % (self.Data[0].stats.station, + + ax1.set_title('Station %s, SNR=%7.2f, Slope= %12.2f counts/s' % (self.Data[0].stats.station, self.SNR, self.slope)) ax2.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime) ax2.set_ylabel('Counts') ax2.set_yticks([]) ax2.legend() + else: + ax1.set_title(self.Data[0].stats.station) if self.Pick == None: print('AICPicker: Could not find minimum, picking window too short?') diff --git a/pylot/core/pick/utils.py b/pylot/core/pick/utils.py index 25054668..76312f83 100644 --- a/pylot/core/pick/utils.py +++ b/pylot/core/pick/utils.py @@ -105,12 +105,11 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=None, stealth_mode=False, fig=Non if iplot > 1: if not fig: - print('New Figure.........................') fig = plt.figure()#iplot) ax = fig.add_subplot(111) ax.plot(t, x, 'k', label='Data') - ax.plot(t[inoise], x[inoise], label='Noise Window') - ax.plot(t[isignal], x[isignal], 'r', label='Signal Window') + ax.axvspan(t[inoise[0]], t[inoise[-1]], color='y', alpha=0.2, lw=0, label='Noise Window') + ax.axvspan(t[isignal[0]], t[isignal[-1]], color='b', alpha=0.2, lw=0, label='Signal Window') ax.plot([t[0], t[int(len(t)) - 1]], [nlevel, nlevel], '--k', label='Noise Level') ax.plot(t[isignal[zc]], np.zeros(len(zc)), '*g', markersize=14, label='Zero Crossings') @@ -292,7 +291,7 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=None, fig=None): ax1.set_title('First-Motion Determination, %s, Unfiltered Data' % Xraw[ 0].stats.station) - ax2=fig.add_subplot(212) + ax2=fig.add_subplot(2,1,2, sharex=ax1) ax2.set_title('First-Motion Determination, Filtered Data') ax2.plot(t, xfilt, 'k') ax2.plot([Pick, Pick], [max(xfilt), -max(xfilt)], 'b', @@ -693,8 +692,8 @@ def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot=0, fi fig = plt.figure()#iplot) ax = fig.add_subplot(111) ax.plot(t, rms, 'k', label='RMS Data') - ax.plot(t[inoise], rms[inoise], 'c', label='RMS Noise Window') - ax.plot(t[isignal], rms[isignal], 'r', label='RMS Signal Window') + ax.axvspan(t[inoise[0]], t[inoise[-1]], color='y', alpha=0.2, lw=0, label='Noise Window') + ax.axvspan(t[isignal[0]], t[isignal[-1]], color='b', alpha=0.2, lw=0, label='Signal Window') ax.plot([t[isignal[0]], t[isignal[len(isignal) - 1]]], [minsiglevel, minsiglevel], 'g', linewidth=2, label='Minimum Signal Level') ax.plot([pick, pick], [min(rms), max(rms)], 'b', linewidth=2, label='Onset') @@ -964,11 +963,10 @@ def checkZ4S(X, pick, zfac, checkwin, iplot, fig=None): fig = plt.figure() ax = fig.add_subplot(111) ax.plot(tz, z / max(z), 'k') - ax.plot(tz[isignal], z[isignal] / max(z), 'r') + ax.axvspan(tz[isignal[0]], tz[isignal[-1]], color='b', alpha=0.2, + lw=0, label='Signal Window') ax.plot(te, edat[0].data / max(edat[0].data) + 1, 'k') - ax.plot(te[isignal], edat[0].data[isignal] / max(edat[0].data) + 1, 'r') ax.plot(tn, ndat[0].data / max(ndat[0].data) + 2, 'k') - ax.plot(tn[isignal], ndat[0].data[isignal] / max(ndat[0].data) + 2, 'r') ax.plot([tz[isignal[0]], tz[isignal[len(isignal) - 1]]], [minsiglevel / max(z), minsiglevel / max(z)], 'g', linewidth=2, label='Minimum Signal Level') diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 988017a1..79140e4b 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -1294,8 +1294,8 @@ class TuneAutopicker(QWidget): self.trace_layout = QtGui.QHBoxLayout() self.parameter_layout = QtGui.QVBoxLayout() - self.main_layout.addLayout(self.tune_layout) self.main_layout.addLayout(self.trace_layout) + self.main_layout.addLayout(self.tune_layout) self.setLayout(self.main_layout) def init_eventlist(self): @@ -1360,10 +1360,8 @@ class TuneAutopicker(QWidget): self.stb_names = ['aicARHfig', 'refSpick', 'el_S1pick', 'el_S2pick'] def fill_tabs(self, canvas_dict): - try: - self.main_tabs.addTab(canvas_dict['mainFig'], 'Overview') - except Exception as e: - self.main_tabs.addTab(QtGui.QWidget(), 'Overview') + id = self.main_tabs.addTab(self.gen_tab_widget('Overview', canvas_dict['mainFig']), 'Overview') + self.main_tabs.setTabEnabled(id, bool(self.fig_dict['mainFig'].axes)) self.main_tabs.addTab(self.p_tabs, 'P') self.main_tabs.addTab(self.s_tabs, 'S') self.fill_p_tabs(canvas_dict) @@ -1375,7 +1373,7 @@ class TuneAutopicker(QWidget): def fill_p_tabs(self, canvas_dict): for name in self.ptb_names: - id = self.p_tabs.addTab(canvas_dict[name], name) + id = self.p_tabs.addTab(self.gen_tab_widget(name, canvas_dict[name]), name) self.p_tabs.setTabEnabled(id, bool(self.fig_dict[name].axes)) try: self.fig_dict[name].tight_layout() @@ -1384,13 +1382,21 @@ class TuneAutopicker(QWidget): def fill_s_tabs(self, canvas_dict): for name in self.stb_names: - figure = self.fig_dict[name] - id = self.s_tabs.addTab(canvas_dict[name], name) + id = self.s_tabs.addTab(self.gen_tab_widget(name, canvas_dict[name]), name) self.s_tabs.setTabEnabled(id, bool(self.fig_dict[name].axes)) try: self.fig_dict[name].tight_layout() except: pass + + def gen_tab_widget(self, name, canvas): + widget = QtGui.QWidget() + v_layout = QtGui.QVBoxLayout() + v_layout.addWidget(canvas) + v_layout.addWidget(NavigationToolbar2QT(canvas, self)) + widget.setLayout(v_layout) + return widget + class PropertiesDlg(QDialog): def __init__(self, parent=None, infile=None): From a2ab98c202e2c24e69a61cf2d8b3567c3b77d9e1 Mon Sep 17 00:00:00 2001 From: Marcel Paffrath Date: Mon, 15 May 2017 12:03:53 +0200 Subject: [PATCH 06/12] added station list to TuneAutopicker --- QtPyLoT.py | 42 +++++++++++++++++++------------------- pylot/RELEASE-VERSION | 2 +- pylot/core/util/widgets.py | 28 ++++++++++++++++++++++--- 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index f565d22b..c88c228f 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -556,19 +556,6 @@ class MainWindow(QMainWindow): self.drawPicks(picktype=type) self.draw() - def getCurrentEvent(self, eventlist=None): - if not eventlist: - eventlist = self.project.eventlist - for event in eventlist: - if event.path == self.getCurrentEventPath(eventlist): - return event - - def getCurrentEventPath(self, eventlist=None): - return str(self.eventBox.currentText().split('|')[0]).strip() - - def getLastEvent(self): - return self.recentfiles[0] - def add_recentfile(self, event): self.recentfiles.insert(0, event) @@ -606,16 +593,28 @@ class MainWindow(QMainWindow): else: return - def getWFFnames_from_eventlist(self, eventlist=None): + def getWFFnames_from_eventbox(self, eventlist=None, eventbox=None): if self.dataStructure: - searchPath = self.dataStructure.expandDataPath() - directory = self.getCurrentEventPath(eventlist) - self.fnames = [os.path.join(directory, f) for f in os.listdir(directory)] + directory = self.getCurrentEventPath(eventbox) + fnames = [os.path.join(directory, f) for f in os.listdir(directory)] else: raise DatastructureError('not specified') - if not self.fnames: - return None - return self.fnames + return fnames + + def getCurrentEvent(self, eventlist=None, eventbox=None): + if not eventlist: + eventlist = self.project.eventlist + for event in eventlist: + if event.path == self.getCurrentEventPath(eventbox): + return event + + def getCurrentEventPath(self, eventbox=None): + if not eventbox: + eventbox = self.eventBox + return str(eventbox.currentText().split('|')[0]).strip() + + def getLastEvent(self): + return self.recentfiles[0] def add_events(self): if not self.project: @@ -942,7 +941,8 @@ class MainWindow(QMainWindow): # ans = self.data.setWFData(self.getWFFnames()) # else: # ans = False - self.data.setWFData(self.getWFFnames_from_eventlist(self.project.eventlist)) + self.fnames = self.getWFFnames_from_eventbox(self.project.eventlist) + self.data.setWFData(self.fnames) self._stime = full_range(self.get_data().getWFData())[0] def connectWFplotEvents(self): diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index 05652c05..d7fe7f2d 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -77b07-dirty +4d9c-dirty diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 79140e4b..1a009b2a 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -30,6 +30,7 @@ from PySide.QtGui import QAction, QApplication, QCheckBox, QComboBox, \ from PySide.QtCore import QSettings, Qt, QUrl, Signal, Slot from PySide.QtWebKit import QWebView from obspy import Stream, UTCDateTime +from pylot.core.io.data import Data from pylot.core.io.inputs import FilterOptions, AutoPickParameter from pylot.core.pick.utils import getSNR, earllatepicker, getnoisewin, \ getResolutionWindow @@ -1272,14 +1273,21 @@ class PickDlg(QDialog): class TuneAutopicker(QWidget): update = QtCore.Signal(str) - + ''' + QWidget used to modifiy and test picking parameters for autopicking algorithm. + + :param: parent + :type: QtPyLoT Mainwindow + ''' def __init__(self, parent): QtGui.QWidget.__init__(self, parent, 1) self.parent = parent self.ap = parent._inputs self.fig_dict = parent.fig_dict + self.data = Data() self.init_main_layouts() self.init_eventlist() + self.init_stationlist() self.init_figure_tabs() self.add_parameter() self.add_buttons() @@ -1302,10 +1310,24 @@ class TuneAutopicker(QWidget): self.eventBox = self.parent.createEventBox() self.fill_eventbox() self.trace_layout.addWidget(self.eventBox) + self.eventBox.activated.connect(self.fill_stationbox) def init_stationlist(self): - pass - + self.stationBox = QtGui.QComboBox() + self.trace_layout.addWidget(self.stationBox) + + def fill_stationbox(self): + fnames = self.parent.getWFFnames_from_eventbox(eventbox=self.eventBox) + self.data.setWFData(fnames) + self.stationBox.clear() + stations = [] + for trace in self.data.getWFData(): + station = trace.stats.station + if not station in stations: + stations.append(str(station)) + for station in stations: + self.stationBox.addItem(str(station)) + def init_figure_tabs(self): self.main_tabs = QtGui.QTabWidget() self.p_tabs = QtGui.QTabWidget() From cae5c961b0c1b40934ab08c1ca5efe3cd65ba638 Mon Sep 17 00:00:00 2001 From: Marcel Paffrath Date: Mon, 15 May 2017 17:21:22 +0200 Subject: [PATCH 07/12] some fixes calling autopylot (figures=None), added log for autoTuner --- QtPyLoT.py | 11 ++- autoPyLoT.py | 21 +++-- pylot/RELEASE-VERSION | 2 +- pylot/core/io/inputs.py | 8 +- pylot/core/pick/autopick.py | 79 +++++++++++----- pylot/core/util/thread.py | 46 +++++++--- pylot/core/util/widgets.py | 178 ++++++++++++++++++++++++++---------- 7 files changed, 252 insertions(+), 93 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index c88c228f..398080bb 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -1181,6 +1181,7 @@ class MainWindow(QMainWindow): if not self.tap: self.tap = TuneAutopicker(self) + self.update_autopicker() self.tap.update.connect(self.update_autopicker) else: self.tap.fill_eventbox() @@ -1761,10 +1762,18 @@ class Project(object): return for item in eventlist: event = Event(item) - if not event in self.eventlist: + if not event.path in self.getPaths(): self.eventlist.append(event) + else: + print('Skipping event with path {}. Already part of project.'.format(event.path)) self.setDirty() + def getPaths(self): + paths = [] + for event in self.eventlist: + paths.append(event.path) + return paths + def setDirty(self): self.dirty = True diff --git a/autoPyLoT.py b/autoPyLoT.py index e66a6c04..cb075580 100755 --- a/autoPyLoT.py +++ b/autoPyLoT.py @@ -29,7 +29,7 @@ from pylot.core.util.version import get_git_version as _getVersionString __version__ = _getVersionString() -def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, savepath=None, iplot=0): +def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, savepath=None, station='all', iplot=0): """ Determine phase onsets automatically utilizing the automatic picking algorithms by Kueperkoch et al. 2010/2012. @@ -55,15 +55,20 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, save ***********************************'''.format(version=_getVersionString()) print(splash) + locflag = 1 if input_dict: if input_dict.has_key('parameter'): parameter = input_dict['parameter'] if input_dict.has_key('fig_dict'): fig_dict = input_dict['fig_dict'] + if input_dict.has_key('station'): + station = input_dict['station'] if input_dict.has_key('fnames'): fnames = input_dict['fnames'] if input_dict.has_key('iplot'): iplot = input_dict['iplot'] + if input_dict.has_key('locflag'): + locflag = input_dict['locflag'] if not parameter: if inputfile: @@ -103,8 +108,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, save datastructure.setExpandFields(exf) # check if default location routine NLLoc is available - if parameter['nllocbin']: - locflag = 1 + if parameter['nllocbin'] and locflag: # get NLLoc-root path nllocroot = parameter.get('nllocroot') # get path to NLLoc executable @@ -168,12 +172,17 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, save now.minute) parameter.setParam(eventID=evID) wfdat = data.getWFData() # all available streams + if not station == 'all': + wfdat = wfdat.select(station=station) + if not wfdat: + print('Could not find station {}. STOP!'.format(station)) + return wfdat = remove_underscores(wfdat) metadata = read_metadata(parameter.get('invdir')) corr_dat = restitute_data(wfdat.copy(), *metadata) - print('Working on event %s' % event) - print(data) + print('Working on event %s. Stations: %s' % (event, station)) + print(wfdat) ########################################################## # !automated picking starts here! picks = autopickevent(wfdat, parameter, iplot=iplot, fig_dict=fig_dict) @@ -243,7 +252,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, save print("autoPyLoT: Number of maximum iterations reached, stop iterative picking!") break print("autoPyLoT: Starting with iteration No. %d ..." % nlloccounter) - picks, _ = iteratepicker(wfdat, nllocfile, picks, badpicks, parameter) + picks = iteratepicker(wfdat, nllocfile, picks, badpicks, parameter, fig_dict=fig_dict) # write phases to NLLoc-phase file nll.export(picks, phasefile, parameter) # remove actual NLLoc-location file to keep only the last diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index d7fe7f2d..a434f915 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -4d9c-dirty +a2ab-dirty diff --git a/pylot/core/io/inputs.py b/pylot/core/io/inputs.py index 0c8c8a07..7500b2c5 100644 --- a/pylot/core/io/inputs.py +++ b/pylot/core/io/inputs.py @@ -186,11 +186,15 @@ class AutoPickParameter(object): if not is_type == expect_type and not is_type == tuple: message = 'Type check failed for param: {}, is type: {}, expected type:{}' message = message.format(param, is_type, expect_type) - raise TypeError(message) + print(Warning(message)) - def setParam(self, param, value): + def setParamKV(self, param, value): self.__setitem__(param, value) + def setParam(self, **kwargs): + for key in kwargs: + self.__setitem__(key, kwargs[key]) + @staticmethod def _printParameterError(errmsg): print('ParameterError:\n non-existent parameter %s' % errmsg) diff --git a/pylot/core/pick/autopick.py b/pylot/core/pick/autopick.py index dc36eb69..7dd8781a 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -233,6 +233,10 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): # get prelimenary onset time from AIC-HOS-CF using subclass AICPicker # of class AutoPicking key = 'aicFig' + if fig_dict: + fig = fig_dict[key] + else: + fig = None aicpick = AICPicker(aiccf, tsnrz, pickwinP, iplot, None, tsmoothP, fig=fig_dict[key]) ############################################################## if aicpick.getpick() is not None: @@ -248,10 +252,14 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): '{1}'.format(minsiglength, minsiglength / 2) if verbose: print(msg) key = 'slength' + if fig_dict: + fig = fig_dict[key] + else: + fig = None Pflag = checksignallength(zne, aicpick.getpick(), tsnrz, minsiglength / 2, nfacsl, minpercent, iplot, - fig_dict[key]) + fig) else: # filter and taper horizontal traces trH1_filt = edat.copy() @@ -266,11 +274,14 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): trH2_filt.taper(max_percentage=0.05, type='hann') zne += trH1_filt zne += trH2_filt - key = 'slength' + if fig_dict: + fig = fig_dict['slength'] + else: + fig = None Pflag = checksignallength(zne, aicpick.getpick(), tsnrz, minsiglength, nfacsl, minpercent, iplot, - fig_dict[key]) + fig) if Pflag == 1: # check for spuriously picked S onset @@ -281,9 +292,12 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): if verbose: print(msg) else: if iplot>1: - key = 'checkZ4s' + if fig_dict: + fig = fig_dict['checkZ4s'] + else: + fig = None Pflag = checkZ4S(zne, aicpick.getpick(), zfac, - tsnrz[3], iplot, fig_dict[key]) + tsnrz[3], iplot, fig) if Pflag == 0: Pmarker = 'SinsteadP' Pweight = 9 @@ -330,18 +344,24 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): 'correctly: maybe the algorithm name ({algoP}) is ' \ 'corrupted'.format( algoP=algoP) - key = 'refPpick' + if fig_dict: + fig = fig_dict['refPpick'] + else: + fig = None refPpick = PragPicker(cf2, tsnrz, pickwinP, iplot, ausP, tsmoothP, - aicpick.getpick(), fig_dict[key]) + aicpick.getpick(), fig) mpickP = refPpick.getpick() ############################################################# if mpickP is not None: # quality assessment # get earliest/latest possible pick and symmetrized uncertainty if iplot: - key = 'el_Ppick' + if fig_dict: + fig = fig_dict['el_Ppick'] + else: + fig = None epickP, lpickP, Perror = earllatepicker(z_copy, nfacP, tsnrz, - mpickP, iplot, fig=fig_dict[key]) + mpickP, iplot, fig=fig) else: epickP, lpickP, Perror = earllatepicker(z_copy, nfacP, tsnrz, mpickP, iplot) @@ -366,8 +386,11 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): # certain quality required if Pweight <= minfmweight and SNRP >= minFMSNR: if iplot: - key = 'fm_picker' - FM = fmpicker(zdat, z_copy, fmpickwin, mpickP, iplot, fig_dict[key]) + if fig_dict: + fig = fig_dict['fm_picker'] + else: + fig = None + FM = fmpicker(zdat, z_copy, fmpickwin, mpickP, iplot, fig) else: FM = fmpicker(zdat, z_copy, fmpickwin, mpickP, iplot) else: @@ -468,9 +491,12 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): ############################################################## # get prelimenary onset time from AIC-HOS-CF using subclass AICPicker # of class AutoPicking - key = 'aicARHfig' + if fig_dict: + fig = fig_dict['aicARHfig'] + else: + fig = None aicarhpick = AICPicker(haiccf, tsnrh, pickwinS, iplot, None, - aictsmoothS, fig = fig_dict[key]) + aictsmoothS, fig=fig) ############################################################### # go on with processing if AIC onset passes quality control if (aicarhpick.getSlope() >= minAICSslope and @@ -524,9 +550,12 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): addnoise) # instance of ARHcf # get refined onset time from CF2 using class Picker - key = 'refSpick' + if fig_dict: + fig = fig_dict['refSpick'] + else: + fig = None refSpick = PragPicker(arhcf2, tsnrh, pickwinS, iplot, ausS, - tsmoothS, aicarhpick.getpick(), fig_dict[key]) + tsmoothS, aicarhpick.getpick(), fig) mpickS = refSpick.getpick() ############################################################# if mpickS is not None: @@ -534,11 +563,14 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): # get earliest/latest possible pick and symmetrized uncertainty h_copy[0].data = trH1_filt.data if iplot: - key = 'el_S1pick' + if fig_dict: + fig = fig_dict['el_S1pick'] + else: + fig = None epickS1, lpickS1, Serror1 = earllatepicker(h_copy, nfacS, tsnrh, mpickS, iplot, - fig_dict[key]) + fig=fig) else: epickS1, lpickS1, Serror1 = earllatepicker(h_copy, nfacS, tsnrh, @@ -546,11 +578,14 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): h_copy[0].data = trH2_filt.data if iplot: - key = 'el_S2pick' + if fig_dict: + fig = fig_dict['el_S2pick'] + else: + fig = None epickS2, lpickS2, Serror2 = earllatepicker(h_copy, nfacS, tsnrh, mpickS, iplot, - fig_dict[key]) + fig=fig) else: epickS2, lpickS2, Serror2 = earllatepicker(h_copy, nfacS, tsnrh, @@ -841,7 +876,7 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None): return picks -def iteratepicker(wf, NLLocfile, picks, badpicks, pickparameter): +def iteratepicker(wf, NLLocfile, picks, badpicks, pickparameter, fig_dict=None): ''' Repicking of bad onsets. Uses theoretical onset times from NLLoc-location file. @@ -916,7 +951,7 @@ def iteratepicker(wf, NLLocfile, picks, badpicks, pickparameter): print("zfac: %f => %f" % (zfac_old, pickparameter.get('zfac'))) # repick station - newpicks, fig = autopickstation(wf2pick, pickparameter) + newpicks = autopickstation(wf2pick, pickparameter, fig_dict=fig_dict) # replace old dictionary with new one picks[badpicks[i][0]] = newpicks @@ -931,4 +966,4 @@ def iteratepicker(wf, NLLocfile, picks, badpicks, pickparameter): pickparameter.setParam(noisefactor=noisefactor_old) pickparameter.setParam(zfac=zfac_old) - return picks, fig + return picks diff --git a/pylot/core/util/thread.py b/pylot/core/util/thread.py index fc76081b..0b76dd1f 100644 --- a/pylot/core/util/thread.py +++ b/pylot/core/util/thread.py @@ -39,39 +39,57 @@ class AutoPickThread(QThread): class Thread(QThread): - def __init__(self, parent, func, arg=None, progressText=None): + message = Signal(str) + + def __init__(self, parent, func, arg=None, progressText=None, pb_widget=None, redirect_stdout=False): QThread.__init__(self, parent) self.func = func self.arg = arg self.progressText = progressText - self.pbdlg = None + self.pb_widget = pb_widget + self.redirect_stdout = redirect_stdout self.finished.connect(self.hideProgressbar) self.showProgressbar() def run(self): - if self.arg: - self.data = self.func(self.arg) - else: - self.data = self.func() + if self.redirect_stdout: + sys.stdout = self + try: + if self.arg: + self.data = self.func(self.arg) + else: + self.data = self.func() + self._executed = True + except Exception as e: + self._executed = False + self._executedError = e + print(e) + sys.stdout = sys.__stdout__ def __del__(self): self.wait() def showProgressbar(self): if self.progressText: - self.pbdlg = QDialog(self.parent()) - self.pbdlg.setModal(True) + if not self.pb_widget: + self.pb_widget = QDialog(self.parent()) + self.pb_widget.setWindowFlags(Qt.SplashScreen) + self.pb_widget.setModal(True) vl = QVBoxLayout() pb = QProgressBar() pb.setRange(0, 0) vl.addWidget(pb) vl.addWidget(QLabel(self.progressText)) - self.pbdlg.setLayout(vl) - self.pbdlg.setWindowFlags(Qt.SplashScreen) - self.pbdlg.show() + self.pb_widget.setLayout(vl) + self.pb_widget.show() def hideProgressbar(self): - if self.pbdlg: - self.pbdlg.hide() + if self.pb_widget: + self.pb_widget.hide() - + def write(self, text): + self.message.emit(text) + + def flush(self): + pass + diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 1a009b2a..03f82638 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -1289,11 +1289,14 @@ class TuneAutopicker(QWidget): self.init_eventlist() self.init_stationlist() self.init_figure_tabs() - self.add_parameter() + self.init_pbwidget() + self.add_parameters() self.add_buttons() + self.add_log() self.set_stretch() self.resize(1280, 720) - self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal) + self.figure_tabs.setCurrentIndex(0) + #self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal) #self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) def init_main_layouts(self): @@ -1309,12 +1312,15 @@ class TuneAutopicker(QWidget): def init_eventlist(self): self.eventBox = self.parent.createEventBox() self.fill_eventbox() + self.eventBox.setCurrentIndex(1) self.trace_layout.addWidget(self.eventBox) self.eventBox.activated.connect(self.fill_stationbox) + self.eventBox.activated.connect(self.update_eventID) def init_stationlist(self): self.stationBox = QtGui.QComboBox() self.trace_layout.addWidget(self.stationBox) + self.fill_stationbox() def fill_stationbox(self): fnames = self.parent.getWFFnames_from_eventbox(eventbox=self.eventBox) @@ -1325,19 +1331,23 @@ class TuneAutopicker(QWidget): station = trace.stats.station if not station in stations: stations.append(str(station)) + stations.sort() for station in stations: self.stationBox.addItem(str(station)) - - def init_figure_tabs(self): - self.main_tabs = QtGui.QTabWidget() - self.p_tabs = QtGui.QTabWidget() - self.s_tabs = QtGui.QTabWidget() - self.tune_layout.insertWidget(0, self.main_tabs) - self.init_tab_names() - def add_parameter(self): + def init_figure_tabs(self): + self.figure_tabs = QtGui.QTabWidget() + self.fill_figure_tabs() + + def init_pbwidget(self): + self.pb_widget = QtGui.QWidget() + + def add_parameters(self): self.parameters = AutoPickParaBox(self.ap) + self.parameters.set_tune_mode(True) + self.update_eventID() self.parameter_layout.addWidget(self.parameters) + self.parameter_layout.addWidget(self.pb_widget) self.tune_layout.insertLayout(1, self.parameter_layout) def add_buttons(self): @@ -1346,29 +1356,83 @@ class TuneAutopicker(QWidget): self.trace_layout.addWidget(self.pick_button) self.trace_layout.setStretch(0, 1) + def add_log(self): + self.listWidget = QtGui.QListWidget() + self.figure_tabs.insertTab(3, self.listWidget, 'log') + + def fill_figure_tabs(self): + self.p_tabs = QtGui.QTabWidget() + self.s_tabs = QtGui.QTabWidget() + self.tune_layout.insertWidget(0, self.figure_tabs) + self.init_tab_names() + def fill_eventbox(self): self.parent.fill_eventbox(self.eventBox, 'ref') + + def get_current_event(self): + return self.eventBox.currentText().split('/')[-1] + + def update_eventID(self): + self.parameters.boxes['eventID'].setText(self.get_current_event()) + + def add_log_item(self, text): + self.listWidget.addItem(text) + self.listWidget.scrollToBottom() def call_picker(self): - self.ap = self.update_params() + self.ap = self.params_from_gui() + station = str(self.stationBox.currentText()) + if not station: + self._warn('No station selected') + return args = {'parameter': self.ap, + 'station': station, 'fnames': 'None', 'iplot': 2, - 'fig_dict': self.fig_dict} - self.ap_thread = Thread(self, autoPyLoT, arg=args, progressText='Picking trace...') + 'fig_dict': self.fig_dict, + 'locflag': 0} + for key in self.fig_dict.keys(): + self.fig_dict[key].clear() + self.ap_thread = Thread(self, autoPyLoT, arg=args, + progressText='Picking trace...', pb_widget=self.pb_widget, + redirect_stdout=True) + self.enable(False) + self.ap_thread.message.connect(self.add_log_item) self.ap_thread.finished.connect(self.finish_picker) + self.figure_tabs.setCurrentIndex(3) self.ap_thread.start() #picks = autoPyLoT(self.ap, fnames='None', iplot=2, fig_dict=self.fig_dict) def finish_picker(self): + self.enable(True) + if not self.ap_thread._executed: + self._warn('Could not execute picker:\n{}'.format( + self.ap_thread._executedError)) + return self.picks = self.ap_thread.data - self.main_tabs.setParent(None) - self.init_figure_tabs() + if not self.picks: + self._warn('No picks found. See terminal output.') + return + #renew tabs + self.overview.setParent(None) + self.p_tabs.setParent(None) + self.s_tabs.setParent(None) + self.fill_figure_tabs() self.set_stretch() self.update.emit('Update') + self.figure_tabs.setCurrentIndex(0) - def update_params(self): - ap = self.parameters.update_params() + def enable(self, bool): + self.pick_button.setEnabled(bool) + self.parameters.setEnabled(bool) + self.eventBox.setEnabled(bool) + self.stationBox.setEnabled(bool) + self.overview.setEnabled(bool) + self.p_tabs.setEnabled(bool) + self.s_tabs.setEnabled(bool) + + def params_from_gui(self): + ap = self.parameters.params_from_gui() if self.parent: self.parent._inputs = ap return ap @@ -1382,10 +1446,11 @@ class TuneAutopicker(QWidget): self.stb_names = ['aicARHfig', 'refSpick', 'el_S1pick', 'el_S2pick'] def fill_tabs(self, canvas_dict): - id = self.main_tabs.addTab(self.gen_tab_widget('Overview', canvas_dict['mainFig']), 'Overview') - self.main_tabs.setTabEnabled(id, bool(self.fig_dict['mainFig'].axes)) - self.main_tabs.addTab(self.p_tabs, 'P') - self.main_tabs.addTab(self.s_tabs, 'S') + self.overview = self.gen_tab_widget('Overview', canvas_dict['mainFig']) + id = self.figure_tabs.insertTab(0, self.overview, 'Overview') + #self.figure_tabs.setTabEnabled(id, bool(self.fig_dict['mainFig'].axes)) + self.figure_tabs.insertTab(1, self.p_tabs, 'P') + self.figure_tabs.insertTab(2, self.s_tabs, 'S') self.fill_p_tabs(canvas_dict) self.fill_s_tabs(canvas_dict) try: @@ -1418,6 +1483,11 @@ class TuneAutopicker(QWidget): v_layout.addWidget(NavigationToolbar2QT(canvas, self)) widget.setLayout(v_layout) return widget + + def _warn(self, message): + self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning, + 'Warning', message) + self.qmb.show() class PropertiesDlg(QDialog): @@ -1701,6 +1771,7 @@ class AutoPickParaBox(QtGui.QWidget): self.setLayout(self.layout) self.add_main_parameters_tab() self.add_special_pick_parameters_tab() + self.params_to_gui() self._toggle_advanced_settings() def _init_sublayouts(self): @@ -1728,8 +1799,16 @@ class AutoPickParaBox(QtGui.QWidget): else: for b in box: b.setEnabled(enable) - - def init_boxes(self, parameter_names, defaults=False): + + def set_tune_mode(self, bool): + keys = ['rootpath', 'datapath', 'database', + 'eventID', 'invdir', 'nllocbin', + 'nllocroot', 'phasefile', + 'ctrfile', 'ttpatter', 'outpatter'] + for key in keys: + self.boxes[key].setEnabled(not(bool)) + + def init_boxes(self, parameter_names): grid = QtGui.QGridLayout() for index1, name in enumerate(parameter_names): @@ -1739,22 +1818,15 @@ class AutoPickParaBox(QtGui.QWidget): tooltip = default_item['tooltip'] tooltip += ' | type: {}'.format(default_item['type']) if not type(default_item['type']) == tuple: - if defaults: - value = default_item['value'] - else: - value = self.ap[name] typ = default_item['type'] - box = self.create_box(value, typ, tooltip) + box = self.create_box(typ, tooltip) self.boxes[name] = box elif type(default_item['type']) == tuple: boxes = [] - if defaults: - values = default_item['value'] - else: - values = self.ap[name] + values = self.ap[name] for index2, val in enumerate(values): typ = default_item['type'][index2] - boxes.append(self.create_box(val, typ, tooltip)) + boxes.append(self.create_box(typ, tooltip)) box = self.create_multi_box(boxes) self.boxes[name] = boxes label.setToolTip(tooltip) @@ -1762,25 +1834,15 @@ class AutoPickParaBox(QtGui.QWidget): grid.addWidget(box, index1, 2) return grid - def create_box(self, value, typ, tooltip): + def create_box(self, typ, tooltip): if typ == str: box = QtGui.QLineEdit() - box.setText(value) elif typ == float: box = QtGui.QDoubleSpinBox() - box.setMaximum(100*value) - box.setValue(value) elif typ == int: box = QtGui.QSpinBox() - box.setMaximum(100*value) - box.setValue(value) elif typ == bool: - if value == 'True': - value = True - if value == 'False': - value = False box = QtGui.QCheckBox() - box.setChecked(value) else: raise TypeError('Unrecognized type {}'.format(typ)) return box @@ -1847,14 +1909,37 @@ class AutoPickParaBox(QtGui.QWidget): if seperator: layout.addWidget(self.gen_h_seperator()) - def update_params(self): + def params_from_gui(self): for param in self.ap.get_all_para_names(): box = self.boxes[param] value = self.getValue(box) self.ap.checkValue(param, value) - self.ap.setParam(param, value) + self.ap.setParamKV(param, value) return self.ap + def params_to_gui(self): + for param in self.ap.get_all_para_names(): + box = self.boxes[param] + value = self.ap[param] + #self.ap.checkValue(param, value) + self.setValue(box, value) + + def setValue(self, box, value): + if type(box) == QtGui.QLineEdit: + box.setText(value) + elif type(box) == QtGui.QSpinBox or type(box) == QtGui.QDoubleSpinBox: + box.setMaximum(100*value) + box.setValue(value) + elif type(box) == QtGui.QCheckBox: + if value == 'True': + value = True + if value == 'False': + value = False + box.setChecked(value) + elif type(box) == list: + for index, b in enumerate(box): + self.setValue(b, value[index]) + def getValue(self, box): if type(box) == QtGui.QLineEdit: value = str(box.text()) @@ -1869,7 +1954,6 @@ class AutoPickParaBox(QtGui.QWidget): value = tuple(value) return value - class ParametersTab(PropTab): def __init__(self, parent=None, infile=None): super(ParametersTab, self).__init__(parent) From c9d872d52ba57533eba71b778465a6ff5e83d05c Mon Sep 17 00:00:00 2001 From: Marcel Paffrath Date: Mon, 15 May 2017 18:12:26 +0200 Subject: [PATCH 08/12] added load/save buttons for parameters --- pylot/RELEASE-VERSION | 2 +- pylot/core/io/inputs.py | 88 +++++++++++++++++++++----------------- pylot/core/util/widgets.py | 52 +++++++++++++++++++++- 3 files changed, 101 insertions(+), 41 deletions(-) diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index a434f915..7509fd8d 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -a2ab-dirty +cae5-dirty diff --git a/pylot/core/io/inputs.py b/pylot/core/io/inputs.py index 7500b2c5..40428633 100644 --- a/pylot/core/io/inputs.py +++ b/pylot/core/io/inputs.py @@ -47,47 +47,12 @@ class AutoPickParameter(object): self.__init_default_paras() self.__init_subsettings() self.__filename = fnin - parFileCont = {} + self._verbosity = verbosity + self._parFileCont = {} # io from parsed arguments alternatively for key, val in kwargs.items(): - parFileCont[key] = val - - if self.__filename is not None: - inputFile = open(self.__filename, 'r') - else: - return - try: - lines = inputFile.readlines() - for line in lines: - parspl = line.split('\t')[:2] - parFileCont[parspl[0].strip()] = parspl[1] - except IndexError as e: - if verbosity > 0: - self._printParameterError(e) - inputFile.seek(0) - lines = inputFile.readlines() - for line in lines: - if not line.startswith(('#', '%', '\n', ' ')): - parspl = line.split('#')[:2] - parFileCont[parspl[1].strip()] = parspl[0].strip() - for key, value in parFileCont.items(): - try: - val = int(value) - except: - try: - val = float(value) - except: - if len(value.split(' ')) > 1: - vallist = value.strip().split(' ') - val = [] - for val0 in vallist: - val0 = float(val0) - val.append(val0) - else: - val = str(value.strip()) - parFileCont[key] = val - self.__parameter = parFileCont - + self._parFileCont[key] = val + self.from_file() if fnout: self.export2File(fnout) @@ -199,6 +164,51 @@ class AutoPickParameter(object): def _printParameterError(errmsg): print('ParameterError:\n non-existent parameter %s' % errmsg) + def reset_defaults(self): + defaults = self.get_defaults() + for param in defaults: + self.setParamKV(param, defaults[param]['value']) + + def from_file(self, fnin=None): + if not fnin: + if self.__filename is not None: + fnin = self.__filename + else: + return + + inputFile = open(fnin, 'r') + try: + lines = inputFile.readlines() + for line in lines: + parspl = line.split('\t')[:2] + self._parFileCont[parspl[0].strip()] = parspl[1] + except IndexError as e: + if self._verbosity > 0: + self._printParameterError(e) + inputFile.seek(0) + lines = inputFile.readlines() + for line in lines: + if not line.startswith(('#', '%', '\n', ' ')): + parspl = line.split('#')[:2] + self._parFileCont[parspl[1].strip()] = parspl[0].strip() + for key, value in self._parFileCont.items(): + try: + val = int(value) + except: + try: + val = float(value) + except: + if len(value.split(' ')) > 1: + vallist = value.strip().split(' ') + val = [] + for val0 in vallist: + val0 = float(val0) + val.append(val0) + else: + val = str(value.strip()) + self._parFileCont[key] = val + self.__parameter = self._parFileCont + def export2File(self, fnout): fid_out = open(fnout, 'w') lines = [] diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 03f82638..ccb0afc0 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -1764,7 +1764,8 @@ class AutoPickParaBox(QtGui.QWidget): QtGui.QWidget.__init__(self, parent) self.ap = ap self.tabs = QtGui.QTabWidget() - self.layout = QtGui.QHBoxLayout() + self.layout = QtGui.QVBoxLayout() + self._init_buttons() self.layout.addWidget(self.tabs) self.boxes = {} self._init_sublayouts() @@ -1778,6 +1779,19 @@ class AutoPickParaBox(QtGui.QWidget): self._main_layout = QtGui.QVBoxLayout() self._advanced_layout = QtGui.QVBoxLayout() self._create_advanced_cb() + + def _init_buttons(self): + self._buttons_layout = QtGui.QHBoxLayout() + self.loadButton = QtGui.QPushButton('&Load settings') + self.saveButton = QtGui.QPushButton('&Save settings') + self.defaultsButton = QtGui.QPushButton('&Defaults') + self._buttons_layout.addWidget(self.loadButton) + self._buttons_layout.addWidget(self.saveButton) + self._buttons_layout.addWidget(self.defaultsButton) + self.layout.addLayout(self._buttons_layout) + self.loadButton.clicked.connect(self.openFile) + self.saveButton.clicked.connect(self.saveFile) + self.defaultsButton.clicked.connect(self.restoreDefaults) def _create_advanced_cb(self): self._advanced_cb = QtGui.QCheckBox('Enable Advanced Settings') @@ -1954,6 +1968,42 @@ class AutoPickParaBox(QtGui.QWidget): value = tuple(value) return value + def openFile(self): + fd = QtGui.QFileDialog() + fname = fd.getOpenFileName(self, 'Browse for settings file.', '*.in') + if fname[0]: + try: + self.ap.from_file(fname[0]) + self.params_to_gui() + except Exception as e: + self._warn('Could not open file {}:\n{}'.format(fname[0], e)) + return + + def saveFile(self): + fd = QtGui.QFileDialog() + fname = fd.getSaveFileName(self, 'Browse for settings file.', '*.in') + if fname[0]: + try: + self.params_from_gui() + self.ap.export2File(fname[0]) + except Exception as e: + self._warn('Could not save file {}:\n{}'.format(fname[0], e)) + return + + def restoreDefaults(self): + try: + self.ap.reset_defaults() + self.params_to_gui() + except Exception as e: + self._warn('Could not restore defaults:\n{}'.format(e)) + return + + def _warn(self, message): + self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning, + 'Warning', message) + self.qmb.show() + + class ParametersTab(PropTab): def __init__(self, parent=None, infile=None): super(ParametersTab, self).__init__(parent) From f43611aeda60f00a539d609ce57bbebfabb6c07e Mon Sep 17 00:00:00 2001 From: Marcel Paffrath Date: Tue, 16 May 2017 13:41:35 +0200 Subject: [PATCH 09/12] added pickdlg to tune autopick, small fixes; to do: add manual picks --- QtPyLoT.py | 36 +- pylot/RELEASE-VERSION | 2 +- pylot/core/util/map_projection.py | 5 +- pylot/core/util/thread.py | 10 +- pylot/core/util/widgets.py | 781 ++++++++++++++++-------------- 5 files changed, 453 insertions(+), 381 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 398080bb..cea5f9f1 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -604,9 +604,10 @@ class MainWindow(QMainWindow): def getCurrentEvent(self, eventlist=None, eventbox=None): if not eventlist: eventlist = self.project.eventlist - for event in eventlist: - if event.path == self.getCurrentEventPath(eventbox): - return event + if not eventbox: + eventbox = self.eventBox + index = eventbox.currentIndex() + return eventbox.itemData(index) def getCurrentEventPath(self, eventbox=None): if not eventbox: @@ -684,7 +685,7 @@ class MainWindow(QMainWindow): if pl > plmax: plmax=pl - for event in self.project.eventlist: + for index, event in enumerate(self.project.eventlist): event_path = event.path event_npicks = 0 event_nautopicks = 0 @@ -695,11 +696,11 @@ class MainWindow(QMainWindow): event_ref = event.isRefEvent() event_test = event.isTestEvent() - text = '{path:{plen}} | manual: [{p:3d}] | auto: [{a:3d}]' - text = text.format(path=event_path, - plen=plmax, - p=event_npicks, - a=event_nautopicks) + # text = '{path:{plen}} | manual: [{p:3d}] | auto: [{a:3d}]' + # text = text.format(path=event_path, + # plen=plmax, + # p=event_npicks, + # a=event_nautopicks) item_path = QtGui.QStandardItem('{path:{plen}}'.format(path=event_path, plen=plmax)) item_nmp = QtGui.QStandardItem(str(event_npicks)) @@ -732,6 +733,12 @@ class MainWindow(QMainWindow): for item in itemlist: item.setEnabled(False) model.appendRow(itemlist) + if not event.path == self.eventBox.itemText(index): + message = ('Path missmatch creating eventbox.\n' + '{} unequal {}.' + .format(event.path, self.eventBox.itemText(index))) + raise ValueError(message) + eventBox.setItemData(index, event) eventBox.setCurrentIndex(index) def filename_from_action(self, action): @@ -929,7 +936,8 @@ class MainWindow(QMainWindow): self._eventChanged[0] = False def loadWaveformDataThread(self): - wfd_thread = Thread(self, self.loadWaveformData, progressText='Reading data input...') + wfd_thread = Thread(self, self.loadWaveformData, + progressText='Reading data input...') wfd_thread.finished.connect(self.plotWaveformDataThread) wfd_thread.start() @@ -999,7 +1007,8 @@ class MainWindow(QMainWindow): self.draw() def plotWaveformDataThread(self): - wfp_thread = Thread(self, self.plotWaveformData, progressText='Plotting waveform data...') + wfp_thread = Thread(self, self.plotWaveformData, + progressText='Plotting waveform data...') wfp_thread.finished.connect(self.finishWaveformDataPlot) wfp_thread.start() @@ -1131,7 +1140,7 @@ class MainWindow(QMainWindow): station = self.getStationName(wfID) self.update_status('picking on station {0}'.format(station)) data = self.get_data().getWFData() - pickDlg = PickDlg(self, infile=self.getinfile(), + pickDlg = PickDlg(self, parameter=self._inputs, data=data.select(station=station), station=station, picks=self.getPicksOnStation(station, 'manual'), @@ -1183,6 +1192,7 @@ class MainWindow(QMainWindow): self.tap = TuneAutopicker(self) self.update_autopicker() self.tap.update.connect(self.update_autopicker) + self.tap.figure_tabs.setCurrentIndex(0) else: self.tap.fill_eventbox() self.tap.show() @@ -1190,7 +1200,7 @@ class MainWindow(QMainWindow): def update_autopicker(self): for key in self.fig_dict.keys(): self.canvas_dict[key] = FigureCanvas(self.fig_dict[key]) - self.tap.fill_tabs(self.canvas_dict) + self.tap.fill_tabs(picked=True) def autoPick(self): self.autosave = QFileDialog().getExistingDirectory(caption='Select autoPyLoT output') diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index 7509fd8d..e808bed5 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -cae5-dirty +c9d8-dirty diff --git a/pylot/core/util/map_projection.py b/pylot/core/util/map_projection.py index 29a2cf7e..b539aea7 100644 --- a/pylot/core/util/map_projection.py +++ b/pylot/core/util/map_projection.py @@ -38,13 +38,14 @@ class map_projection(QtGui.QWidget): def onpick(self, event): ind = event.ind - if ind == []: + button = event.mouseevent.button + if ind == [] or not button == 1: return data = self._parent.get_data().getWFData() for index in ind: station=str(self.station_names[index]) try: - pickDlg = PickDlg(self, infile=self._parent.getinfile(), + pickDlg = PickDlg(self, parameter=self._parent._inputs, data=data.select(station=station), station=station, picks=self._parent.getPicksOnStation(station, 'manual'), diff --git a/pylot/core/util/thread.py b/pylot/core/util/thread.py index 0b76dd1f..859740a8 100644 --- a/pylot/core/util/thread.py +++ b/pylot/core/util/thread.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import sys from PySide.QtCore import QThread, Signal, Qt -from PySide.QtGui import QDialog, QProgressBar, QLabel, QVBoxLayout +from PySide.QtGui import QDialog, QProgressBar, QLabel, QHBoxLayout class AutoPickThread(QThread): @@ -75,12 +75,12 @@ class Thread(QThread): self.pb_widget = QDialog(self.parent()) self.pb_widget.setWindowFlags(Qt.SplashScreen) self.pb_widget.setModal(True) - vl = QVBoxLayout() + hl = QHBoxLayout() pb = QProgressBar() pb.setRange(0, 0) - vl.addWidget(pb) - vl.addWidget(QLabel(self.progressText)) - self.pb_widget.setLayout(vl) + hl.addWidget(pb) + hl.addWidget(QLabel(self.progressText)) + self.pb_widget.setLayout(hl) self.pb_widget.show() def hideProgressbar(self): diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index ccb0afc0..18e54f9b 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -516,11 +516,12 @@ class WaveformWidget(FigureCanvas): class PickDlg(QDialog): def __init__(self, parent=None, data=None, station=None, picks=None, - autopicks=None, rotate=False, infile=None): + autopicks=None, rotate=False, parameter=None, buttons=True): super(PickDlg, self).__init__(parent) # initialize attributes - self.infile = infile + self.parameter = parameter + self._buttons = buttons self.station = station self.rotate = rotate self.components = 'ZNE' @@ -661,7 +662,8 @@ class PickDlg(QDialog): QDialogButtonBox.Cancel) # merge widgets and layouts to establish the dialog - _innerlayout.addWidget(_buttonbox) + if self._buttons: + _innerlayout.addWidget(_buttonbox) _outerlayout.addWidget(_dialtoolbar) _outerlayout.addLayout(_innerlayout) @@ -773,8 +775,8 @@ class PickDlg(QDialog): self.cidrelease = self.connectReleaseEvent(self.panRelease) self.cidscroll = self.connectScrollEvent(self.scrollZoom) - def getinfile(self): - return self.infile + def getParameter(self): + return self.parameter def getStartTime(self): return self.stime @@ -899,7 +901,7 @@ class PickDlg(QDialog): def setIniPickP(self, gui_event, wfdata, trace_number): - parameter = AutoPickParameter(self.getinfile()) + parameter = self.parameter ini_pick = gui_event.xdata nfac = parameter.get('nfacP') @@ -948,7 +950,7 @@ class PickDlg(QDialog): def setIniPickS(self, gui_event, wfdata): - parameter = AutoPickParameter(self.getinfile()) + parameter = self.parameter ini_pick = gui_event.xdata nfac = parameter.get('nfacS') @@ -1002,7 +1004,7 @@ class PickDlg(QDialog): def setPick(self, gui_event): - parameter = AutoPickParameter(self.getinfile()) + parameter = self.parameter # get axes limits self.updateCurrentLimits() @@ -1282,20 +1284,21 @@ class TuneAutopicker(QWidget): def __init__(self, parent): QtGui.QWidget.__init__(self, parent, 1) self.parent = parent - self.ap = parent._inputs + self.setParent(parent) + self.parameter = parent._inputs self.fig_dict = parent.fig_dict self.data = Data() self.init_main_layouts() self.init_eventlist() - self.init_stationlist() self.init_figure_tabs() + self.init_stationlist() self.init_pbwidget() + self.connect_signals() self.add_parameters() self.add_buttons() self.add_log() self.set_stretch() self.resize(1280, 720) - self.figure_tabs.setCurrentIndex(0) #self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal) #self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) @@ -1312,16 +1315,21 @@ class TuneAutopicker(QWidget): def init_eventlist(self): self.eventBox = self.parent.createEventBox() self.fill_eventbox() - self.eventBox.setCurrentIndex(1) + self.eventBox.setCurrentIndex(0) self.trace_layout.addWidget(self.eventBox) - self.eventBox.activated.connect(self.fill_stationbox) - self.eventBox.activated.connect(self.update_eventID) - + def init_stationlist(self): self.stationBox = QtGui.QComboBox() self.trace_layout.addWidget(self.stationBox) self.fill_stationbox() + self.figure_tabs.setCurrentIndex(0) + def connect_signals(self): + self.eventBox.activated.connect(self.fill_stationbox) + self.eventBox.activated.connect(self.update_eventID) + self.eventBox.activated.connect(self.fill_tabs) + self.stationBox.activated.connect(self.fill_tabs) + def fill_stationbox(self): fnames = self.parent.getWFFnames_from_eventbox(eventbox=self.eventBox) self.data.setWFData(fnames) @@ -1342,8 +1350,12 @@ class TuneAutopicker(QWidget): def init_pbwidget(self): self.pb_widget = QtGui.QWidget() + def init_tab_names(self): + self.ptb_names = ['aicFig', 'slength', 'checkZ4s', 'refPpick', 'el_Ppick', 'fm_picker'] + self.stb_names = ['aicARHfig', 'refSpick', 'el_S1pick', 'el_S2pick'] + def add_parameters(self): - self.parameters = AutoPickParaBox(self.ap) + self.parameters = AutoPickParaBox(self.parameter) self.parameters.set_tune_mode(True) self.update_eventID() self.parameter_layout.addWidget(self.parameters) @@ -1358,105 +1370,66 @@ class TuneAutopicker(QWidget): def add_log(self): self.listWidget = QtGui.QListWidget() - self.figure_tabs.insertTab(3, self.listWidget, 'log') + self.figure_tabs.insertTab(4, self.listWidget, 'log') - def fill_figure_tabs(self): - self.p_tabs = QtGui.QTabWidget() - self.s_tabs = QtGui.QTabWidget() - self.tune_layout.insertWidget(0, self.figure_tabs) - self.init_tab_names() - - def fill_eventbox(self): - self.parent.fill_eventbox(self.eventBox, 'ref') - - def get_current_event(self): - return self.eventBox.currentText().split('/')[-1] - - def update_eventID(self): - self.parameters.boxes['eventID'].setText(self.get_current_event()) - def add_log_item(self, text): self.listWidget.addItem(text) self.listWidget.scrollToBottom() - def call_picker(self): - self.ap = self.params_from_gui() - station = str(self.stationBox.currentText()) - if not station: - self._warn('No station selected') - return - args = {'parameter': self.ap, - 'station': station, - 'fnames': 'None', - 'iplot': 2, - 'fig_dict': self.fig_dict, - 'locflag': 0} - for key in self.fig_dict.keys(): - self.fig_dict[key].clear() - self.ap_thread = Thread(self, autoPyLoT, arg=args, - progressText='Picking trace...', pb_widget=self.pb_widget, - redirect_stdout=True) - self.enable(False) - self.ap_thread.message.connect(self.add_log_item) - self.ap_thread.finished.connect(self.finish_picker) - self.figure_tabs.setCurrentIndex(3) - self.ap_thread.start() - #picks = autoPyLoT(self.ap, fnames='None', iplot=2, fig_dict=self.fig_dict) - - def finish_picker(self): - self.enable(True) - if not self.ap_thread._executed: - self._warn('Could not execute picker:\n{}'.format( - self.ap_thread._executedError)) - return - self.picks = self.ap_thread.data - if not self.picks: - self._warn('No picks found. See terminal output.') - return - #renew tabs - self.overview.setParent(None) - self.p_tabs.setParent(None) - self.s_tabs.setParent(None) - self.fill_figure_tabs() - self.set_stretch() - self.update.emit('Update') - self.figure_tabs.setCurrentIndex(0) - - def enable(self, bool): - self.pick_button.setEnabled(bool) - self.parameters.setEnabled(bool) - self.eventBox.setEnabled(bool) - self.stationBox.setEnabled(bool) - self.overview.setEnabled(bool) - self.p_tabs.setEnabled(bool) - self.s_tabs.setEnabled(bool) + def get_current_event(self): + index = self.eventBox.currentIndex() + return self.eventBox.itemData(index) - def params_from_gui(self): - ap = self.parameters.params_from_gui() - if self.parent: - self.parent._inputs = ap - return ap + def get_current_event_name(self): + return self.eventBox.currentText().split('/')[-1] - def set_stretch(self): - self.tune_layout.setStretch(0, 3) - self.tune_layout.setStretch(1, 1) + def get_current_event_fp(self): + return self.eventBox.currentText() - def init_tab_names(self): - self.ptb_names = ['aicFig', 'slength', 'checkZ4s', 'refPpick', 'el_Ppick', 'fm_picker'] - self.stb_names = ['aicARHfig', 'refSpick', 'el_S1pick', 'el_S2pick'] + def get_current_station(self): + return str(self.stationBox.currentText()) + + def gen_tab_widget(self, name, canvas): + widget = QtGui.QWidget() + v_layout = QtGui.QVBoxLayout() + v_layout.addWidget(canvas) + v_layout.addWidget(NavigationToolbar2QT(canvas, self)) + widget.setLayout(v_layout) + return widget - def fill_tabs(self, canvas_dict): + def gen_pick_dlg(self): + station = self.get_current_station() + data = self.data.getWFData() + pickDlg = PickDlg(self, data=data.select(station=station), + station=station, parameter=self.parameter, + picks=self.get_current_event().picks, + autopicks=self.get_current_event().autopicks, + buttons=False) + self.pickDlg = QtGui.QWidget() + hl = QtGui.QHBoxLayout() + self.pickDlg.setLayout(hl) + hl.addWidget(pickDlg) + + def fill_tabs(self, event=None, picked=False): + self.clear_all() + canvas_dict = self.parent.canvas_dict + self.gen_pick_dlg() self.overview = self.gen_tab_widget('Overview', canvas_dict['mainFig']) - id = self.figure_tabs.insertTab(0, self.overview, 'Overview') - #self.figure_tabs.setTabEnabled(id, bool(self.fig_dict['mainFig'].axes)) - self.figure_tabs.insertTab(1, self.p_tabs, 'P') - self.figure_tabs.insertTab(2, self.s_tabs, 'S') - self.fill_p_tabs(canvas_dict) - self.fill_s_tabs(canvas_dict) + id0 = self.figure_tabs.insertTab(0, self.pickDlg, 'Traces Plot') + id1 = self.figure_tabs.insertTab(1, self.overview, 'Overview') + id2 = self.figure_tabs.insertTab(2, self.p_tabs, 'P') + id3 = self.figure_tabs.insertTab(3, self.s_tabs, 'S') + if picked: + self.fill_p_tabs(canvas_dict) + self.fill_s_tabs(canvas_dict) + self.toggle_autopickTabs(bool(self.fig_dict['mainFig'].axes)) + else: + self.disable_autopickTabs() try: main_fig.tight_layout() except: pass + self.figure_tabs.setCurrentIndex(0) def fill_p_tabs(self, canvas_dict): for name in self.ptb_names: @@ -1476,20 +1449,360 @@ class TuneAutopicker(QWidget): except: pass - def gen_tab_widget(self, name, canvas): - widget = QtGui.QWidget() - v_layout = QtGui.QVBoxLayout() - v_layout.addWidget(canvas) - v_layout.addWidget(NavigationToolbar2QT(canvas, self)) - widget.setLayout(v_layout) - return widget + def fill_figure_tabs(self): + self.clear_all() + self.p_tabs = QtGui.QTabWidget() + self.s_tabs = QtGui.QTabWidget() + self.tune_layout.insertWidget(0, self.figure_tabs) + self.init_tab_names() + def fill_eventbox(self): + self.parent.fill_eventbox(self.eventBox, 'ref') + + def update_eventID(self): + self.parameters.boxes['eventID'].setText( + self.get_current_event_name()) + self.figure_tabs.setCurrentIndex(0) + + def call_picker(self): + self.parameter = self.params_from_gui() + station = self.get_current_station() + if not station: + self._warn('No station selected') + return + args = {'parameter': self.parameter, + 'station': station, + 'fnames': 'None', + 'iplot': 2, + 'fig_dict': self.fig_dict, + 'locflag': 0} + for key in self.fig_dict.keys(): + self.fig_dict[key].clear() + self.ap_thread = Thread(self, autoPyLoT, arg=args, + progressText='Picking trace...', + pb_widget=self.pb_widget, + redirect_stdout=True) + self.enable(False) + self.ap_thread.message.connect(self.add_log_item) + self.ap_thread.finished.connect(self.finish_picker) + self.figure_tabs.setCurrentIndex(4) + self.ap_thread.start() + #picks = autoPyLoT(self.parameter, fnames='None', iplot=2, fig_dict=self.fig_dict) + + def finish_picker(self): + self.enable(True) + if not self.ap_thread._executed: + self._warn('Could not execute picker:\n{}'.format( + self.ap_thread._executedError)) + return + self.picks = self.ap_thread.data + if not self.picks: + self._warn('No picks found. See terminal output.') + return + #renew tabs + #self.fill_figure_tabs() + self.set_stretch() + self.update.emit('Update') + self.figure_tabs.setCurrentIndex(1) + + def enable(self, bool): + self.pick_button.setEnabled(bool) + self.parameters.setEnabled(bool) + self.eventBox.setEnabled(bool) + self.stationBox.setEnabled(bool) + self.overview.setEnabled(bool) + self.p_tabs.setEnabled(bool) + self.s_tabs.setEnabled(bool) + + def params_from_gui(self): + parameters = self.parameters.params_from_gui() + if self.parent: + self.parent._inputs = parameters + return parameters + + def set_stretch(self): + self.tune_layout.setStretch(0, 3) + self.tune_layout.setStretch(1, 1) + + def clear_all(self): + if hasattr(self, 'pickDlg'): + self.pickDlg.setParent(None) + del(self.pickDlg) + if hasattr(self, 'overview'): + self.overview.setParent(None) + if hasattr(self, 'p_tabs'): + self.p_tabs.clear() + self.p_tabs.setParent(None) + if hasattr(self, 's_tabs'): + self.s_tabs.clear() + self.s_tabs.setParent(None) + + def disable_autopickTabs(self): + self.toggle_autopickTabs(False) + + def toggle_autopickTabs(self, bool): + self.figure_tabs.setTabEnabled(1, bool) + self.figure_tabs.setTabEnabled(2, bool) + self.figure_tabs.setTabEnabled(3, bool) + def _warn(self, message): self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning, 'Warning', message) self.qmb.show() +class AutoPickParaBox(QtGui.QWidget): + def __init__(self, parameter, parent=None): + ''' + Generate Widget containing parameters for automatic picking algorithm. + + :param: parameter + :type: AutoPickParameter (object) + + ''' + QtGui.QWidget.__init__(self, parent) + self.parameter = parameter + self.tabs = QtGui.QTabWidget() + self.layout = QtGui.QVBoxLayout() + self._init_buttons() + self.layout.addWidget(self.tabs) + self.boxes = {} + self._init_sublayouts() + self.setLayout(self.layout) + self.add_main_parameters_tab() + self.add_special_pick_parameters_tab() + self.params_to_gui() + self._toggle_advanced_settings() + + def _init_sublayouts(self): + self._main_layout = QtGui.QVBoxLayout() + self._advanced_layout = QtGui.QVBoxLayout() + self._create_advanced_cb() + + def _init_buttons(self): + self._buttons_layout = QtGui.QHBoxLayout() + self.loadButton = QtGui.QPushButton('&Load settings') + self.saveButton = QtGui.QPushButton('&Save settings') + self.defaultsButton = QtGui.QPushButton('&Defaults') + self._buttons_layout.addWidget(self.loadButton) + self._buttons_layout.addWidget(self.saveButton) + self._buttons_layout.addWidget(self.defaultsButton) + self.layout.addLayout(self._buttons_layout) + self.loadButton.clicked.connect(self.openFile) + self.saveButton.clicked.connect(self.saveFile) + self.defaultsButton.clicked.connect(self.restoreDefaults) + + def _create_advanced_cb(self): + self._advanced_cb = QtGui.QCheckBox('Enable Advanced Settings') + self._advanced_layout.addWidget(self._advanced_cb) + self._advanced_cb.toggled.connect(self._toggle_advanced_settings) + + def _toggle_advanced_settings(self): + if self._advanced_cb.isChecked(): + self._enable_advanced(True) + else: + self._enable_advanced(False) + + def _enable_advanced(self, enable): + for lst in self.parameter.get_special_para_names().values(): + for param in lst: + box = self.boxes[param] + if type(box) is not list: + box.setEnabled(enable) + else: + for b in box: + b.setEnabled(enable) + + def set_tune_mode(self, bool): + keys = ['rootpath', 'datapath', 'database', + 'eventID', 'invdir', 'nllocbin', + 'nllocroot', 'phasefile', + 'ctrfile', 'ttpatter', 'outpatter'] + for key in keys: + self.boxes[key].setEnabled(not(bool)) + + def init_boxes(self, parameter_names): + grid = QtGui.QGridLayout() + + for index1, name in enumerate(parameter_names): + text = name + ' [?]' + label = QtGui.QLabel(text) + default_item = self.parameter.get_defaults()[name] + tooltip = default_item['tooltip'] + tooltip += ' | type: {}'.format(default_item['type']) + if not type(default_item['type']) == tuple: + typ = default_item['type'] + box = self.create_box(typ, tooltip) + self.boxes[name] = box + elif type(default_item['type']) == tuple: + boxes = [] + values = self.parameter[name] + for index2, val in enumerate(values): + typ = default_item['type'][index2] + boxes.append(self.create_box(typ, tooltip)) + box = self.create_multi_box(boxes) + self.boxes[name] = boxes + label.setToolTip(tooltip) + grid.addWidget(label, index1, 1) + grid.addWidget(box, index1, 2) + return grid + + def create_box(self, typ, tooltip): + if typ == str: + box = QtGui.QLineEdit() + elif typ == float: + box = QtGui.QDoubleSpinBox() + elif typ == int: + box = QtGui.QSpinBox() + elif typ == bool: + box = QtGui.QCheckBox() + else: + raise TypeError('Unrecognized type {}'.format(typ)) + return box + + def create_multi_box(self, boxes): + box = QtGui.QWidget() + hl = QtGui.QHBoxLayout() + for b in boxes: + hl.addWidget(b) + box.setLayout(hl) + return box + + def add_tab(self, layout, name): + widget = QtGui.QWidget() + scrollA = QtGui.QScrollArea() + scrollA.setWidgetResizable(True) + scrollA.setWidget(widget) + + widget.setLayout(layout) + + self.tabs.addTab(scrollA, name) + + def add_main_parameters_tab(self): + self.add_to_layout(self._main_layout, 'Directories', + self.parameter.get_main_para_names()['dirs']) + self.add_to_layout(self._main_layout, 'NLLoc', + self.parameter.get_main_para_names()['nlloc']) + self.add_to_layout(self._main_layout, 'Seismic Moment', + self.parameter.get_main_para_names()['smoment']) + self.add_to_layout(self._main_layout, 'Focal Mechanism', + self.parameter.get_main_para_names()['focmec']) + self.add_to_layout(self._main_layout, 'Pick Settings', + self.parameter.get_main_para_names()['pick'], + False) + self.add_tab(self._main_layout, 'Main Settings') + + def add_special_pick_parameters_tab(self): + self.add_to_layout(self._advanced_layout, 'Z-component', + self.parameter.get_special_para_names()['z']) + self.add_to_layout(self._advanced_layout, 'H-components', + self.parameter.get_special_para_names()['h']) + self.add_to_layout(self._advanced_layout, 'First-motion picker', + self.parameter.get_special_para_names()['fm']) + self.add_to_layout(self._advanced_layout, 'Quality assessment', + self.parameter.get_special_para_names()['quality'], + False) + self.add_tab(self._advanced_layout, 'Advanced Settings') + + def gen_h_seperator(self): + seperator = QtGui.QFrame() + seperator.setFrameShape(QtGui.QFrame.HLine) + return seperator + + def gen_headline(self, text): + label=QtGui.QLabel(text) + font=QtGui.QFont() + font.setBold(True) + label.setFont(font) + return label + + def add_to_layout(self, layout, name, items, seperator=True): + layout.addWidget(self.gen_headline(name)) + layout.addLayout(self.init_boxes(items)) + if seperator: + layout.addWidget(self.gen_h_seperator()) + + def params_from_gui(self): + for param in self.parameter.get_all_para_names(): + box = self.boxes[param] + value = self.getValue(box) + self.parameter.checkValue(param, value) + self.parameter.setParamKV(param, value) + return self.parameter + + def params_to_gui(self): + for param in self.parameter.get_all_para_names(): + box = self.boxes[param] + value = self.parameter[param] + #self.parameter.checkValue(param, value) + self.setValue(box, value) + + def setValue(self, box, value): + if type(box) == QtGui.QLineEdit: + box.setText(value) + elif type(box) == QtGui.QSpinBox or type(box) == QtGui.QDoubleSpinBox: + box.setMaximum(100*value) + box.setValue(value) + elif type(box) == QtGui.QCheckBox: + if value == 'True': + value = True + if value == 'False': + value = False + box.setChecked(value) + elif type(box) == list: + for index, b in enumerate(box): + self.setValue(b, value[index]) + + def getValue(self, box): + if type(box) == QtGui.QLineEdit: + value = str(box.text()) + elif type(box) == QtGui.QSpinBox or type(box) == QtGui.QDoubleSpinBox: + value = box.value() + elif type(box) == QtGui.QCheckBox: + value = box.isChecked() + elif type(box) == list: + value = [] + for b in box: + value.append(self.getValue(b)) + value = tuple(value) + return value + + def openFile(self): + fd = QtGui.QFileDialog() + fname = fd.getOpenFileName(self, 'Browse for settings file.', '*.in') + if fname[0]: + try: + self.parameter.from_file(fname[0]) + self.params_to_gui() + except Exception as e: + self._warn('Could not open file {}:\n{}'.format(fname[0], e)) + return + + def saveFile(self): + fd = QtGui.QFileDialog() + fname = fd.getSaveFileName(self, 'Browse for settings file.', '*.in') + if fname[0]: + try: + self.params_from_gui() + self.parameter.export2File(fname[0]) + except Exception as e: + self._warn('Could not save file {}:\n{}'.format(fname[0], e)) + return + + def restoreDefaults(self): + try: + self.parameter.reset_defaults() + self.params_to_gui() + except Exception as e: + self._warn('Could not restore defaults:\n{}'.format(e)) + return + + def _warn(self, message): + self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning, + 'Warning', message) + self.qmb.show() + + class PropertiesDlg(QDialog): def __init__(self, parent=None, infile=None): super(PropertiesDlg, self).__init__(parent) @@ -1752,258 +2065,6 @@ class LocalisationTab(PropTab): "nll/binPath": self.binedit.setText("%s" % nllocbin)} -class AutoPickParaBox(QtGui.QWidget): - def __init__(self, ap, parent=None): - ''' - Generate Widget containing parameters for automatic picking algorithm. - - :param: ap - :type: AutoPickParameter (object) - - ''' - QtGui.QWidget.__init__(self, parent) - self.ap = ap - self.tabs = QtGui.QTabWidget() - self.layout = QtGui.QVBoxLayout() - self._init_buttons() - self.layout.addWidget(self.tabs) - self.boxes = {} - self._init_sublayouts() - self.setLayout(self.layout) - self.add_main_parameters_tab() - self.add_special_pick_parameters_tab() - self.params_to_gui() - self._toggle_advanced_settings() - - def _init_sublayouts(self): - self._main_layout = QtGui.QVBoxLayout() - self._advanced_layout = QtGui.QVBoxLayout() - self._create_advanced_cb() - - def _init_buttons(self): - self._buttons_layout = QtGui.QHBoxLayout() - self.loadButton = QtGui.QPushButton('&Load settings') - self.saveButton = QtGui.QPushButton('&Save settings') - self.defaultsButton = QtGui.QPushButton('&Defaults') - self._buttons_layout.addWidget(self.loadButton) - self._buttons_layout.addWidget(self.saveButton) - self._buttons_layout.addWidget(self.defaultsButton) - self.layout.addLayout(self._buttons_layout) - self.loadButton.clicked.connect(self.openFile) - self.saveButton.clicked.connect(self.saveFile) - self.defaultsButton.clicked.connect(self.restoreDefaults) - - def _create_advanced_cb(self): - self._advanced_cb = QtGui.QCheckBox('Enable Advanced Settings') - self._advanced_layout.addWidget(self._advanced_cb) - self._advanced_cb.toggled.connect(self._toggle_advanced_settings) - - def _toggle_advanced_settings(self): - if self._advanced_cb.isChecked(): - self._enable_advanced(True) - else: - self._enable_advanced(False) - - def _enable_advanced(self, enable): - for lst in self.ap.get_special_para_names().values(): - for param in lst: - box = self.boxes[param] - if type(box) is not list: - box.setEnabled(enable) - else: - for b in box: - b.setEnabled(enable) - - def set_tune_mode(self, bool): - keys = ['rootpath', 'datapath', 'database', - 'eventID', 'invdir', 'nllocbin', - 'nllocroot', 'phasefile', - 'ctrfile', 'ttpatter', 'outpatter'] - for key in keys: - self.boxes[key].setEnabled(not(bool)) - - def init_boxes(self, parameter_names): - grid = QtGui.QGridLayout() - - for index1, name in enumerate(parameter_names): - text = name + ' [?]' - label = QtGui.QLabel(text) - default_item = self.ap.get_defaults()[name] - tooltip = default_item['tooltip'] - tooltip += ' | type: {}'.format(default_item['type']) - if not type(default_item['type']) == tuple: - typ = default_item['type'] - box = self.create_box(typ, tooltip) - self.boxes[name] = box - elif type(default_item['type']) == tuple: - boxes = [] - values = self.ap[name] - for index2, val in enumerate(values): - typ = default_item['type'][index2] - boxes.append(self.create_box(typ, tooltip)) - box = self.create_multi_box(boxes) - self.boxes[name] = boxes - label.setToolTip(tooltip) - grid.addWidget(label, index1, 1) - grid.addWidget(box, index1, 2) - return grid - - def create_box(self, typ, tooltip): - if typ == str: - box = QtGui.QLineEdit() - elif typ == float: - box = QtGui.QDoubleSpinBox() - elif typ == int: - box = QtGui.QSpinBox() - elif typ == bool: - box = QtGui.QCheckBox() - else: - raise TypeError('Unrecognized type {}'.format(typ)) - return box - - def create_multi_box(self, boxes): - box = QtGui.QWidget() - hl = QtGui.QHBoxLayout() - for b in boxes: - hl.addWidget(b) - box.setLayout(hl) - return box - - def add_tab(self, layout, name): - widget = QtGui.QWidget() - scrollA = QtGui.QScrollArea() - scrollA.setWidgetResizable(True) - scrollA.setWidget(widget) - - widget.setLayout(layout) - - self.tabs.addTab(scrollA, name) - - def add_main_parameters_tab(self): - self.add_to_layout(self._main_layout, 'Directories', - self.ap.get_main_para_names()['dirs']) - self.add_to_layout(self._main_layout, 'NLLoc', - self.ap.get_main_para_names()['nlloc']) - self.add_to_layout(self._main_layout, 'Seismic Moment', - self.ap.get_main_para_names()['smoment']) - self.add_to_layout(self._main_layout, 'Focal Mechanism', - self.ap.get_main_para_names()['focmec']) - self.add_to_layout(self._main_layout, 'Pick Settings', - self.ap.get_main_para_names()['pick'], - False) - self.add_tab(self._main_layout, 'Main Settings') - - def add_special_pick_parameters_tab(self): - self.add_to_layout(self._advanced_layout, 'Z-component', - self.ap.get_special_para_names()['z']) - self.add_to_layout(self._advanced_layout, 'H-components', - self.ap.get_special_para_names()['h']) - self.add_to_layout(self._advanced_layout, 'First-motion picker', - self.ap.get_special_para_names()['fm']) - self.add_to_layout(self._advanced_layout, 'Quality assessment', - self.ap.get_special_para_names()['quality'], - False) - self.add_tab(self._advanced_layout, 'Advanced Settings') - - def gen_h_seperator(self): - seperator = QtGui.QFrame() - seperator.setFrameShape(QtGui.QFrame.HLine) - return seperator - - def gen_headline(self, text): - label=QtGui.QLabel(text) - font=QtGui.QFont() - font.setBold(True) - label.setFont(font) - return label - - def add_to_layout(self, layout, name, items, seperator=True): - layout.addWidget(self.gen_headline(name)) - layout.addLayout(self.init_boxes(items)) - if seperator: - layout.addWidget(self.gen_h_seperator()) - - def params_from_gui(self): - for param in self.ap.get_all_para_names(): - box = self.boxes[param] - value = self.getValue(box) - self.ap.checkValue(param, value) - self.ap.setParamKV(param, value) - return self.ap - - def params_to_gui(self): - for param in self.ap.get_all_para_names(): - box = self.boxes[param] - value = self.ap[param] - #self.ap.checkValue(param, value) - self.setValue(box, value) - - def setValue(self, box, value): - if type(box) == QtGui.QLineEdit: - box.setText(value) - elif type(box) == QtGui.QSpinBox or type(box) == QtGui.QDoubleSpinBox: - box.setMaximum(100*value) - box.setValue(value) - elif type(box) == QtGui.QCheckBox: - if value == 'True': - value = True - if value == 'False': - value = False - box.setChecked(value) - elif type(box) == list: - for index, b in enumerate(box): - self.setValue(b, value[index]) - - def getValue(self, box): - if type(box) == QtGui.QLineEdit: - value = str(box.text()) - elif type(box) == QtGui.QSpinBox or type(box) == QtGui.QDoubleSpinBox: - value = box.value() - elif type(box) == QtGui.QCheckBox: - value = box.isChecked() - elif type(box) == list: - value = [] - for b in box: - value.append(self.getValue(b)) - value = tuple(value) - return value - - def openFile(self): - fd = QtGui.QFileDialog() - fname = fd.getOpenFileName(self, 'Browse for settings file.', '*.in') - if fname[0]: - try: - self.ap.from_file(fname[0]) - self.params_to_gui() - except Exception as e: - self._warn('Could not open file {}:\n{}'.format(fname[0], e)) - return - - def saveFile(self): - fd = QtGui.QFileDialog() - fname = fd.getSaveFileName(self, 'Browse for settings file.', '*.in') - if fname[0]: - try: - self.params_from_gui() - self.ap.export2File(fname[0]) - except Exception as e: - self._warn('Could not save file {}:\n{}'.format(fname[0], e)) - return - - def restoreDefaults(self): - try: - self.ap.reset_defaults() - self.params_to_gui() - except Exception as e: - self._warn('Could not restore defaults:\n{}'.format(e)) - return - - def _warn(self, message): - self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning, - 'Warning', message) - self.qmb.show() - - class ParametersTab(PropTab): def __init__(self, parent=None, infile=None): super(ParametersTab, self).__init__(parent) From ba58cb548b168d5b2ba6c59a5150a99e42279b6e Mon Sep 17 00:00:00 2001 From: Marcel Paffrath Date: Tue, 16 May 2017 14:20:32 +0200 Subject: [PATCH 10/12] bugfix iterating over same index as eventBox index --- QtPyLoT.py | 8 ++++---- pylot/RELEASE-VERSION | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index cea5f9f1..7cef866a 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -685,7 +685,7 @@ class MainWindow(QMainWindow): if pl > plmax: plmax=pl - for index, event in enumerate(self.project.eventlist): + for id, event in enumerate(self.project.eventlist): event_path = event.path event_npicks = 0 event_nautopicks = 0 @@ -733,12 +733,12 @@ class MainWindow(QMainWindow): for item in itemlist: item.setEnabled(False) model.appendRow(itemlist) - if not event.path == self.eventBox.itemText(index): + if not event.path == self.eventBox.itemText(id): message = ('Path missmatch creating eventbox.\n' '{} unequal {}.' - .format(event.path, self.eventBox.itemText(index))) + .format(event.path, self.eventBox.itemText(id))) raise ValueError(message) - eventBox.setItemData(index, event) + eventBox.setItemData(id, event) eventBox.setCurrentIndex(index) def filename_from_action(self, action): diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index e808bed5..9db2e713 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -c9d8-dirty +f436-dirty From 55bc0de036468197be4de010cf7628a1c88fdf18 Mon Sep 17 00:00:00 2001 From: Marcel Paffrath Date: Tue, 16 May 2017 17:26:42 +0200 Subject: [PATCH 11/12] working on connection between picks/autopicks of different tools [WIP], to do: fix array map number of picks/points mismatch in map --- QtPyLoT.py | 37 +++++++++++-- pylot/RELEASE-VERSION | 2 +- pylot/core/util/map_projection.py | 11 ++-- pylot/core/util/widgets.py | 87 +++++++++++++++++++++++++++---- 4 files changed, 116 insertions(+), 21 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 7cef866a..d1e6cf35 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -661,11 +661,13 @@ class MainWindow(QMainWindow): self.refreshEvents() tabindex = self.tabs.currentIndex() - def fill_eventbox(self, eventBox, select_events='all'): + def fill_eventbox(self, eventBox=None, select_events='all'): ''' :param: select_events, can be 'all', 'ref' :type: str ''' + if not eventBox: + eventBox = self.eventBox index=eventBox.currentIndex() tv=QtGui.QTableView() header = tv.horizontalHeader() @@ -1149,6 +1151,7 @@ class MainWindow(QMainWindow): self.setDirty(True) self.update_status('picks accepted ({0})'.format(station)) replot = self.addPicks(station, pickDlg.getPicks()) + self.getCurrentEvent().setPick(station, pickDlg.getPicks()) if replot: self.plotWaveformData() self.drawPicks() @@ -1439,7 +1442,7 @@ class MainWindow(QMainWindow): if not self.array_map: return # refresh with new picks here!!! - self.array_map.refresh_drawings(self.picks) + self.array_map.refresh_drawings(self.getCurrentEvent().getPicks()) self._eventChanged[1] = False def init_event_table(self, tabindex=2): @@ -1836,9 +1839,9 @@ class Event(object): ''' def __init__(self, path): self.path = path - self.autopicks = None - self.picks = None - self.notes = None + self.autopicks = {} + self.picks = {} + self.notes = '' self._testEvent = False self._refEvent = False @@ -1867,7 +1870,31 @@ class Event(object): def setTestEvent(self, bool): self._testEvent = bool if bool: self._refEvent = False + + def setPick(self, station, pick): + self.picks[station] = pick + + def setPicks(self, picks): + self.picks = picks + def getPick(self, station): + return self.picks[station] + + def getPicks(self): + return self.picks + + def setAutopick(self, station, autopick): + self.autopicks[station] = autopick + + def setAutopicks(self, autopicks): + self.autopicks = autopicks + + def getAutopick(self, station): + return self.autopicks[station] + + def getAutopicks(self): + return self.autopicks + class getExistingDirectories(QFileDialog): def __init__(self, *args): diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index 9db2e713..1834d1e2 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -f436-dirty +ba58-dirty diff --git a/pylot/core/util/map_projection.py b/pylot/core/util/map_projection.py index b539aea7..6f506b8d 100644 --- a/pylot/core/util/map_projection.py +++ b/pylot/core/util/map_projection.py @@ -48,13 +48,13 @@ class map_projection(QtGui.QWidget): pickDlg = PickDlg(self, parameter=self._parent._inputs, data=data.select(station=station), station=station, - picks=self._parent.getPicksOnStation(station, 'manual'), - autopicks=self._parent.getPicksOnStation(station, 'auto')) + picks=self._parent.getCurrentEvent().getPick(station), + autopicks=self._parent.getCurrentEvent().getAutopick(station)) pyl_mw = self._parent if pickDlg.exec_(): pyl_mw.setDirty(True) pyl_mw.update_status('picks accepted ({0})'.format(station)) - replot = pyl_mw.addPicks(station, pickDlg.getPicks()) + replot = pyl_mw.getCurrentEvent().setPick(station, pickDlg.getPicks()) if replot: pyl_mw.plotWaveformData() pyl_mw.drawPicks() @@ -148,8 +148,9 @@ class map_projection(QtGui.QWidget): def remove_nan_picks(picks): picks_no_nan=[] for pick in picks: - if not np.isnan(pick): - picks_no_nan.append(pick) + if pick: + if not np.isnan(pick): + picks_no_nan.append(pick) return picks_no_nan self.picks_no_nan = remove_nan_picks(self.picks_rel) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 18e54f9b..d062ac60 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -515,13 +515,14 @@ class WaveformWidget(FigureCanvas): class PickDlg(QDialog): + update_picks = QtCore.Signal(dict) def __init__(self, parent=None, data=None, station=None, picks=None, - autopicks=None, rotate=False, parameter=None, buttons=True): + autopicks=None, rotate=False, parameter=None, embedded=False): super(PickDlg, self).__init__(parent) # initialize attributes self.parameter = parameter - self._buttons = buttons + self._embedded = embedded self.station = station self.rotate = rotate self.components = 'ZNE' @@ -531,12 +532,16 @@ class PickDlg(QDialog): self._user = settings.value('user/Login', pylot_user) if picks: self.picks = picks + self._init_picks = copy.deepcopy(picks) else: self.picks = {} + self._init_picks = {} if autopicks: self.autopicks = autopicks + self._init_autopicks = copy.deepcopy(autopicks) else: self.autopicks = {} + self._init_autopicks = {} self.filteroptions = FILTERDEFAULTS self.pick_block = False @@ -638,6 +643,11 @@ class PickDlg(QDialog): # set button tooltips self.p_button.setToolTip('Hotkey: "1"') self.s_button.setToolTip('Hotkey: "2"') + + # create accept/reject button + self.accept_button = QPushButton('&Accept Picks') + self.reject_button = QPushButton('&Reject Picks') + self.disable_ar_buttons() # layout the outermost appearance of the Pick Dialog _outerlayout = QVBoxLayout() @@ -652,6 +662,9 @@ class PickDlg(QDialog): _dialtoolbar.addAction(self.resetZoomAction) _dialtoolbar.addSeparator() _dialtoolbar.addAction(self.resetPicksAction) + if self._embedded: + _dialtoolbar.addWidget(self.accept_button) + _dialtoolbar.addWidget(self.reject_button) # layout the innermost widget _innerlayout = QVBoxLayout() @@ -662,7 +675,7 @@ class PickDlg(QDialog): QDialogButtonBox.Cancel) # merge widgets and layouts to establish the dialog - if self._buttons: + if not self._embedded: _innerlayout.addWidget(_buttonbox) _outerlayout.addWidget(_dialtoolbar) _outerlayout.addLayout(_innerlayout) @@ -671,6 +684,10 @@ class PickDlg(QDialog): # object self.p_button.clicked.connect(self.p_clicked) self.s_button.clicked.connect(self.s_clicked) + self.accept_button.clicked.connect(self.accept) + self.reject_button.clicked.connect(self.reject) + self.accept_button.clicked.connect(self.disable_ar_buttons) + self.reject_button.clicked.connect(self.disable_ar_buttons) _buttonbox.accepted.connect(self.accept) _buttonbox.rejected.connect(self.reject) @@ -713,6 +730,13 @@ class PickDlg(QDialog): widget = self.getPlotWidget() return widget.mpl_connect('button_release_event', slot) + def disable_ar_buttons(self): + self.enable_ar_buttons(False) + + def enable_ar_buttons(self, bool=True): + self.accept_button.setEnabled(bool) + self.reject_button.setEnabled(bool) + def p_clicked(self): if self.p_button.isChecked(): self.s_button.setEnabled(False) @@ -1073,6 +1097,7 @@ class PickDlg(QDialog): olpp=olpp) self.disconnectPressEvent() + self.enable_ar_buttons() self.zoomAction.setEnabled(True) self.pick_block = self.togglePickBlocker() self.leave_picking_mode() @@ -1110,9 +1135,10 @@ class PickDlg(QDialog): if picktype == 'manual': ax.fill_between([epp, lpp], ylims[0], ylims[1], alpha=.25, color=colors[0]) - ax.plot([mpp - spe, mpp - spe], ylims, colors[1], - [mpp, mpp], ylims, colors[2], - [mpp + spe, mpp + spe], ylims, colors[1]) + if spe: + ax.plot([mpp - spe, mpp - spe], ylims, colors[1], + [mpp, mpp], ylims, colors[2], + [mpp + spe, mpp + spe], ylims, colors[1]) elif picktype == 'auto': ax.plot(mpp, ylims[1], colors[3], mpp, ylims[0], colors[4]) @@ -1265,12 +1291,35 @@ class PickDlg(QDialog): def apply(self): picks = self.getPicks() + self.update_picks.emit(picks) for pick in picks: print(pick, picks[pick]) + def discard(self): + picks = self._init_picks + self.picks = picks + self.update_picks.emit(picks) + for pick in picks: + print(pick, picks[pick]) + + def reject(self): + self.discard() + if not self._embedded: + QDialog.reject(self) + else: + self.resetPlot() + self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Information, + 'Denied', 'New picks rejected!') + self.qmb.show() + def accept(self): self.apply() - QDialog.accept(self) + if not self._embedded: + QDialog.accept(self) + else: + self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Information, + 'Accepted', 'New picks applied!') + self.qmb.show() class TuneAutopicker(QWidget): @@ -1285,6 +1334,7 @@ class TuneAutopicker(QWidget): QtGui.QWidget.__init__(self, parent, 1) self.parent = parent self.setParent(parent) + self.setWindowTitle('PyLoT - Tune Autopicker') self.parameter = parent._inputs self.fig_dict = parent.fig_dict self.data = Data() @@ -1385,6 +1435,16 @@ class TuneAutopicker(QWidget): def get_current_event_fp(self): return self.eventBox.currentText() + + def get_current_event_picks(self, station): + event = self.get_current_event() + if station in event.picks.keys(): + return event.picks[station] + + def get_current_event_autopicks(self, station): + event = self.get_current_event() + if event.autopicks: + return event.autopicks[station] def get_current_station(self): return str(self.stationBox.currentText()) @@ -1402,13 +1462,20 @@ class TuneAutopicker(QWidget): data = self.data.getWFData() pickDlg = PickDlg(self, data=data.select(station=station), station=station, parameter=self.parameter, - picks=self.get_current_event().picks, - autopicks=self.get_current_event().autopicks, - buttons=False) + picks=self.get_current_event_picks(station), + autopicks=self.get_current_event_autopicks(station), + embedded=True) + pickDlg.update_picks.connect(self.picks_from_pickdlg) + pickDlg.update_picks.connect(self.parent.fill_eventbox) + pickDlg.update_picks.connect(self.fill_eventbox) self.pickDlg = QtGui.QWidget() hl = QtGui.QHBoxLayout() self.pickDlg.setLayout(hl) hl.addWidget(pickDlg) + + def picks_from_pickdlg(self, picks=None): + station = self.get_current_station() + self.get_current_event().setPick(station, picks) def fill_tabs(self, event=None, picked=False): self.clear_all() From d81fb3e2e903bc689a0a5c4030199ccb89b43846 Mon Sep 17 00:00:00 2001 From: Marcel Paffrath Date: Wed, 17 May 2017 13:25:41 +0200 Subject: [PATCH 12/12] several bugfixes, mainly on map_projection with updated pick structure as part of event class --- QtPyLoT.py | 42 ++++++++++------ pylot/RELEASE-VERSION | 2 +- pylot/core/util/map_projection.py | 79 +++++++++++++++++++++---------- pylot/core/util/widgets.py | 13 ++++- 4 files changed, 92 insertions(+), 44 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index d1e6cf35..0d209017 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -912,6 +912,7 @@ class MainWindow(QMainWindow): self.refreshTabs() def refreshTabs(self): + plotted=False if self._eventChanged[0] or self._eventChanged[1]: event = self.getCurrentEvent() if not event.picks: @@ -927,20 +928,25 @@ class MainWindow(QMainWindow): if len(self.project.eventlist) > 0: if self._eventChanged[0]: self.newWFplot() + plotted=True if self.tabs.currentIndex() == 1: if self._eventChanged[1]: self.refresh_array_map() + if not plotted and self._eventChanged[0]: + self.newWFplot(False) if self.tabs.currentIndex() == 2: self.init_event_table() - def newWFplot(self): - self.loadWaveformDataThread() - self._eventChanged[0] = False + def newWFplot(self, plot=True): + self.loadWaveformDataThread(plot) + if plot: + self._eventChanged[0] = False - def loadWaveformDataThread(self): + def loadWaveformDataThread(self, plot=True): wfd_thread = Thread(self, self.loadWaveformData, progressText='Reading data input...') - wfd_thread.finished.connect(self.plotWaveformDataThread) + if plot: + wfd_thread.finished.connect(self.plotWaveformDataThread) wfd_thread.start() def loadWaveformData(self): @@ -1845,12 +1851,6 @@ class Event(object): self._testEvent = False self._refEvent = False - def addPicks(self, picks): - self.picks = picks - - def addAutopicks(self, autopicks): - self.autopicks = autopicks - def addNotes(self, notes): self.notes = notes @@ -1871,26 +1871,38 @@ class Event(object): self._testEvent = bool if bool: self._refEvent = False + def addPicks(self, picks): + for station in picks: + self.picks[station] = picks[station] + + def addAutopicks(self, autopicks): + for station in autopicks: + self.autopicks[station] = autopicks[station] + def setPick(self, station, pick): - self.picks[station] = pick + if pick: + self.picks[station] = pick def setPicks(self, picks): self.picks = picks def getPick(self, station): - return self.picks[station] + if station in self.picks.keys(): + return self.picks[station] def getPicks(self): return self.picks def setAutopick(self, station, autopick): - self.autopicks[station] = autopick + if autopick: + self.autopicks[station] = autopick def setAutopicks(self, autopicks): self.autopicks = autopicks def getAutopick(self, station): - return self.autopicks[station] + if station in self.autopicks.keys(): + return self.autopicks[station] def getAutopicks(self): return self.autopicks diff --git a/pylot/RELEASE-VERSION b/pylot/RELEASE-VERSION index 1834d1e2..9b24c362 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -ba58-dirty +55bc-dirty diff --git a/pylot/core/util/map_projection.py b/pylot/core/util/map_projection.py index 6f506b8d..1c6e06cf 100644 --- a/pylot/core/util/map_projection.py +++ b/pylot/core/util/map_projection.py @@ -50,22 +50,29 @@ class map_projection(QtGui.QWidget): station=station, picks=self._parent.getCurrentEvent().getPick(station), autopicks=self._parent.getCurrentEvent().getAutopick(station)) - pyl_mw = self._parent - if pickDlg.exec_(): - pyl_mw.setDirty(True) - pyl_mw.update_status('picks accepted ({0})'.format(station)) - replot = pyl_mw.getCurrentEvent().setPick(station, pickDlg.getPicks()) - if replot: - pyl_mw.plotWaveformData() - pyl_mw.drawPicks() - pyl_mw.draw() - else: - pyl_mw.drawPicks(station) - pyl_mw.draw() - else: - pyl_mw.update_status('picks discarded ({0})'.format(station)) except Exception as e: - print('Could not generate Plot for station {st}.\n{er}'.format(st=station, er=e)) + message = 'Could not generate Plot for station {st}.\n{er}'.format(st=station, er=e) + self._warn(message) + print(message, e) + pyl_mw = self._parent + #try: + if pickDlg.exec_(): + pyl_mw.setDirty(True) + pyl_mw.update_status('picks accepted ({0})'.format(station)) + replot = pyl_mw.getCurrentEvent().setPick(station, pickDlg.getPicks()) + if replot: + pyl_mw.plotWaveformData() + pyl_mw.drawPicks() + pyl_mw.draw() + else: + pyl_mw.drawPicks(station) + pyl_mw.draw() + else: + pyl_mw.update_status('picks discarded ({0})'.format(station)) + # except Exception as e: + # message = 'Could not save picks for station {st}.\n{er}'.format(st=station, er=e) + # self._warn(message) + # print(message, e) def connectSignals(self): self.comboBox_phase.currentIndexChanged.connect(self._refresh_drawings) @@ -92,9 +99,9 @@ class map_projection(QtGui.QWidget): self.comboBox_phase.insertItem(0, 'P') self.comboBox_phase.insertItem(1, 'S') - # self.comboBox_am = QtGui.QComboBox() - # self.comboBox_am.insertItem(0, 'auto') - # self.comboBox_am.insertItem(1, 'manual') + self.comboBox_am = QtGui.QComboBox() + self.comboBox_am.insertItem(0, 'auto') + self.comboBox_am.insertItem(1, 'manual') self.top_row.addWidget(QtGui.QLabel('Select a phase: ')) self.top_row.addWidget(self.comboBox_phase) @@ -134,9 +141,13 @@ class map_projection(QtGui.QWidget): def get_picks_rel(picks): picks_rel=[] - minp = min(picks) + picks_utc = [] for pick in picks: if type(pick) is obspy.core.utcdatetime.UTCDateTime: + picks_utc.append(pick) + minp = min(picks_utc) + for pick in picks: + if type(pick) is obspy.core.utcdatetime.UTCDateTime: pick -= minp picks_rel.append(pick) return picks_rel @@ -148,9 +159,8 @@ class map_projection(QtGui.QWidget): def remove_nan_picks(picks): picks_no_nan=[] for pick in picks: - if pick: - if not np.isnan(pick): - picks_no_nan.append(pick) + if not np.isnan(pick): + picks_no_nan.append(pick) return picks_no_nan self.picks_no_nan = remove_nan_picks(self.picks_rel) @@ -225,8 +235,19 @@ class map_projection(QtGui.QWidget): self.cid = self.canvas.mpl_connect('pick_event', self.onpick) def scatter_picked_stations(self): - self.sc_picked = self.basemap.scatter(self.lon_no_nan, self.lat_no_nan, s=50, facecolor='white', - c=self.picks_no_nan, latlon=True, zorder=11, label='Picked') + lon = self.lon_no_nan + lat = self.lat_no_nan + + #workaround because of an issue with latlon transformation of arrays with len <3 + if len(lon) <= 2 and len(lat) <= 2: + self.sc_picked = self.basemap.scatter(lon[0], lat[0], s=50, facecolor='white', + c=self.picks_no_nan[0], latlon=True, zorder=11, label='Picked') + if len(lon) == 2 and len(lat) == 2: + self.sc_picked = self.basemap.scatter(lon[1], lat[1], s=50, facecolor='white', + c=self.picks_no_nan[1], latlon=True, zorder=11) + else: + self.sc_picked = self.basemap.scatter(lon, lat, s=50, facecolor='white', + c=self.picks_no_nan, latlon=True, zorder=11, label='Picked') def annotate_ax(self): self.annotations=[] @@ -254,8 +275,9 @@ class map_projection(QtGui.QWidget): self.init_picks() self.init_picks_active() self.init_stations_active() - self.init_picksgrid() - self.draw_contour_filled() + if len(self.picks_no_nan) >= 3: + self.init_picksgrid() + self.draw_contour_filled() self.scatter_all_stations() if self.picks_dict: self.scatter_picked_stations() @@ -297,4 +319,9 @@ class map_projection(QtGui.QWidget): for annotation in self.annotations: annotation.remove() + def _warn(self, message): + self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning, + 'Warning', message) + self.qmb.show() + diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index d062ac60..f588230a 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -693,6 +693,7 @@ class PickDlg(QDialog): # finally layout the entire dialog self.setLayout(_outerlayout) + self.resize(1280, 720) def disconnectPressEvent(self): widget = self.getPlotWidget() @@ -1390,8 +1391,12 @@ class TuneAutopicker(QWidget): if not station in stations: stations.append(str(station)) stations.sort() + model = self.stationBox.model() for station in stations: - self.stationBox.addItem(str(station)) + item = QtGui.QStandardItem(str(station)) + if station in self.get_current_event().picks: + item.setBackground(QtGui.QColor(200, 210, 230, 255)) + model.appendRow(item) def init_figure_tabs(self): self.figure_tabs = QtGui.QTabWidget() @@ -1415,8 +1420,11 @@ class TuneAutopicker(QWidget): def add_buttons(self): self.pick_button = QtGui.QPushButton('Pick Trace') self.pick_button.clicked.connect(self.call_picker) + self.close_button = QtGui.QPushButton('Close') + self.close_button.clicked.connect(self.hide) self.trace_layout.addWidget(self.pick_button) self.trace_layout.setStretch(0, 1) + self.parameter_layout.addWidget(self.close_button) def add_log(self): self.listWidget = QtGui.QListWidget() @@ -1467,7 +1475,8 @@ class TuneAutopicker(QWidget): embedded=True) pickDlg.update_picks.connect(self.picks_from_pickdlg) pickDlg.update_picks.connect(self.parent.fill_eventbox) - pickDlg.update_picks.connect(self.fill_eventbox) + pickDlg.update_picks.connect(self.fill_eventbox) + pickDlg.update_picks.connect(self.fill_stationbox) self.pickDlg = QtGui.QWidget() hl = QtGui.QHBoxLayout() self.pickDlg.setLayout(hl)