From 7ec28664b48870e8041b0b33e906074155491f8c Mon Sep 17 00:00:00 2001 From: Sebastian Wehling-Benatelli Date: Thu, 25 Jun 2015 10:21:52 +0200 Subject: [PATCH 1/9] new function getResolutionWindow and doc testing added --- pylot/core/pick/utils.py | 59 +++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/pylot/core/pick/utils.py b/pylot/core/pick/utils.py index 1bcb7469..c80ac572 100644 --- a/pylot/core/pick/utils.py +++ b/pylot/core/pick/utils.py @@ -398,6 +398,43 @@ def getsignalwin(t, t1, tsignal): return isignal +def getResolutionWindow(snr): + """ + Number -> Float + produce the half of the time resolution window width from given SNR + value + SNR >= 3 -> 2 sec HRW + 3 > SNR >= 2 -> 5 sec MRW + 2 > SNR >= 1.5 -> 10 sec LRW + 1.5 > SNR -> 15 sec VLRW + see also Diehl et al. 2009 + + >>> getResolutionWindow(0.5) + 7.5 + >>> getResolutionWindow(1.8) + 5.0 + >>> getResolutionWindow(2.3) + 2.5 + >>> getResolutionWindow(4) + 1.0 + >>> getResolutionWindow(2) + 2.5 + """ + + res_wins = {'HRW': 2., 'MRW': 5., 'LRW': 10., 'VLRW': 15.} + + if snr < 1.5: + time_resolution = res_wins['VLRW'] + elif snr < 2.: + time_resolution = res_wins['LRW'] + elif snr < 3.: + time_resolution = res_wins['MRW'] + else: + time_resolution = res_wins['HRW'] + + return time_resolution/2 + + def wadaticheck(pickdic, dttolerance, iplot): ''' Function to calculate Wadati-diagram from given P and S onsets in order @@ -453,7 +490,7 @@ def wadaticheck(pickdic, dttolerance, iplot): for key in pickdic: if pickdic[key].has_key('SPt'): wddiff = abs(pickdic[key]['SPt'] - wdfit[ii]) - ii += 1 + ii += 1 # check, if deviation is larger than adjusted if wddiff >= dttolerance: # mark onset and downgrade S-weight to 9 @@ -481,7 +518,7 @@ def wadaticheck(pickdic, dttolerance, iplot): print 'wadaticheck: Average Vp/Vs ratio after check:', cvpvsr else: print 'wadatacheck: Not enough checked S-P times available!' - print 'Skip Wadati check!' + print 'Skip Wadati check!' checkedonsets = pickdic @@ -489,7 +526,7 @@ def wadaticheck(pickdic, dttolerance, iplot): print 'wadaticheck: Not enough S-P times available for reliable regression!' print 'Skip wadati check!' wfitflag = 1 - + # plot results if iplot > 1: plt.figure(iplot) @@ -518,14 +555,14 @@ def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot): ''' Function to detect spuriously picked noise peaks. Uses envelope to determine, how many samples [per cent] after - P onset are below certain threshold, calculated from noise + P onset are below certain threshold, calculated from noise level times noise factor. : param: X, time series (seismogram) : type: `~obspy.core.stream.Stream` : param: pick, initial (AIC) P onset time - : type: float + : type: float : param: TSNR, length of time windows around initial pick [s] : type: tuple (T_noise, T_gap, T_signal) @@ -544,7 +581,7 @@ def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot): : param: iplot, if iplot > 1, results are shown in figure : type: int ''' - + assert isinstance(X, Stream), "%s is not a stream object" % str(X) print 'Checking signal length ...' @@ -565,7 +602,7 @@ def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot): # minimum adjusted number of samples over minimum signal level minnum = len(isignal) * minpercent/100 # get number of samples above minimum adjusted signal level - numoverthr = len(np.where(e[isignal] >= minsiglevel)[0]) + numoverthr = len(np.where(e[isignal] >= minsiglevel)[0]) if numoverthr >= minnum: print 'checksignallength: Signal reached required length.' @@ -574,12 +611,12 @@ def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot): print 'checksignallength: Signal shorter than required minimum signal length!' print 'Presumably picked picked noise peak, pick is rejected!' returnflag = 0 - + if iplot == 2: plt.figure(iplot) p1, = plt.plot(t,x, 'k') p2, = plt.plot(t[inoise], e[inoise]) - p3, = plt.plot(t[isignal],e[isignal], 'r') + p3, = plt.plot(t[isignal],e[isignal], 'r') p4, = plt.plot([t[isignal[0]], t[isignal[len(isignal)-1]]], \ [minsiglevel, minsiglevel], 'g') p5, = plt.plot([pick, pick], [min(x), max(x)], 'c') @@ -596,4 +633,6 @@ def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot): return returnflag - +if __name__ == '__main__': + import doctest + doctest.testmod() From 7635f790fda6c454e33611f55ff848c2e63ec97b Mon Sep 17 00:00:00 2001 From: Sebastian Wehling-Benatelli Date: Thu, 25 Jun 2015 10:24:17 +0200 Subject: [PATCH 2/9] [bugfix] one filter parameter was type string and caused problems when parsing the parameters to the filter function of an obspy object --- pylot/core/util/defaults.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pylot/core/util/defaults.py b/pylot/core/util/defaults.py index b9815b45..df4fe5f7 100644 --- a/pylot/core/util/defaults.py +++ b/pylot/core/util/defaults.py @@ -10,7 +10,7 @@ FILTERDEFAULTS = {'P': {'filtertype': None, 'order': None, 'freq': None}, 'S': {'filtertype': 'bandpass', - 'order': '4', + 'order': 4, 'freq': [.5, 5]}} -OUTPUTFORMATS = {'QuakeML':'QUAKEML', 'VelEst':'VELEST'} \ No newline at end of file +OUTPUTFORMATS = {'QuakeML':'QUAKEML', 'VelEst':'VELEST'} From b42f88605bc9182cdff7f50bdf336ed36a6251f8 Mon Sep 17 00:00:00 2001 From: Sebastian Wehling-Benatelli Date: Thu, 25 Jun 2015 10:25:08 +0200 Subject: [PATCH 3/9] the main application window now opens in fullscreen mode --- QtPyLoT.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 14733925..a63153d5 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -549,7 +549,7 @@ def main(): pylot_form = MainWindow() # Show main window and run the app - pylot_form.show() + pylot_form.showMaximized() pylot_app.exec_() From bb52f8ac8311acf58f9c7d7b060b65eb35d0e8fd Mon Sep 17 00:00:00 2001 From: Sebastian Wehling-Benatelli Date: Thu, 25 Jun 2015 10:27:00 +0200 Subject: [PATCH 4/9] moved the determination of the time resolution window to the utils module within the pick package --- pylot/core/util/widgets.py | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 9cb326a0..cb4508bf 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -24,7 +24,8 @@ from PySide.QtCore import QSettings, Qt, QUrl, Signal, Slot from PySide.QtWebKit import QWebView from obspy import Stream, UTCDateTime from pylot.core.read import FilterOptions -from pylot.core.pick.utils import getSNR, earllatepicker, getnoisewin +from pylot.core.pick.utils import getSNR, earllatepicker, getnoisewin,\ + getResolutionWindow from pylot.core.util.defaults import OUTPUTFORMATS, FILTERDEFAULTS from pylot.core.util import prepTimeAxis, getGlobalTimes @@ -403,20 +404,6 @@ class PickDlg(QDialog): ini_pick = gui_event.xdata - # calculate the resolution window width from SNR - # SNR >= 3 -> 2 sec HRW - # 3 > SNR >= 2 -> 5 sec MRW - # 2 > SNR >= 1.5 -> 10 sec LRW - # 1.5 > SNR -> 15 sec VLRW - # see also Diehl et al. 2009 - - res_wins = { - 'HRW': 2., - 'MRW': 5., - 'LRW': 10., - 'VLRW': 15. - } - settings = QSettings() nfac = settings.value('picking/nfac', 1.5) @@ -429,15 +416,7 @@ class PickDlg(QDialog): snr = result[0] noiselevel = result[2] * nfac - if snr < 1.5: - x_res = res_wins['VLRW'] - elif snr < 2.: - x_res = res_wins['LRW'] - elif snr < 3.: - x_res = res_wins['MRW'] - else: - x_res = res_wins['HRW'] - x_res /= 2 + x_res = getResolutionWindow(snr) # demean data before plotting data = self.getWFData().copy() From cb5bd7dc095caed672bbb0115f56c0bbcb7bd1d9 Mon Sep 17 00:00:00 2001 From: Sebastian Wehling-Benatelli Date: Thu, 25 Jun 2015 10:30:59 +0200 Subject: [PATCH 5/9] differentiate between initial picks for p and s phases as they are picked from different components; zoom window determination for s phases not implemented yet --- pylot/core/util/widgets.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index cb4508bf..9eec8066 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -390,6 +390,12 @@ class PickDlg(QDialog): return self.picks def setIniPick(self, gui_event): + if self.selectPhase.currentText().upper().startswith('P'): + self.setIniPickP(gui_event) + elif self.selectPhase.currentText().upper().startswith('S'): + self.setIniPickS(gui_event) + + def setIniPickP(self, gui_event): trace_number = round(gui_event.ydata) @@ -444,6 +450,8 @@ class PickDlg(QDialog): self.setPlotLabels() self.draw() + def setIniPickS(self, gui_event): + pass def setPick(self, gui_event): From a383f8c769e04e99920fd67fb87ae75e6450f300 Mon Sep 17 00:00:00 2001 From: Sebastian Wehling-Benatelli Date: Thu, 25 Jun 2015 10:31:55 +0200 Subject: [PATCH 6/9] [bugfix] labels are now drawn correctly after picking an onset --- pylot/core/util/widgets.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 9eec8066..f7a460e3 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -505,8 +505,7 @@ class PickDlg(QDialog): self.disconnectPressEvent() self.zoomAction.setEnabled(True) self.selectPhase.setCurrentIndex(-1) - self.getPlotWidget().setXLims(self.getXLims()) - self.getPlotWidget().setYLims(self.getYLims()) + self.setPlotLabels() def drawPicks(self, phase=None): # plotting picks From ec3ecd04bb287683a98ab4b97a5800228b2e7d38 Mon Sep 17 00:00:00 2001 From: Sebastian Wehling-Benatelli Date: Thu, 25 Jun 2015 10:34:15 +0200 Subject: [PATCH 7/9] pick colors now depend on the type of phase picked; blueish colors for compressional wave (p) phases and reddish colors for shear wave (s) phases --- pylot/core/util/widgets.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index f7a460e3..b8b8b931 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -511,9 +511,12 @@ class PickDlg(QDialog): # plotting picks ax = self.getPlotWidget().axes ylims = self.getGlobalLimits('y') + phase_col = {'P': ('c', 'c--', 'b-'), + 'S': ('m', 'm--', 'r-')} if self.getPicks(): if phase is not None: picks = self.getPicks()[phase] + colors = phase_col[phase[0].upper()] else: for phase in self.getPicks(): self.drawPicks(phase) @@ -526,10 +529,11 @@ class PickDlg(QDialog): lpp = picks['lpp'] spe = picks['spe'] - ax.fill_between([epp, lpp], ylims[0], ylims[1], alpha=.5, color='c') - ax.plot([mpp - spe, mpp - spe], ylims, 'c--', - [mpp, mpp], ylims, 'b-', - [mpp + spe, mpp + spe], ylims, 'c--') + ax.fill_between([epp, lpp], ylims[0], ylims[1], + alpha=.5, color=colors[0]) + ax.plot([mpp - spe, mpp - spe], ylims, colors[1], + [mpp, mpp], ylims, colors[2], + [mpp + spe, mpp + spe], ylims, colors[1]) def panPress(self, gui_event): ax = self.getPlotWidget().axes From 4292197818e6cb8ab2038eb871fb07d1067a372a Mon Sep 17 00:00:00 2001 From: Sebastian Wehling-Benatelli Date: Thu, 25 Jun 2015 10:35:58 +0200 Subject: [PATCH 8/9] [bugfix] switching between zooming types now does not cause weird mouse event behavior anymore --- pylot/core/util/widgets.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index b8b8b931..0c0ec11d 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -609,10 +609,11 @@ class PickDlg(QDialog): self.disconnectScrollEvent() self.figToolBar.zoom() else: - self.connectPressEvent(self.panPress) - self.connectMotionEvent(self.panMotion) - self.connectReleaseEvent(self.panRelease) - self.connectScrollEvent(self.scrollZoom) + self.figToolBar.zoom() + self.cidpress = self.connectPressEvent(self.panPress) + self.cidmotion = self.connectMotionEvent(self.panMotion) + self.cidrelease = self.connectReleaseEvent(self.panRelease) + self.cidscroll = self.connectScrollEvent(self.scrollZoom) def scrollZoom(self, gui_event, factor=2.): From e542aa70d9341893b874499586f7ee8cc5be18bc Mon Sep 17 00:00:00 2001 From: Sebastian Wehling-Benatelli Date: Thu, 25 Jun 2015 10:36:45 +0200 Subject: [PATCH 9/9] doctesting added without having doctests inserted (pending) --- pylot/core/util/widgets.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 0c0ec11d..71c6cc5d 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -1040,3 +1040,7 @@ class HelpForm(QDialog): def updatePageTitle(self): self.pageLabel.setText(self.webBrowser.documentTitle()) + +if __name__ == '__main__': + import doctest + doctest.testmod()