diff --git a/QtPyLoT.py b/QtPyLoT.py index 5b0db609..0d209017 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") @@ -548,17 +556,6 @@ class MainWindow(QMainWindow): self.drawPicks(picktype=type) self.draw() - def getCurrentEvent(self): - for event in self.project.eventlist: - if event.path == self.getCurrentEventPath(): - return event - - def getCurrentEventPath(self): - 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) @@ -596,16 +593,29 @@ class MainWindow(QMainWindow): else: return - def getWFFnames_from_eventlist(self): + def getWFFnames_from_eventbox(self, eventlist=None, eventbox=None): if self.dataStructure: - searchPath = self.dataStructure.expandDataPath() - directory = self.getCurrentEventPath() - 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 + if not eventbox: + eventbox = self.eventBox + index = eventbox.currentIndex() + return eventbox.itemData(index) + + 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: @@ -628,13 +638,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() @@ -643,7 +653,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: @@ -651,8 +661,14 @@ class MainWindow(QMainWindow): self.refreshEvents() tabindex = self.tabs.currentIndex() - def fill_eventbox(self): - index=self.eventBox.currentIndex() + 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() header.setResizeMode(QtGui.QHeaderView.ResizeToContents) @@ -661,16 +677,17 @@ 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: plmax=pl - for event in self.project.eventlist: + for id, event in enumerate(self.project.eventlist): event_path = event.path event_npicks = 0 event_nautopicks = 0 @@ -681,11 +698,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)) @@ -714,8 +731,17 @@ 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) + if not event.path == self.eventBox.itemText(id): + message = ('Path missmatch creating eventbox.\n' + '{} unequal {}.' + .format(event.path, self.eventBox.itemText(id))) + raise ValueError(message) + eventBox.setItemData(id, event) + eventBox.setCurrentIndex(index) def filename_from_action(self, action): if action.data() is None: @@ -886,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: @@ -901,19 +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): - wfd_thread = Thread(self, self.loadWaveformData, progressText='Reading data input...') - wfd_thread.finished.connect(self.plotWaveformDataThread) + def loadWaveformDataThread(self, plot=True): + wfd_thread = Thread(self, self.loadWaveformData, + progressText='Reading data input...') + if plot: + wfd_thread.finished.connect(self.plotWaveformDataThread) wfd_thread.start() def loadWaveformData(self): @@ -924,7 +957,8 @@ class MainWindow(QMainWindow): # ans = self.data.setWFData(self.getWFFnames()) # else: # ans = False - self.data.setWFData(self.getWFFnames_from_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): @@ -981,7 +1015,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() @@ -1113,7 +1148,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'), @@ -1122,6 +1157,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() @@ -1141,6 +1177,40 @@ class MainWindow(QMainWindow): self.listWidget.addItem(text) self.listWidget.scrollToBottom() + def tune_autopicker(self): + 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 + + if not self.tap: + 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() + + def update_autopicker(self): + for key in self.fig_dict.keys(): + self.canvas_dict[key] = FigureCanvas(self.fig_dict[key]) + self.tap.fill_tabs(picked=True) + def autoPick(self): self.autosave = QFileDialog().getExistingDirectory(caption='Select autoPyLoT output') if not os.path.exists(self.autosave): @@ -1354,19 +1424,34 @@ 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: 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, 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) @@ -1397,12 +1482,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) @@ -1467,7 +1552,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...') @@ -1656,7 +1741,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): @@ -1696,10 +1781,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 @@ -1752,18 +1845,12 @@ 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 - def addPicks(self, picks): - self.picks = picks - - def addAutopicks(self, autopicks): - self.autopicks = autopicks - def addNotes(self, notes): self.notes = notes @@ -1783,7 +1870,43 @@ class Event(object): def setTestEvent(self, bool): 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): + if pick: + self.picks[station] = pick + + def setPicks(self, picks): + self.picks = picks + + def getPick(self, station): + if station in self.picks.keys(): + return self.picks[station] + + def getPicks(self): + return self.picks + + def setAutopick(self, station, autopick): + if autopick: + self.autopicks[station] = autopick + + def setAutopicks(self, autopicks): + self.autopicks = autopicks + + def getAutopick(self, station): + if station in self.autopicks.keys(): + return self.autopicks[station] + + def getAutopicks(self): + return self.autopicks + class getExistingDirectories(QFileDialog): def __init__(self, *args): diff --git a/autoPyLoT.py b/autoPyLoT.py index f4192f5c..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(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,6 +55,21 @@ def autoPyLoT(parameter=None, inputfile=None, fnames=None, savepath=None, iplot= ***********************************'''.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: parameter = AutoPickParameter(inputfile) @@ -93,8 +108,7 @@ def autoPyLoT(parameter=None, inputfile=None, fnames=None, savepath=None, iplot= 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 @@ -158,15 +172,20 @@ def autoPyLoT(parameter=None, inputfile=None, fnames=None, savepath=None, iplot= 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, mainFig = autopickevent(wfdat, parameter, iplot=iplot) + picks = autopickevent(wfdat, parameter, iplot=iplot, fig_dict=fig_dict) ########################################################## # locating if locflag == 1: @@ -233,7 +252,7 @@ def autoPyLoT(parameter=None, inputfile=None, fnames=None, savepath=None, iplot= 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 @@ -317,7 +336,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 +363,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 5c1a3758..9b24c362 100644 --- a/pylot/RELEASE-VERSION +++ b/pylot/RELEASE-VERSION @@ -1 +1 @@ -dc65-dirty +55bc-dirty diff --git a/pylot/core/io/inputs.py b/pylot/core/io/inputs.py index 0c8c8a07..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) @@ -186,15 +151,64 @@ 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) + 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/pick/autopick.py b/pylot/core/pick/autopick.py index 1acc7871..7dd8781a 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 @@ -75,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 @@ -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,12 @@ 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 + 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: # check signal length to detect spuriously picked noise peaks @@ -252,9 +252,14 @@ 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) + if fig_dict: + fig = fig_dict[key] + else: + fig = None + Pflag = checksignallength(zne, aicpick.getpick(), tsnrz, + minsiglength / 2, + nfacsl, minpercent, iplot, + fig) else: # filter and taper horizontal traces trH1_filt = edat.copy() @@ -269,10 +274,14 @@ 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' - Pflag, fig_dict[key] = checksignallength(zne, aicpick.getpick(), tsnrz, - minsiglength, - nfacsl, minpercent, iplot) + if fig_dict: + fig = fig_dict['slength'] + else: + fig = None + Pflag = checksignallength(zne, aicpick.getpick(), tsnrz, + minsiglength, + nfacsl, minpercent, iplot, + fig) if Pflag == 1: # check for spuriously picked S onset @@ -283,9 +292,12 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): if verbose: print(msg) else: if iplot>1: - key = 'checkZ4S' - Pflag, fig_dict[key] = checkZ4S(zne, aicpick.getpick(), zfac, - tsnrz[3], iplot) + if fig_dict: + fig = fig_dict['checkZ4s'] + else: + fig = None + Pflag = checkZ4S(zne, aicpick.getpick(), zfac, + tsnrz[3], iplot, fig) if Pflag == 0: Pmarker = 'SinsteadP' Pweight = 9 @@ -332,19 +344,24 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): 'correctly: maybe the algorithm name ({algoP}) is ' \ 'corrupted'.format( algoP=algoP) + if fig_dict: + fig = fig_dict['refPpick'] + else: + fig = None refPpick = PragPicker(cf2, tsnrz, pickwinP, iplot, ausP, tsmoothP, - aicpick.getpick()) - key = 'refPpick' - fig_dict[key] = refPpick.fig + 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' - epickP, lpickP, Perror, fig_dict[key] = earllatepicker(z_copy, nfacP, tsnrz, - mpickP, iplot) + if fig_dict: + fig = fig_dict['el_Ppick'] + else: + fig = None + epickP, lpickP, Perror = earllatepicker(z_copy, nfacP, tsnrz, + mpickP, iplot, fig=fig) else: epickP, lpickP, Perror = earllatepicker(z_copy, nfacP, tsnrz, mpickP, iplot) @@ -369,8 +386,11 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): # certain quality required if Pweight <= minfmweight and SNRP >= minFMSNR: if iplot: - key = 'fm_picker' - FM, fig_dict[key] = fmpicker(zdat, z_copy, fmpickwin, mpickP, iplot) + 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: @@ -471,10 +491,12 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): ############################################################## # get prelimenary onset time from AIC-HOS-CF using subclass AICPicker # of class AutoPicking + if fig_dict: + fig = fig_dict['aicARHfig'] + else: + fig = None aicarhpick = AICPicker(haiccf, tsnrh, pickwinS, iplot, None, - aictsmoothS) - key = 'aicARHfig' - fig_dict[key] = aicarhpick.fig + aictsmoothS, fig=fig) ############################################################### # go on with processing if AIC onset passes quality control if (aicarhpick.getSlope() >= minAICSslope and @@ -528,10 +550,12 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): addnoise) # instance of ARHcf # get refined onset time from CF2 using class Picker + if fig_dict: + fig = fig_dict['refSpick'] + else: + fig = None refSpick = PragPicker(arhcf2, tsnrh, pickwinS, iplot, ausS, - tsmoothS, aicarhpick.getpick()) - key = 'refSpick' - fig_dict[key] = refSpick.fig + tsmoothS, aicarhpick.getpick(), fig) mpickS = refSpick.getpick() ############################################################# if mpickS is not None: @@ -539,10 +563,14 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): # get earliest/latest possible pick and symmetrized uncertainty 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) + if fig_dict: + fig = fig_dict['el_S1pick'] + else: + fig = None + epickS1, lpickS1, Serror1 = earllatepicker(h_copy, nfacS, + tsnrh, + mpickS, iplot, + fig=fig) else: epickS1, lpickS1, Serror1 = earllatepicker(h_copy, nfacS, tsnrh, @@ -550,10 +578,14 @@ 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) + if fig_dict: + fig = fig_dict['el_S2pick'] + else: + fig = None + epickS2, lpickS2, Serror2 = earllatepicker(h_copy, nfacS, + tsnrh, + mpickS, iplot, + fig=fig) else: epickS2, lpickS2, Serror2 = earllatepicker(h_copy, nfacS, tsnrh, @@ -649,7 +681,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) @@ -700,7 +735,7 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): 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 +784,7 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0): 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, @@ -792,8 +827,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,10 +873,10 @@ 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): +def iteratepicker(wf, NLLocfile, picks, badpicks, pickparameter, fig_dict=None): ''' Repicking of bad onsets. Uses theoretical onset times from NLLoc-location file. @@ -918,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 @@ -933,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/pick/picker.py b/pylot/core/pick/picker.py index 663f8da1..b2c34813 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,8 @@ class AutoPicker(object): self.setaus(aus) self.setTsmooth(Tsmooth) self.setpick1(Pick1) - self.fig = self.calcPick() + self.fig = fig + self.calcPick() def __str__(self): return '''\n\t{name} object:\n @@ -152,7 +153,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 +227,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 +239,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 +256,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') @@ -262,27 +268,33 @@ 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?') - return fig + return class PragPicker(AutoPicker): @@ -375,7 +387,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 +400,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..76312f83 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,11 +104,12 @@ 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') - 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') @@ -127,13 +128,10 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=None, stealth_mode=False): X[0].stats.station) ax.legend() - if iplot: - return EPick, LPick, PickError, fig - else: - return EPick, LPick, PickError + return EPick, LPick, PickError -def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=None): +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 @@ -278,7 +276,8 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=None): 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') @@ -292,7 +291,7 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=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', @@ -305,10 +304,7 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=None): ax2.set_xlabel('Time [s] since %s' % Xraw[0].stats.starttime) ax2.set_yticks([]) - if iplot: - return FM, fig - else: - return FM + return FM def crossings_nonzero_all(data): @@ -620,7 +616,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=None): ''' Function to detect spuriously picked noise peaks. Uses RMS trace of all 3 components (if available) to determine, @@ -692,11 +688,12 @@ def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot): 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') - 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') @@ -706,7 +703,7 @@ def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot): 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): @@ -868,7 +865,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 @@ -962,14 +959,14 @@ 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') + 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') @@ -980,7 +977,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/map_projection.py b/pylot/core/util/map_projection.py index 2bfd3ed4..1c6e06cf 100644 --- a/pylot/core/util/map_projection.py +++ b/pylot/core/util/map_projection.py @@ -12,61 +12,83 @@ 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 == []: + button = event.mouseevent.button + if ind == [] or not button == 1: 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, parameter=self._parent._inputs, 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 - if pickDlg.exec_(): - pyl_mw.setDirty(True) - pyl_mw.update_status('picks accepted ({0})'.format(station)) - replot = pyl_mw.addPicks(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)) + picks=self._parent.getCurrentEvent().getPick(station), + autopicks=self._parent.getCurrentEvent().getAutopick(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) 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) @@ -77,26 +99,17 @@ 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) 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=[] @@ -128,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 @@ -186,7 +203,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): @@ -219,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=[] @@ -248,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() @@ -291,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/thread.py b/pylot/core/util/thread.py index fc76081b..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): @@ -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) - vl = QVBoxLayout() + if not self.pb_widget: + self.pb_widget = QDialog(self.parent()) + self.pb_widget.setWindowFlags(Qt.SplashScreen) + self.pb_widget.setModal(True) + hl = QHBoxLayout() 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() + hl.addWidget(pb) + hl.addWidget(QLabel(self.progressText)) + self.pb_widget.setLayout(hl) + 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 bfb171c0..f588230a 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 @@ -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 @@ -39,6 +40,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): @@ -513,12 +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, infile=None): + autopicks=None, rotate=False, parameter=None, embedded=False): super(PickDlg, self).__init__(parent) # initialize attributes - self.infile = infile + self.parameter = parameter + self._embedded = embedded self.station = station self.rotate = rotate self.components = 'ZNE' @@ -528,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 @@ -635,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() @@ -649,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() @@ -659,7 +675,8 @@ class PickDlg(QDialog): QDialogButtonBox.Cancel) # merge widgets and layouts to establish the dialog - _innerlayout.addWidget(_buttonbox) + if not self._embedded: + _innerlayout.addWidget(_buttonbox) _outerlayout.addWidget(_dialtoolbar) _outerlayout.addLayout(_innerlayout) @@ -667,11 +684,16 @@ 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) # finally layout the entire dialog self.setLayout(_outerlayout) + self.resize(1280, 720) def disconnectPressEvent(self): widget = self.getPlotWidget() @@ -709,6 +731,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) @@ -771,8 +800,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 @@ -897,7 +926,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') @@ -946,7 +975,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') @@ -1000,7 +1029,7 @@ class PickDlg(QDialog): def setPick(self, gui_event): - parameter = AutoPickParameter(self.getinfile()) + parameter = self.parameter # get axes limits self.updateCurrentLimits() @@ -1069,6 +1098,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() @@ -1106,9 +1136,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]) @@ -1261,100 +1292,593 @@ 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): - def __init__(self, ap, parent=None): - QtGui.QWidget.__init__(self, parent) - self.ap = ap - self.station = 'AH11' - self.fd = None - self.layout = QtGui.QHBoxLayout() - self.parameter_layout = QtGui.QVBoxLayout() - self.setLayout(self.layout) + 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.setParent(parent) + self.setWindowTitle('PyLoT - Tune Autopicker') + self.parameter = parent._inputs + self.fig_dict = parent.fig_dict + self.data = Data() + self.init_main_layouts() + self.init_eventlist() self.init_figure_tabs() - self.add_parameter() + 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.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal) + #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.trace_layout) + self.main_layout.addLayout(self.tune_layout) + self.setLayout(self.main_layout) + + def init_eventlist(self): + self.eventBox = self.parent.createEventBox() + self.fill_eventbox() + self.eventBox.setCurrentIndex(0) + self.trace_layout.addWidget(self.eventBox) + + 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) + self.stationBox.clear() + stations = [] + for trace in self.data.getWFData(): + station = trace.stats.station + if not station in stations: + stations.append(str(station)) + stations.sort() + model = self.stationBox.model() + for station in stations: + 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.main_tabs = QtGui.QTabWidget() - 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.figure_tabs = QtGui.QTabWidget() + self.fill_figure_tabs() + + def init_pbwidget(self): + self.pb_widget = QtGui.QWidget() - def add_parameter(self): - self.parameters = AutoPickParaBox(self.ap) + 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.parameter) + self.parameters.set_tune_mode(True) + self.update_eventID() self.parameter_layout.addWidget(self.parameters) - self.layout.insertLayout(1, self.parameter_layout) + self.parameter_layout.addWidget(self.pb_widget) + 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.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 call_picker(self): - self.parameters.update_params() - picks, fig_dict = autoPyLoT(self.ap, fnames='None', iplot=2) - self.main_tabs.setParent(None) - self.fd = fig_dict[self.station] - self.init_figure_tabs() - self.set_stretch() - - def set_stretch(self): - self.layout.setStretch(0, 3) - self.layout.setStretch(1, 1) + def add_log(self): + self.listWidget = QtGui.QListWidget() + self.figure_tabs.insertTab(4, self.listWidget, 'log') - def init_tab_names(self): - self.ptb_names = ['aicFig', 'slenght', 'checkZ4S', 'refPpick', 'el_Ppick', 'fm_picker'] - self.stb_names = ['aicARHfig', 'refSpick', 'el_S1pick', 'el_S2pick'] + def add_log_item(self, text): + self.listWidget.addItem(text) + self.listWidget.scrollToBottom() + + def get_current_event(self): + index = self.eventBox.currentIndex() + return self.eventBox.itemData(index) + + def get_current_event_name(self): + return self.eventBox.currentText().split('/')[-1] - def fill_tabs(self): - try: - main_fig = self.fd['mainFig'] - self.main_tabs.addTab(main_fig.canvas, '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() + 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()) + + 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 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(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) + pickDlg.update_picks.connect(self.fill_stationbox) + 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() + canvas_dict = self.parent.canvas_dict + self.gen_pick_dlg() + self.overview = self.gen_tab_widget('Overview', canvas_dict['mainFig']) + 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): + def fill_p_tabs(self, canvas_dict): for name in self.ptb_names: + 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: - figure = self.fd[name] - id = self.p_tabs.addTab(figure.canvas, 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): + self.fig_dict[name].tight_layout() + except: + pass + + def fill_s_tabs(self, canvas_dict): for name in self.stb_names: + 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: - figure = self.fd[name] - id = self.s_tabs.addTab(figure.canvas, 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 + + 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) @@ -1617,193 +2141,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.QHBoxLayout() - 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._toggle_advanced_settings() - - def _init_sublayouts(self): - self._main_layout = QtGui.QVBoxLayout() - self._advanced_layout = QtGui.QVBoxLayout() - self._create_advanced_cb() - - 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 init_boxes(self, parameter_names, defaults=False): - 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: - if defaults: - value = default_item['value'] - else: - value = self.ap[name] - typ = default_item['type'] - box = self.create_box(value, typ, tooltip) - self.boxes[name] = box - elif type(default_item['type']) == tuple: - boxes = [] - if defaults: - values = default_item['value'] - else: - values = self.ap[name] - for index2, val in enumerate(values): - typ = default_item['type'][index2] - boxes.append(self.create_box(val, 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, value, 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 - - 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 update_params(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) - - 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 - - class ParametersTab(PropTab): def __init__(self, parent=None, infile=None): super(ParametersTab, self).__init__(parent)