From 4d3b300e1728e71a6b9cd65cacae5202020c1c79 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 19 Apr 2018 16:51:29 +0200 Subject: [PATCH 01/70] [removed] check4gaps/doubled, plotting merged instead --- PyLoT.py | 9 +++++---- pylot/core/io/data.py | 3 --- pylot/core/util/widgets.py | 19 ++++++++++++++++++- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index cd3c849d..9d73bd32 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -1753,13 +1753,14 @@ class MainWindow(QMainWindow): def finish_pg_plot(self): self.getPlotWidget().updateWidget() - plots = self.wfp_thread.data + plots, gaps = self.wfp_thread.data for times, data, times_syn, data_syn in plots: self.dataPlot.plotWidget.getPlotItem().plot(times, data, pen=self.dataPlot.pen_linecolor) if len(data_syn) > 0: self.dataPlot.plotWidget.getPlotItem().plot(times_syn, data_syn, pen=self.dataPlot.pen_linecolor_syn) + self.dataPlot.reinitMoveProxy() self.dataPlot.plotWidget.showAxis('left') self.dataPlot.plotWidget.showAxis('bottom') @@ -1900,9 +1901,9 @@ class MainWindow(QMainWindow): self.plot_method = 'fast' else: self.plot_method = 'normal' - plots = plotWidget.plotWFData(wfdata=wfst, wfsyn=wfsyn, title=title, mapping=False, component=comp, - nth_sample=int(nth_sample), method=self.plot_method) - return plots + plots, gaps = plotWidget.plotWFData(wfdata=wfst, wfsyn=wfsyn, title=title, mapping=False, component=comp, + nth_sample=int(nth_sample), method=self.plot_method) + return plots, gaps def adjustPlotHeight(self): if self.pg: diff --git a/pylot/core/io/data.py b/pylot/core/io/data.py index a7cb85d5..50e7a961 100644 --- a/pylot/core/io/data.py +++ b/pylot/core/io/data.py @@ -398,9 +398,6 @@ class Data(object): # various pre-processing steps: # remove possible underscores in station names self.wfdata = remove_underscores(self.wfdata) - # check for gaps and doubled channels - check4gaps(self.wfdata) - check4doubled(self.wfdata) # check for stations with rotated components if checkRotated and metadata is not None: self.wfdata = check4rotated(self.wfdata, metadata, verbosity=0) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 56dc16dd..d31a2a6e 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -464,6 +464,7 @@ class WaveformWidgetPG(QtGui.QWidget): self.wfstart, self.wfend = 0, 0 self.pen_multicursor = self.pg.mkPen(self.parent()._style['multicursor']['rgba']) self.pen_linecolor = self.pg.mkPen(self.parent()._style['linecolor']['rgba']) + self.pen_linecolor_highlight = self.pg.mkPen((255, 100, 100, 255)) self.pen_linecolor_syn = self.pg.mkPen((100, 0, 255, 255)) self.reinitMoveProxy() self._proxy = self.pg.SignalProxy(self.plotWidget.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved) @@ -529,6 +530,14 @@ class WaveformWidgetPG(QtGui.QWidget): else: st_select = wfdata + gaps = st_select.get_gaps() + if gaps: + merged = ['{}.{}.{}.{}'.format(*gap[:4]) for gap in gaps] + st_select.merge() + print('Merged the following stations because of gaps:') + for merged_station in merged: + print(merged_station) + # list containing tuples of network, station, channel (for sorting) nsc = [] for trace in st_select: @@ -590,7 +599,7 @@ class WaveformWidgetPG(QtGui.QWidget): self.ylabel = '' self.setXLims([0, self.wfend - self.wfstart]) self.setYLims([0.5, nmax + 0.5]) - return plots + return plots, gaps def minMax(self, trace, time_ax): ''' @@ -1013,6 +1022,14 @@ class PylotCanvas(FigureCanvas): if mapping: plot_positions = self.calcPlotPositions(st_select, compclass) + gaps = st_select.get_gaps() + if gaps: + merged = ['{}.{}.{}.{}'.format(*gap[:4]) for gap in gaps] + st_select.merge() + print('Merged the following stations because of gaps:') + for merged_station in merged: + print(merged_station) + # list containing tuples of network, station, channel and plot position (for sorting) nsc = [] for plot_pos, trace in enumerate(st_select): From 9b0ef55b702d63f74d027077c93194dd35cb9f65 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 20 Apr 2018 13:51:21 +0200 Subject: [PATCH 02/70] [bugfix] wasnt using processed data --- pylot/core/io/data.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pylot/core/io/data.py b/pylot/core/io/data.py index 50e7a961..77b24a3d 100644 --- a/pylot/core/io/data.py +++ b/pylot/core/io/data.py @@ -379,7 +379,10 @@ class Data(object): self.wfsyn = Stream() wffnames = None wffnames_syn = None - wfdir = 'processed' if 'processed' in [fname.split('/')[-1] for fname in fnames] else 'raw' + wfdir = 'raw' + for fname in fnames: + if fname.endswith('processed'): + wfdir = 'processed' if obspy_dmt: for fpath in fnames: if fpath.endswith(wfdir): From 0320ad67b98b6b2ef40f5955bf5a0a48dd5466f6 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 20 Apr 2018 14:53:15 +0200 Subject: [PATCH 03/70] [new] station highlighting by middle mouseclick --- PyLoT.py | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index 9d73bd32..5ff59b30 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -138,6 +138,7 @@ class MainWindow(QMainWindow): self._eventChanged = [False, False] self.apd_local = None self.apd_sge = None + self.stations_highlighted = [] self.poS_id = None self.ae_id = None @@ -1764,6 +1765,7 @@ class MainWindow(QMainWindow): self.dataPlot.reinitMoveProxy() self.dataPlot.plotWidget.showAxis('left') self.dataPlot.plotWidget.showAxis('bottom') + self.highlight_stations() def finishWaveformDataPlot(self): self.comparable = self.checkEvents4comparison() @@ -2132,10 +2134,12 @@ class MainWindow(QMainWindow): def pickOnStation(self, gui_event): if self.pg: - if not gui_event.button() == 1: + button = gui_event.button() + if not button in [1, 4]: return else: - if not gui_event.button == 1: + button = gui_event.button + if not button == 1: return if self.pg: @@ -2146,12 +2150,42 @@ class MainWindow(QMainWindow): wfID = self.getWFID(ycoord) if wfID is None: return - self.pickDialog(wfID) - def pickDialog(self, wfID, nextStation=False): - station = self.getStationName(wfID) network = self.getNetworkName(wfID) + station = self.getStationName(wfID) + if button == 1: + self.pickDialog(wfID, network, station) + elif button == 4: + self.toggle_station_color(wfID, network, station) + + def toggle_station_color(self, wfID, network, station): + black_pen = pg.mkPen((0, 0, 0)) + red_pen = pg.mkPen((200, 50, 50)) + line_item = self.dataPlot.plotWidget.getPlotItem().listDataItems()[wfID - 1] + current_pen = line_item.opts['pen'] + nwst = '{}.{}'.format(network, station) + if current_pen == black_pen: + line_item.setPen(red_pen) + if not nwst in self.stations_highlighted: + self.stations_highlighted.append(nwst) + else: + line_item.setPen(black_pen) + if nwst in self.stations_highlighted: + self.stations_highlighted.pop(self.stations_highlighted.index(nwst)) + + def highlight_stations(self): + for wfID, value in self.getPlotWidget().getPlotDict().items(): + station, channel, network = value + nwst = '{}.{}'.format(network, station) + if nwst in self.stations_highlighted: + self.toggle_station_color(wfID, network, station) + + def pickDialog(self, wfID, network=None, station=None, nextStation=False): + if not network: + network = self.getNetworkName(wfID) if not station: + station = self.getStationName(wfID) + if not station or not network: return self.update_status('picking on station {0}'.format(station)) data = self.get_data().getOriginalWFData().copy() From 36a4f0df8a8375d871be186dd5f66b842442329f Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 23 Apr 2018 13:33:05 +0200 Subject: [PATCH 04/70] [bugfix] error when there is nothing to plot --- PyLoT.py | 5 +++-- pylot/core/util/widgets.py | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index 5ff59b30..6d56c19f 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -1903,8 +1903,9 @@ class MainWindow(QMainWindow): self.plot_method = 'fast' else: self.plot_method = 'normal' - plots, gaps = plotWidget.plotWFData(wfdata=wfst, wfsyn=wfsyn, title=title, mapping=False, component=comp, - nth_sample=int(nth_sample), method=self.plot_method) + rval = plotWidget.plotWFData(wfdata=wfst, wfsyn=wfsyn, title=title, mapping=False, component=comp, + nth_sample=int(nth_sample), method=self.plot_method) + plots, gaps = rval if rval else ([], []) return plots, gaps def adjustPlotHeight(self): diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index d31a2a6e..89bc851c 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -447,6 +447,10 @@ class WaveformWidgetPG(QtGui.QWidget): self.orig_parent = parent # attribute plotdict is a dictionary connecting position and a name self.plotdict = dict() + # init labels + self.xlabel = None + self.ylabel = None + self.title = None # create plot self.main_layout = QtGui.QVBoxLayout() self.label_layout = QtGui.QHBoxLayout() From e6648a3cecd879380c32a8a924fe30e80a569c94 Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 23 Apr 2018 16:49:01 +0200 Subject: [PATCH 05/70] [add] read event info from obsDMT pickle file --- pylot/core/io/data.py | 4 +++- pylot/core/util/event.py | 14 ++++++++++++++ pylot/core/util/obspyDMT_interface.py | 18 +++++++++++++++++- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/pylot/core/io/data.py b/pylot/core/io/data.py index 77b24a3d..aa42738b 100644 --- a/pylot/core/io/data.py +++ b/pylot/core/io/data.py @@ -15,7 +15,7 @@ from pylot.core.util.event import Event from pylot.core.util.utils import fnConstructor, full_range, remove_underscores, check4gaps, check4doubled, \ check4rotated, trim_station_components import pylot.core.loc.velest as velest - +from pylot.core.util.obspyDMT_interface import qml_from_obspyDMT class Data(object): """ @@ -60,6 +60,8 @@ class Data(object): raise NotImplementedError('PILOT location information ' 'read support not yet ' 'implemeted.') + elif 'event.pkl' in evtdata: + evtdata = qml_from_obspyDMT(evtdata) else: raise e else: diff --git a/pylot/core/util/event.py b/pylot/core/util/event.py index 4ded8d50..a4f1e9cb 100644 --- a/pylot/core/util/event.py +++ b/pylot/core/util/event.py @@ -7,6 +7,7 @@ from obspy import UTCDateTime from obspy.core.event import Event as ObsPyEvent from obspy.core.event import Origin, ResourceIdentifier from pylot.core.io.phases import picks_from_picksdict +from pylot.core.util.obspyDMT_interface import qml_from_obspyDMT class Event(ObsPyEvent): @@ -33,6 +34,7 @@ class Event(ObsPyEvent): self._testEvent = False self._refEvent = False self.get_notes() + self.get_obspy_event_info() def get_notes_path(self): """ @@ -43,6 +45,18 @@ class Event(ObsPyEvent): notesfile = os.path.join(self.path, 'notes.txt') return notesfile + def get_obspy_event_info(self): + infile_pickle = os.path.join(self.path, 'info/event.pkl') + if not os.path.isfile(infile_pickle): + return + try: + event_dmt = qml_from_obspyDMT(infile_pickle) + except Exception as e: + print('Could not get obspy event info: {}'.format(e)) + return + self.magnitudes = event_dmt.magnitudes + self.origins = event_dmt.origins + def get_notes(self): """ set self.note attribute to content of notes file diff --git a/pylot/core/util/obspyDMT_interface.py b/pylot/core/util/obspyDMT_interface.py index 661e4f5b..47d5c687 100644 --- a/pylot/core/util/obspyDMT_interface.py +++ b/pylot/core/util/obspyDMT_interface.py @@ -25,4 +25,20 @@ def check_obspydmt_eventfolder(folder): except Exception as e: return False, e -check_obspydmt_eventfolder('20110311_054623.a') \ No newline at end of file +def qml_from_obspyDMT(path): + import pickle + from obspy.core.event import Event, Magnitude, Origin + + if not os.path.exists(path): + return IOError('Could not find Event at {}'.format(path)) + infile = open(path, 'rb') + event_dmt = pickle.load(infile) + ev = Event(resource_id=event_dmt['event_id']) + origin = Origin(resource_id=event_dmt['origin_id'], time=event_dmt['datetime'], longitude=event_dmt['longitude'], + latitude=event_dmt['latitude'], depth=event_dmt['depth']) + mag = Magnitude(mag=event_dmt['magnitude'], magnitude_type=event_dmt['magnitude_type'], + origin_id=event_dmt['origin_id']) + ev.magnitudes.append(mag) + ev.origins.append(origin) + return ev + From d3de33a12bc569750ccd2ffc50569858edba548b Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 23 Apr 2018 17:00:09 +0200 Subject: [PATCH 06/70] [add] lineEdit showing if using processed/raw data --- PyLoT.py | 20 ++++++++++++++++++-- pylot/core/io/data.py | 12 ++++++++---- pylot/core/util/widgets.py | 25 ++++++++++++++++++------- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index 6d56c19f..f713d4b1 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -1667,6 +1667,21 @@ class MainWindow(QMainWindow): metadata=self.metadata, obspy_dmt=obspy_dmt) + def setWFstatus(self): + ''' + show status of current data, can be either 'raw' or 'processed' + :param status: + :return: + ''' + status = self.data.processed + wf_stat_color = {True: 'green', + False: 'black', + None: None} + wf_stat = {True: 'processed', + False: 'raw', + None: None} + self.dataPlot.setPermTextRight(wf_stat[status], wf_stat_color[status]) + def check_plot_quantity(self): settings = QSettings() nth_sample = int(settings.value("nth_sample")) if settings.value("nth_sample") else 1 @@ -1807,6 +1822,7 @@ class MainWindow(QMainWindow): if True in self.comparable.values(): self.compare_action.setEnabled(True) self.draw() + self.setWFstatus() def checkEvent4comparison(self, event): if event.pylot_picks and event.pylot_autopicks: @@ -3212,9 +3228,9 @@ class MainWindow(QMainWindow): self.fill_eventbox() self.getPlotWidget().draw() if self.plot_method == 'fast': - self.dataPlot.setPermText('MIN/MAX plot', color='red') + self.dataPlot.setPermTextMid('MIN/MAX plot', color='red') else: - self.dataPlot.setPermText() + self.dataPlot.setPermTextMid() def _setDirty(self): self.setDirty(True) diff --git a/pylot/core/io/data.py b/pylot/core/io/data.py index aa42738b..cd06a9b5 100644 --- a/pylot/core/io/data.py +++ b/pylot/core/io/data.py @@ -74,6 +74,7 @@ class Data(object): self.wforiginal = None self.cuttimes = None self.dirty = False + self.processed = None def __str__(self): return str(self.wfdata) @@ -381,11 +382,14 @@ class Data(object): self.wfsyn = Stream() wffnames = None wffnames_syn = None - wfdir = 'raw' - for fname in fnames: - if fname.endswith('processed'): - wfdir = 'processed' if obspy_dmt: + wfdir = 'raw' + self.processed = False + for fname in fnames: + if fname.endswith('processed'): + wfdir = 'processed' + self.processed = True + break for fpath in fnames: if fpath.endswith(wfdir): wffnames = [os.path.join(fpath, fname) for fname in os.listdir(fpath)] diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 89bc851c..b6b8a07d 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -454,14 +454,13 @@ class WaveformWidgetPG(QtGui.QWidget): # create plot self.main_layout = QtGui.QVBoxLayout() self.label_layout = QtGui.QHBoxLayout() - self.status_label = QtGui.QLabel() - self.perm_label = QtGui.QLabel() - self.setLayout(self.main_layout) + self.add_labels() self.plotWidget = self.pg.PlotWidget(self.parent(), title=title) self.main_layout.addWidget(self.plotWidget) self.main_layout.addLayout(self.label_layout) self.label_layout.addWidget(self.status_label) - self.label_layout.addWidget(self.perm_label) + self.label_layout.addWidget(self.perm_label_mid) + self.label_layout.addWidget(self.perm_label_right) self.plotWidget.showGrid(x=False, y=True, alpha=0.3) self.plotWidget.hideAxis('bottom') self.plotWidget.hideAxis('left') @@ -494,12 +493,24 @@ class WaveformWidgetPG(QtGui.QWidget): self.vLine.setPos(mousePoint.x()) self.hLine.setPos(mousePoint.y()) + def add_labels(self): + self.status_label = QtGui.QLabel() + self.perm_label_mid = QtGui.QLabel() + self.perm_label_mid.setAlignment(4) + self.perm_label_right = QtGui.QLabel() + self.perm_label_right.setAlignment(2) + self.setLayout(self.main_layout) + def getPlotDict(self): return self.plotdict - def setPermText(self, text=None, color='black'): - self.perm_label.setText(text) - self.perm_label.setStyleSheet('color: {}'.format(color)) + def setPermTextMid(self, text=None, color='black'): + self.perm_label_mid.setText(text) + self.perm_label_mid.setStyleSheet('color: {}'.format(color)) + + def setPermTextRight(self, text=None, color='black'): + self.perm_label_right.setText(text) + self.perm_label_right.setStyleSheet('color: {}'.format(color)) def setPlotDict(self, key, value): self.plotdict[key] = value From 073a71e1503e60fd0eec4414c2353044a00c0fc4 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 24 Apr 2018 15:37:15 +0200 Subject: [PATCH 07/70] [add] origin/mag to eventBox --- PyLoT.py | 23 +++++++++++++++++++++-- pylot/core/util/widgets.py | 10 +++++++--- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index f713d4b1..9dc7de29 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -1250,6 +1250,17 @@ class MainWindow(QMainWindow): event_ref = event.isRefEvent() event_test = event.isTestEvent() + time = lat = lon = depth = mag = None + if len(event.origins) == 1: + origin = event.origins[0] + time = origin.time + 0 # add 0 because there was an exception for time = 0s + lat = origin.latitude + lon = origin.longitude + depth = origin.depth + if len(event.magnitudes) == 1: + magnitude = event.magnitudes[0] + mag = magnitude.mag + # text = '{path:{plen}} | manual: [{p:3d}] | auto: [{a:3d}]' # text = text.format(path=event_path, # plen=plmax, @@ -1257,6 +1268,11 @@ class MainWindow(QMainWindow): # a=event_nautopicks) item_path = QtGui.QStandardItem('{path:{plen}}'.format(path=event_path, plen=plmax)) + item_time = QtGui.QStandardItem('{}'.format(time)) + item_lat = QtGui.QStandardItem('{}'.format(lat)) + item_lon = QtGui.QStandardItem('{}'.format(lon)) + item_depth = QtGui.QStandardItem('{}'.format(depth)) + item_mag = QtGui.QStandardItem('{}'.format(mag)) item_nmp = QtGui.QStandardItem(str(ma_count['manual'])) item_nmp.setIcon(self.manupicksicon_small) item_nap = QtGui.QStandardItem(str(ma_count['auto'])) @@ -1282,7 +1298,10 @@ class MainWindow(QMainWindow): # item.setFont(font) # item2.setForeground(QtGui.QColor('black')) # item2.setFont(font) - itemlist = [item_path, item_nmp, item_nap, item_ref, item_test, item_notes] + itemlist = [item_path, item_time, item_lat, item_lon, item_depth, + item_mag, item_nmp, item_nap, item_ref, item_test, item_notes] + for item in itemlist: + item.setTextAlignment(Qt.AlignCenter) if event_test and select_events == 'ref': for item in itemlist: item.setEnabled(False) @@ -2935,7 +2954,7 @@ class MainWindow(QMainWindow): if hasattr(event, 'origins'): if event.origins: origin = event.origins[0] - item_time.setText(str(origin.time).split('.')[0]) + item_time.setText(str(origin.time + 0).split('.')[0]) # +0 as workaround in case time=0s item_lon.setText(str(origin.longitude)) item_lat.setText(str(origin.latitude)) item_depth.setText(str(origin.depth)) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index b6b8a07d..5f9c9c03 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -576,6 +576,8 @@ class WaveformWidgetPG(QtGui.QWidget): st_syn = wfsyn.select(network=network, station=station, channel=channel) if st_syn: trace_syn = st_syn[0].copy() + else: + trace_syn = Trace() if mapping: comp = channel[-1] n = compclass.getPlotPosition(str(comp)) @@ -592,7 +594,9 @@ class WaveformWidgetPG(QtGui.QWidget): time_ax_syn = prepTimeAxis(stime_syn, trace_syn) if method == 'fast': - trace.data, time_ax = self.minMax(trace, time_ax) + trace.data, time_ax = self.minMax(trace, time_ax) + if trace_syn: + trace_syn.data, time_ax_syn = self.minMax(trace_syn, time_ax_syn) if time_ax not in [None, []]: if not scaleddata: @@ -605,10 +609,10 @@ class WaveformWidgetPG(QtGui.QWidget): times = np.array([time for index, time in enumerate(time_ax) if not index % nth_sample]) times_syn = np.array([time for index, time in enumerate(time_ax_syn) if not index % nth_sample] if st_syn else []) trace.data = np.array([datum + n for index, datum in enumerate(trace.data) if not index % nth_sample]) - trace.data_syn = np.array([datum + n for index, datum in enumerate(trace.data_syn) + trace_syn.data = np.array([datum + n for index, datum in enumerate(trace_syn.data) if not index % nth_sample] if st_syn else []) plots.append((times, trace.data, - times_syn, trace.data_syn)) + times_syn, trace_syn.data)) self.setPlotDict(n, (station, channel, network)) self.xlabel = 'seconds since {0}'.format(self.wfstart) self.ylabel = '' From d6150c5d1a3c201b380e499dc092c99c6e6172b1 Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 25 Apr 2018 13:48:06 +0200 Subject: [PATCH 08/70] [new] disable event selection of folder is empty --- PyLoT.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/PyLoT.py b/PyLoT.py index 9dc7de29..ffe69bf3 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -1302,7 +1302,7 @@ class MainWindow(QMainWindow): item_mag, item_nmp, item_nap, item_ref, item_test, item_notes] for item in itemlist: item.setTextAlignment(Qt.AlignCenter) - if event_test and select_events == 'ref': + if event_test and select_events == 'ref' or self.isEmpty(event_path): for item in itemlist: item.setEnabled(False) model.appendRow(itemlist) @@ -1316,6 +1316,16 @@ class MainWindow(QMainWindow): eventBox.setCurrentIndex(index) self.refreshRefTestButtons() + def isEmpty(self, event_path): + wf_stat = {True: 'processed', + False: 'raw', + None: None} + + wf_dir = wf_stat[self.data.processed] + if wf_dir is not None: + event_path = os.path.join(event_path, wf_dir) + return not bool(os.listdir(event_path)) + def filename_from_action(self, action): if action.data() is None: filt = "Supported file formats" \ From 644470f1567582d7df6229981dd3dfabff2f8c53 Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 25 Apr 2018 14:01:05 +0200 Subject: [PATCH 09/70] [bugfix] was only checking current data processing state --- PyLoT.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PyLoT.py b/PyLoT.py index ffe69bf3..80e2b15a 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -1321,9 +1321,12 @@ class MainWindow(QMainWindow): False: 'raw', None: None} + # self.data.processed is only None for PyLoT datastructure, else True or False wf_dir = wf_stat[self.data.processed] if wf_dir is not None: event_path = os.path.join(event_path, wf_dir) + if wf_dir is 'processed' and not os.path.exists(event_path): + event_path = os.path.join(event_path, 'raw') return not bool(os.listdir(event_path)) def filename_from_action(self, action): From be82706413195d39a3043b83b9c6ab1265f2b394 Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 25 Apr 2018 14:04:31 +0200 Subject: [PATCH 10/70] [bugfix] event_path overwritten --- PyLoT.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index 80e2b15a..de4c879f 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -1324,10 +1324,14 @@ class MainWindow(QMainWindow): # self.data.processed is only None for PyLoT datastructure, else True or False wf_dir = wf_stat[self.data.processed] if wf_dir is not None: - event_path = os.path.join(event_path, wf_dir) - if wf_dir is 'processed' and not os.path.exists(event_path): - event_path = os.path.join(event_path, 'raw') - return not bool(os.listdir(event_path)) + wf_path = os.path.join(event_path, wf_dir) + if wf_dir is 'processed' and not os.path.exists(wf_path): + wf_path = os.path.join(event_path, 'raw') + else: + wf_path = event_path + if not os.path.exists(wf_path): + return True + return not bool(os.listdir(wf_path)) def filename_from_action(self, action): if action.data() is None: From c90a2f6ae19326b5edb27192a39a67355741d47d Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 26 Apr 2018 14:50:18 +0200 Subject: [PATCH 11/70] [bugfix] forgot to replace PyQt4 with PySide --- icons_rc_2.py | 2 +- icons_rc_3.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/icons_rc_2.py b/icons_rc_2.py index bcf764af..9f36b183 100644 --- a/icons_rc_2.py +++ b/icons_rc_2.py @@ -7,7 +7,7 @@ # # WARNING! All changes made in this file will be lost! -from PyQt4 import QtCore +from PySide import QtCore qt_resource_data = "\ \x00\x00\x9e\x04\ diff --git a/icons_rc_3.py b/icons_rc_3.py index a437650d..963cf353 100644 --- a/icons_rc_3.py +++ b/icons_rc_3.py @@ -7,7 +7,7 @@ # # WARNING! All changes made in this file will be lost! -from PyQt4 import QtCore +from PySide import QtCore qt_resource_data = "\ \x00\x00\x9e\x04\ From 4c42d34adcee8916925af89482ac662f7e81c1ec Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 26 Apr 2018 14:52:17 +0200 Subject: [PATCH 12/70] [bugfix] check for time_ax not working this way --- pylot/core/util/widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 5f9c9c03..5bd3cc52 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -598,7 +598,7 @@ class WaveformWidgetPG(QtGui.QWidget): if trace_syn: trace_syn.data, time_ax_syn = self.minMax(trace_syn, time_ax_syn) - if time_ax not in [None, []]: + if len(time_ax) > 0: if not scaleddata: trace.detrend('constant') trace.normalize(np.max(np.abs(trace.data)) * 2) From 8073a872c1d11536dad0b740a4266cbdd7e98c44 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 26 Apr 2018 16:26:03 +0200 Subject: [PATCH 13/70] [add] event colored grey if folder isEmpty --- PyLoT.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PyLoT.py b/PyLoT.py index 1fa99970..b27a6536 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -3019,6 +3019,9 @@ class MainWindow(QMainWindow): if index%2: set_background_color(column, QtGui.QColor(*(245, 245, 245, 255))) + if self.isEmpty(event.path): + set_foreground_color(column, QtGui.QColor(*(180, 180, 180, 255))) + if event == current_event: set_foreground_color(column, QtGui.QColor(*(0, 143, 143, 255))) From 2554f6ca7e74851472dc55bf4cc21ca4cd027df8 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 26 Apr 2018 16:32:05 +0200 Subject: [PATCH 14/70] [new] dont show plot if no data --- pylot/core/util/widgets.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 5bd3cc52..57f26899 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -524,7 +524,9 @@ class WaveformWidgetPG(QtGui.QWidget): method='normal'): if not wfdata: print('Nothing to plot.') + self.setVisible(False) return + self.setVisible(True) self.title = title self.clearPlotDict() self.wfstart, self.wfend = full_range(wfdata) From 65f0d23f072c7212b0e569c28cd90dd58446d4aa Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 26 Apr 2018 16:37:57 +0200 Subject: [PATCH 15/70] [revert] changes not working due to Thread --- pylot/core/util/widgets.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 57f26899..5bd3cc52 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -524,9 +524,7 @@ class WaveformWidgetPG(QtGui.QWidget): method='normal'): if not wfdata: print('Nothing to plot.') - self.setVisible(False) return - self.setVisible(True) self.title = title self.clearPlotDict() self.wfstart, self.wfend = full_range(wfdata) From ae4c345fa7c14045f100fbec366deedc1f8a33a9 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 26 Apr 2018 16:40:46 +0200 Subject: [PATCH 16/70] [update] same functionality but within main thread --- PyLoT.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PyLoT.py b/PyLoT.py index b27a6536..286d06cf 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -1810,13 +1810,14 @@ class MainWindow(QMainWindow): def finish_pg_plot(self): self.getPlotWidget().updateWidget() plots, gaps = self.wfp_thread.data + # do not show plot if no data are given + self.dataPlot.setVisible(len(plots) > 0) for times, data, times_syn, data_syn in plots: self.dataPlot.plotWidget.getPlotItem().plot(times, data, pen=self.dataPlot.pen_linecolor) if len(data_syn) > 0: self.dataPlot.plotWidget.getPlotItem().plot(times_syn, data_syn, pen=self.dataPlot.pen_linecolor_syn) - self.dataPlot.reinitMoveProxy() self.dataPlot.plotWidget.showAxis('left') self.dataPlot.plotWidget.showAxis('bottom') From f49d323c1342c35a221cdf18ae8200f03c49d942 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 27 Apr 2018 10:45:20 +0200 Subject: [PATCH 17/70] [add] no data label --- PyLoT.py | 19 ++++++++++++------- pylot/core/util/widgets.py | 2 -- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index 286d06cf..ad25169f 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -616,6 +616,10 @@ class MainWindow(QMainWindow): # add scroll area used in case number of traces gets too high self.wf_scroll_area = QtGui.QScrollArea(self) + self.wf_scroll_area.setVisible(False) + self.no_data_label = QLabel('No Data') + self.no_data_label.setStyleSheet('color: red') + self.no_data_label.setAlignment(Qt.AlignCenter) # create central matplotlib figure canvas widget self.init_wfWidget() @@ -638,6 +642,7 @@ class MainWindow(QMainWindow): self.tabs.addTab(array_tab, 'Array Map') self.tabs.addTab(events_tab, 'Eventlist') + self.wf_layout.addWidget(self.no_data_label) self.wf_layout.addWidget(self.wf_scroll_area) self.wf_scroll_area.setWidgetResizable(True) self.init_array_tab() @@ -1811,7 +1816,8 @@ class MainWindow(QMainWindow): self.getPlotWidget().updateWidget() plots, gaps = self.wfp_thread.data # do not show plot if no data are given - self.dataPlot.setVisible(len(plots) > 0) + self.wf_scroll_area.setVisible(len(plots) > 0) + self.no_data_label.setVisible(not len(plots) > 0) for times, data, times_syn, data_syn in plots: self.dataPlot.plotWidget.getPlotItem().plot(times, data, pen=self.dataPlot.pen_linecolor) @@ -1819,8 +1825,6 @@ class MainWindow(QMainWindow): self.dataPlot.plotWidget.getPlotItem().plot(times_syn, data_syn, pen=self.dataPlot.pen_linecolor_syn) self.dataPlot.reinitMoveProxy() - self.dataPlot.plotWidget.showAxis('left') - self.dataPlot.plotWidget.showAxis('bottom') self.highlight_stations() def finishWaveformDataPlot(self): @@ -1898,12 +1902,10 @@ class MainWindow(QMainWindow): comparable[event.pylot_id] = self.checkEvent4comparison(event) return comparable - def clearWaveformDataPlot(self): + def clearWaveformDataPlot(self, refresh_plot=False): self.disconnectWFplotEvents() if self.pg: self.dataPlot.plotWidget.getPlotItem().clear() - self.dataPlot.plotWidget.hideAxis('bottom') - self.dataPlot.plotWidget.hideAxis('left') else: for ax in self.dataPlot.axes: ax.cla() @@ -1919,6 +1921,9 @@ class MainWindow(QMainWindow): self.openEventAction.setEnabled(False) self.openEventsAutoAction.setEnabled(False) self.loadpilotevent.setEnabled(False) + if not refresh_plot: + self.wf_scroll_area.setVisible(False) + self.no_data_label.setVisible(True) self.disableSaveEventAction() self.draw() @@ -1927,7 +1932,7 @@ class MainWindow(QMainWindow): Open a modal thread to plot current waveform data. ''' self.check_plot_quantity() - self.clearWaveformDataPlot() + self.clearWaveformDataPlot(refresh_plot=True) self.wfp_thread = Thread(self, self.plotWaveformData, arg=filter, progressText='Plotting waveform data...', diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 5bd3cc52..da4adbe0 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -462,8 +462,6 @@ class WaveformWidgetPG(QtGui.QWidget): self.label_layout.addWidget(self.perm_label_mid) self.label_layout.addWidget(self.perm_label_right) self.plotWidget.showGrid(x=False, y=True, alpha=0.3) - self.plotWidget.hideAxis('bottom') - self.plotWidget.hideAxis('left') self.wfstart, self.wfend = 0, 0 self.pen_multicursor = self.pg.mkPen(self.parent()._style['multicursor']['rgba']) self.pen_linecolor = self.pg.mkPen(self.parent()._style['linecolor']['rgba']) From 20eb54e9c5675aa1684545e4625014ce86934927 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 5 Jun 2018 13:47:00 +0200 Subject: [PATCH 18/70] [minor] gitignore modification --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c99398e7..78b6b4e7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.pyc *~ pylot/RELEASE-VERSION +*.idea From cbba41f16a9d5101cf507e42730b5befa2932d5e Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 5 Jun 2018 14:24:00 +0200 Subject: [PATCH 19/70] [bugfix] autoPickWidget not enabled again after Error --- PyLoT.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/PyLoT.py b/PyLoT.py index ad25169f..c143e036 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -2457,6 +2457,7 @@ class MainWindow(QMainWindow): self.mp_worker.signals.message.connect(self.addListItem) self.mp_worker.signals.result.connect(self.finalizeAutoPick) + self.mp_worker.signals.finished.connect(self.enableAutoPickWidget) self.mp_thread.start(self.mp_worker) @@ -2471,7 +2472,6 @@ class MainWindow(QMainWindow): self.apd_sge.show() def finalizeAutoPick(self, result): - self.apw.enable(True) if result: self.init_canvas_dict_wadatijack() for eventID in result.keys(): @@ -2487,6 +2487,9 @@ class MainWindow(QMainWindow): self.drawPicks(picktype='auto') self.draw() + def enableAutoPickWidget(self, event=None): + self.apw.enable(True) + def get_event_from_id(self, eventID): for event in self.project.eventlist: if event.pylot_id == eventID: From d695c0016aebf2980c0258a8eeaf1d9038c65b02 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 5 Jun 2018 15:06:33 +0200 Subject: [PATCH 20/70] [bugfix] delete_later not caused tuneAutoPicker to malfunction --- pylot/core/util/widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index da4adbe0..01c02bd3 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -1282,6 +1282,7 @@ class PickDlg(QDialog): event=None, filteroptions=None, model='iasp91'): super(PickDlg, self).__init__(parent, 1) self.orig_parent = parent + self.setAttribute(Qt.WA_DeleteOnClose) # initialize attributes self.parameter = parameter @@ -1414,7 +1415,6 @@ class PickDlg(QDialog): self.setWindowTitle('Pickwindow on station: {}'.format(self.getStation())) self.setWindowState(QtCore.Qt.WindowMaximized) - self.deleteLater() def setupUi(self): menuBar = QtGui.QMenuBar(self) From 9b5fe3baba151edf3963367594ee7c7cf94af941 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 5 Jun 2018 15:07:06 +0200 Subject: [PATCH 21/70] [bugfix] saving xml when tuning autopicker unnecessary (and caused id mismatch) --- PyLoT.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index c143e036..e5c02e7a 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -2348,7 +2348,7 @@ class MainWindow(QMainWindow): def tune_autopicker(self): ''' - Initiates TuneAutopicker widget use to interactively + Initiates TuneAutopicker widget used to interactively tune parameters for autopicking algorithm. ''' # figures and canvas have to be iniated from the main GUI @@ -2447,7 +2447,8 @@ class MainWindow(QMainWindow): 'iplot': 0, 'fig_dict': None, 'fig_dict_wadatijack': self.fig_dict_wadatijack, - 'locflag': 0} + 'locflag': 0, + 'savexml': False} # init pick thread self.mp_thread = QtCore.QThreadPool() From 5e161d308af5d7f397c2857af901fad48749117b Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 5 Jun 2018 15:11:43 +0200 Subject: [PATCH 22/70] [bugfix] trying to access station not in autopicks dictionary --- pylot/core/util/widgets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 01c02bd3..9d20d9b6 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -3127,7 +3127,8 @@ class TuneAutopicker(QWidget): def get_current_event_autopicks(self, station): event = self.get_current_event() if event.pylot_autopicks: - return event.pylot_autopicks[station] + if station in event.pylot_autopicks: + return event.pylot_autopicks[station] def get_current_station(self): return str(self.stationBox.currentText()).split('.')[-1] From 8155389b3d2ca793210c41b2387242485b02cdd0 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 8 Jun 2018 14:18:28 +0200 Subject: [PATCH 23/70] [new] add qcombobox for raw/processed selection --- PyLoT.py | 59 ++++++++++++++++++++++++-------------- pylot/core/io/data.py | 42 +++++++++++++-------------- pylot/core/util/widgets.py | 24 ++++++++++++---- 3 files changed, 76 insertions(+), 49 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index e5c02e7a..c4837690 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -1001,6 +1001,7 @@ class MainWindow(QMainWindow): # TODO: add dataStructure class for obspyDMT here, this is just a workaround! eventpath = self.get_current_event_path(eventbox) basepath = eventpath.split(os.path.basename(eventpath))[0] + obspy_dmt = check_obspydmt_structure(basepath) if self.dataStructure: if not eventpath: return @@ -1659,10 +1660,10 @@ class MainWindow(QMainWindow): if self._eventChanged[1]: self.refresh_array_map() if not plotted and self._eventChanged[0]: - # newWF(False) = load data without plotting + # newWF(plot=False) = load data without plotting self.newWF(plot=False) - def newWF(self, plot=True): + def newWF(self, event=None, plot=True): ''' Load new data and plot if necessary. ''' @@ -1703,25 +1704,42 @@ class MainWindow(QMainWindow): eventpath = self.get_current_event_path() basepath = eventpath.split(os.path.basename(eventpath))[0] obspy_dmt = check_obspydmt_structure(basepath) - self.data.setWFData(self.fnames, - checkRotated=True, - metadata=self.metadata, - obspy_dmt=obspy_dmt) + if obspy_dmt: + self.prepareObspyDMT_data(eventpath) - def setWFstatus(self): - ''' - show status of current data, can be either 'raw' or 'processed' - :param status: - :return: - ''' - status = self.data.processed - wf_stat_color = {True: 'green', - False: 'black', - None: None} - wf_stat = {True: 'processed', - False: 'raw', - None: None} - self.dataPlot.setPermTextRight(wf_stat[status], wf_stat_color[status]) + self.data.setWFData(self.fnames, + self.fnames_syn, + checkRotated=True, + metadata=self.metadata) + + def prepareObspyDMT_data(self, eventpath): + qcbox_processed = self.dataPlot.perm_qcbox_right + qcbox_processed.setEnabled(False) + for fpath in os.listdir(eventpath): + fpath = fpath.split('/')[-1] + if 'syngine' in fpath: + eventpath_syn = os.path.join(eventpath, fpath) + self.fnames_syn = [os.path.join(eventpath_syn, filename) for filename in os.listdir(eventpath_syn)] + if 'processed' in fpath: + qcbox_processed.setEnabled(True) + wftype = qcbox_processed.currentText() if qcbox_processed.isEnabled() else 'raw' + eventpath_dmt = os.path.join(eventpath, wftype) + self.fnames = [os.path.join(eventpath_dmt, filename) for filename in os.listdir(eventpath_dmt)] + + # def setWFstatus(self): + # ''' + # show status of current data, can be either 'raw' or 'processed' + # :param status: + # :return: + # ''' + # status = self.data.processed + # wf_stat_color = {True: 'green', + # False: 'black', + # None: None} + # wf_stat = {True: 'processed', + # False: 'raw', + # None: None} + # self.dataPlot.setQCboxItem(wf_stat[status]) def check_plot_quantity(self): """ @@ -1867,7 +1885,6 @@ class MainWindow(QMainWindow): if True in self.comparable.values(): self.compare_action.setEnabled(True) self.draw() - self.setWFstatus() def checkEvent4comparison(self, event): if event.pylot_picks and event.pylot_autopicks: diff --git a/pylot/core/io/data.py b/pylot/core/io/data.py index cd06a9b5..f10242db 100644 --- a/pylot/core/io/data.py +++ b/pylot/core/io/data.py @@ -371,7 +371,7 @@ class Data(object): data.filter(**kwargs) self.dirty = True - def setWFData(self, fnames, checkRotated=False, metadata=None, obspy_dmt=False): + def setWFData(self, fnames, fnames_syn=None, checkRotated=False, metadata=None): """ Clear current waveform data and set given waveform data :param fnames: waveform data names to append @@ -380,27 +380,25 @@ class Data(object): self.wfdata = Stream() self.wforiginal = None self.wfsyn = Stream() - wffnames = None - wffnames_syn = None - if obspy_dmt: - wfdir = 'raw' - self.processed = False - for fname in fnames: - if fname.endswith('processed'): - wfdir = 'processed' - self.processed = True - break - for fpath in fnames: - if fpath.endswith(wfdir): - wffnames = [os.path.join(fpath, fname) for fname in os.listdir(fpath)] - if 'syngine' in fpath.split('/')[-1]: - wffnames_syn = [os.path.join(fpath, fname) for fname in os.listdir(fpath)] - else: - wffnames = fnames - if wffnames is not None: - self.appendWFData(wffnames) - if wffnames_syn is not None: - self.appendWFData(wffnames_syn, synthetic=True) + # if obspy_dmt: + # wfdir = 'raw' + # self.processed = False + # for fname in fnames: + # if fname.endswith('processed'): + # wfdir = 'processed' + # self.processed = True + # break + # for fpath in fnames: + # if fpath.endswith(wfdir): + # wffnames = [os.path.join(fpath, fname) for fname in os.listdir(fpath)] + # if 'syngine' in fpath.split('/')[-1]: + # wffnames_syn = [os.path.join(fpath, fname) for fname in os.listdir(fpath)] + # else: + # wffnames = fnames + if fnames is not None: + self.appendWFData(fnames) + if fnames_syn is not None: + self.appendWFData(fnames_syn, synthetic=True) else: return False diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 9d20d9b6..a3defac9 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -455,12 +455,13 @@ class WaveformWidgetPG(QtGui.QWidget): self.main_layout = QtGui.QVBoxLayout() self.label_layout = QtGui.QHBoxLayout() self.add_labels() + self.connect_signals() self.plotWidget = self.pg.PlotWidget(self.parent(), title=title) self.main_layout.addWidget(self.plotWidget) self.main_layout.addLayout(self.label_layout) self.label_layout.addWidget(self.status_label) self.label_layout.addWidget(self.perm_label_mid) - self.label_layout.addWidget(self.perm_label_right) + self.label_layout.addWidget(self.perm_qcbox_right) self.plotWidget.showGrid(x=False, y=True, alpha=0.3) self.wfstart, self.wfend = 0, 0 self.pen_multicursor = self.pg.mkPen(self.parent()._style['multicursor']['rgba']) @@ -491,12 +492,17 @@ class WaveformWidgetPG(QtGui.QWidget): self.vLine.setPos(mousePoint.x()) self.hLine.setPos(mousePoint.y()) + def connect_signals(self): + self.perm_qcbox_right.currentIndexChanged.connect(self.parent().newWF) + def add_labels(self): self.status_label = QtGui.QLabel() self.perm_label_mid = QtGui.QLabel() self.perm_label_mid.setAlignment(4) - self.perm_label_right = QtGui.QLabel() - self.perm_label_right.setAlignment(2) + self.perm_qcbox_right = QtGui.QComboBox() + self.addQCboxItem('raw', 'black') + self.addQCboxItem('processed', 'green') + #self.perm_qcbox_right.setAlignment(2) self.setLayout(self.main_layout) def getPlotDict(self): @@ -506,9 +512,15 @@ class WaveformWidgetPG(QtGui.QWidget): self.perm_label_mid.setText(text) self.perm_label_mid.setStyleSheet('color: {}'.format(color)) - def setPermTextRight(self, text=None, color='black'): - self.perm_label_right.setText(text) - self.perm_label_right.setStyleSheet('color: {}'.format(color)) + def addQCboxItem(self, text=None, color='black'): + item = QtGui.QStandardItem(text) + model = self.perm_qcbox_right.model() + model.appendRow(item) + item.setForeground(QtGui.QColor('{}'.format(color))) + + def setQCboxItem(self, text): + index = self.perm_qcbox_right.findText(text) + self.perm_qcbox_right.setCurrentIndex(index) def setPlotDict(self, key, value): self.plotdict[key] = value From 083e5c8fe910e581a54b70eee36aac6b3cfc39cd Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 8 Jun 2018 14:27:43 +0200 Subject: [PATCH 24/70] [new] synthetics checkbox --- PyLoT.py | 7 ++++++- pylot/core/util/widgets.py | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/PyLoT.py b/PyLoT.py index c4837690..d3367cfa 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -1701,6 +1701,7 @@ class MainWindow(QMainWindow): # else: # ans = False self.fnames = self.getWFFnames_from_eventbox() + self.fnames_syn = [] eventpath = self.get_current_event_path() basepath = eventpath.split(os.path.basename(eventpath))[0] obspy_dmt = check_obspydmt_structure(basepath) @@ -1714,12 +1715,16 @@ class MainWindow(QMainWindow): def prepareObspyDMT_data(self, eventpath): qcbox_processed = self.dataPlot.perm_qcbox_right + qcheckb_syn = self.dataPlot.syn_checkbox qcbox_processed.setEnabled(False) + qcheckb_syn.setEnabled(False) for fpath in os.listdir(eventpath): fpath = fpath.split('/')[-1] if 'syngine' in fpath: eventpath_syn = os.path.join(eventpath, fpath) - self.fnames_syn = [os.path.join(eventpath_syn, filename) for filename in os.listdir(eventpath_syn)] + qcheckb_syn.setEnabled(True) + if self.dataPlot.syn_checkbox.isChecked(): + self.fnames_syn = [os.path.join(eventpath_syn, filename) for filename in os.listdir(eventpath_syn)] if 'processed' in fpath: qcbox_processed.setEnabled(True) wftype = qcbox_processed.currentText() if qcbox_processed.isEnabled() else 'raw' diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index a3defac9..c53333eb 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -461,6 +461,7 @@ class WaveformWidgetPG(QtGui.QWidget): self.main_layout.addLayout(self.label_layout) self.label_layout.addWidget(self.status_label) self.label_layout.addWidget(self.perm_label_mid) + self.label_layout.addWidget(self.syn_checkbox) self.label_layout.addWidget(self.perm_qcbox_right) self.plotWidget.showGrid(x=False, y=True, alpha=0.3) self.wfstart, self.wfend = 0, 0 @@ -494,12 +495,14 @@ class WaveformWidgetPG(QtGui.QWidget): def connect_signals(self): self.perm_qcbox_right.currentIndexChanged.connect(self.parent().newWF) + self.syn_checkbox.clicked.connect(self.parent().newWF) def add_labels(self): self.status_label = QtGui.QLabel() self.perm_label_mid = QtGui.QLabel() self.perm_label_mid.setAlignment(4) self.perm_qcbox_right = QtGui.QComboBox() + self.syn_checkbox = QtGui.QCheckBox('synthetics') self.addQCboxItem('raw', 'black') self.addQCboxItem('processed', 'green') #self.perm_qcbox_right.setAlignment(2) From f50e38241e9de4337d6f53294fbf202ef8e7ee91 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 8 Jun 2018 15:01:05 +0200 Subject: [PATCH 25/70] [minor] tweaks and finalization of obspyDMT options --- PyLoT.py | 26 +++++++++++++++++--------- pylot/core/util/widgets.py | 31 ++++++++++++++++++++++--------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index d3367cfa..32d4b0b2 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -1677,6 +1677,7 @@ class MainWindow(QMainWindow): call modal plot thread method when finished. ''' if load: + self.prepareLoadWaveformData() self.wfd_thread = Thread(self, self.loadWaveformData, progressText='Reading data input...', pb_widget=self.mainProgressBarWidget) @@ -1689,6 +1690,16 @@ class MainWindow(QMainWindow): if plot and not load: self.plotWaveformDataThread() + def prepareLoadWaveformData(self): + self.fnames = self.getWFFnames_from_eventbox() + self.fnames_syn = [] + eventpath = self.get_current_event_path() + basepath = eventpath.split(os.path.basename(eventpath))[0] + obspy_dmt = check_obspydmt_structure(basepath) + self.dataPlot.activateObspyDMToptions(obspy_dmt) + if obspy_dmt: + self.prepareObspyDMT_data(eventpath) + def loadWaveformData(self): ''' Load waveform data corresponding to current selected event. @@ -1700,13 +1711,6 @@ class MainWindow(QMainWindow): # ans = self.data.setWFData(self.getWFFnames()) # else: # ans = False - self.fnames = self.getWFFnames_from_eventbox() - self.fnames_syn = [] - eventpath = self.get_current_event_path() - basepath = eventpath.split(os.path.basename(eventpath))[0] - obspy_dmt = check_obspydmt_structure(basepath) - if obspy_dmt: - self.prepareObspyDMT_data(eventpath) self.data.setWFData(self.fnames, self.fnames_syn, @@ -1714,7 +1718,7 @@ class MainWindow(QMainWindow): metadata=self.metadata) def prepareObspyDMT_data(self, eventpath): - qcbox_processed = self.dataPlot.perm_qcbox_right + qcbox_processed = self.dataPlot.qcombo_processed qcheckb_syn = self.dataPlot.syn_checkbox qcbox_processed.setEnabled(False) qcheckb_syn.setEnabled(False) @@ -1727,7 +1731,11 @@ class MainWindow(QMainWindow): self.fnames_syn = [os.path.join(eventpath_syn, filename) for filename in os.listdir(eventpath_syn)] if 'processed' in fpath: qcbox_processed.setEnabled(True) - wftype = qcbox_processed.currentText() if qcbox_processed.isEnabled() else 'raw' + if qcbox_processed.isEnabled(): + wftype = qcbox_processed.currentText() + else: + wftype = 'raw' + qcbox_processed.setCurrentIndex(qcbox_processed.findText(wftype)) eventpath_dmt = os.path.join(eventpath, wftype) self.fnames = [os.path.join(eventpath_dmt, filename) for filename in os.listdir(eventpath_dmt)] diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index c53333eb..0df1b784 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -459,10 +459,8 @@ class WaveformWidgetPG(QtGui.QWidget): self.plotWidget = self.pg.PlotWidget(self.parent(), title=title) self.main_layout.addWidget(self.plotWidget) self.main_layout.addLayout(self.label_layout) - self.label_layout.addWidget(self.status_label) - self.label_layout.addWidget(self.perm_label_mid) - self.label_layout.addWidget(self.syn_checkbox) - self.label_layout.addWidget(self.perm_qcbox_right) + self.init_labels() + self.activateObspyDMToptions(False) self.plotWidget.showGrid(x=False, y=True, alpha=0.3) self.wfstart, self.wfend = 0, 0 self.pen_multicursor = self.pg.mkPen(self.parent()._style['multicursor']['rgba']) @@ -494,14 +492,25 @@ class WaveformWidgetPG(QtGui.QWidget): self.hLine.setPos(mousePoint.y()) def connect_signals(self): - self.perm_qcbox_right.currentIndexChanged.connect(self.parent().newWF) + self.qcombo_processed.activated.connect(self.parent().newWF) self.syn_checkbox.clicked.connect(self.parent().newWF) + def init_labels(self): + self.label_layout.addWidget(self.status_label) + self.label_layout.addWidget(self.perm_label_mid) + self.label_layout.addWidget(self.syn_checkbox) + self.label_layout.addWidget(self.qcombo_processed) + self.syn_checkbox.setLayoutDirection(Qt.RightToLeft) + self.label_layout.setStretch(0, 4) + self.label_layout.setStretch(1, 2) + self.label_layout.setStretch(2, 3) + self.label_layout.setStretch(3, 1) + def add_labels(self): self.status_label = QtGui.QLabel() self.perm_label_mid = QtGui.QLabel() self.perm_label_mid.setAlignment(4) - self.perm_qcbox_right = QtGui.QComboBox() + self.qcombo_processed = QtGui.QComboBox() self.syn_checkbox = QtGui.QCheckBox('synthetics') self.addQCboxItem('raw', 'black') self.addQCboxItem('processed', 'green') @@ -511,19 +520,23 @@ class WaveformWidgetPG(QtGui.QWidget): def getPlotDict(self): return self.plotdict + def activateObspyDMToptions(self, activate): + self.syn_checkbox.setVisible(activate) + self.qcombo_processed.setVisible(activate) + def setPermTextMid(self, text=None, color='black'): self.perm_label_mid.setText(text) self.perm_label_mid.setStyleSheet('color: {}'.format(color)) def addQCboxItem(self, text=None, color='black'): item = QtGui.QStandardItem(text) - model = self.perm_qcbox_right.model() + model = self.qcombo_processed.model() model.appendRow(item) item.setForeground(QtGui.QColor('{}'.format(color))) def setQCboxItem(self, text): - index = self.perm_qcbox_right.findText(text) - self.perm_qcbox_right.setCurrentIndex(index) + index = self.qcombo_processed.findText(text) + self.qcombo_processed.setCurrentIndex(index) def setPlotDict(self, key, value): self.plotdict[key] = value From 06cacdd4cb29515f2369320346b494b508cd106d Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 13 Jun 2018 17:01:05 +0200 Subject: [PATCH 26/70] [update] major improvements of array_map, code restyled, increased flexibility --- PyLoT.py | 9 +- .../util/{map_projection.py => array_map.py} | 269 ++++++++++-------- 2 files changed, 158 insertions(+), 120 deletions(-) rename pylot/core/util/{map_projection.py => array_map.py} (56%) diff --git a/PyLoT.py b/PyLoT.py index 32d4b0b2..96c30e4a 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -86,7 +86,7 @@ from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \ PylotCanvas, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \ getDataType, ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \ CompareEventsWidget -from pylot.core.util.map_projection import map_projection +from pylot.core.util.array_map import Array_map from pylot.core.util.structure import DATASTRUCTURE from pylot.core.util.thread import Thread, Worker from pylot.core.util.version import get_git_version as _getVersionString @@ -2850,9 +2850,9 @@ class MainWindow(QMainWindow): if not self.metadata: return self.am_figure = Figure() - self.am_canvas = FigureCanvas(self.am_figure) + self.am_canvas = PylotCanvas(self.am_figure, parent=self, panZoomX=False, panZoomY=False) self.am_toolbar = NavigationToolbar(self.am_canvas, self) - self.array_map = map_projection(self) + self.array_map = Array_map(self) # self.array_map_thread() self.array_layout.addWidget(self.array_map) self.tabs.setCurrentIndex(index) @@ -2891,7 +2891,8 @@ class MainWindow(QMainWindow): lon = event.origins[0].longitude self.array_map.eventLoc = (lat, lon) if self.get_current_event(): - self.array_map.refresh_drawings(self.get_current_event().getPicks()) + self.array_map.refresh_drawings(self.get_current_event().getPicks(), + self.get_current_event().getAutopicks(),) self._eventChanged[1] = False def init_event_table(self, tabindex=2): diff --git a/pylot/core/util/map_projection.py b/pylot/core/util/array_map.py similarity index 56% rename from pylot/core/util/map_projection.py rename to pylot/core/util/array_map.py index 66cfb5ce..39e4f1ad 100644 --- a/pylot/core/util/map_projection.py +++ b/pylot/core/util/array_map.py @@ -13,19 +13,20 @@ from scipy.interpolate import griddata plt.interactive(False) -class map_projection(QtGui.QWidget): +class Array_map(QtGui.QWidget): def __init__(self, parent, figure=None): ''' - - :param: picked, can be False, auto, manual - :value: str + Create a map of the array. + :param parent: PyLoT Mainwindow class + :param figure: ''' QtGui.QWidget.__init__(self) self._parent = parent - self.metadata = parent.metadata - self.parser = parent.metadata[1] + self.metadata_type = parent.metadata[0] + self.metadata = parent.metadata[1] self.picks = None self.picks_dict = None + self.autopicks_dict = None self.eventLoc = None self.figure = figure self.init_graphics() @@ -49,9 +50,9 @@ class map_projection(QtGui.QWidget): return data = self._parent.get_data().getWFData() for index in ind: - station = str(self.station_names[index].split('.')[-1]) + station = str(self._station_onpick_ids[index].split('.')[-1]) try: - pickDlg = PickDlg(self, parameter=self._parent._inputs, + pickDlg = PickDlg(self._parent, parameter=self._parent._inputs, data=data.select(station=station), station=station, picks=self._parent.get_current_event().getPick(station), @@ -84,7 +85,29 @@ class map_projection(QtGui.QWidget): def connectSignals(self): self.comboBox_phase.currentIndexChanged.connect(self._refresh_drawings) - self.zoom_id = self.basemap.ax.figure.canvas.mpl_connect('scroll_event', self.zoom) + self.comboBox_am.currentIndexChanged.connect(self._refresh_drawings) + #self.zoom_id = self.basemap.ax.figure.canvas.mpl_connect('scroll_event', self.zoom) + + def _from_dict(self, function, key): + return function(self.stations_dict.values(), key=lambda x: x[key])[key] + + def get_min_from_stations(self, key): + return self._from_dict(min, key) + + def get_max_from_stations(self, key): + return self._from_dict(max, key) + + def get_min_from_picks(self): + return min(self.picks_rel.values()) + + def get_max_from_picks(self): + return max(self.picks_rel.values()) + + def current_picks_dict(self): + picktype = self.comboBox_am.currentText() + auto_manu = {'auto': self.autopicks_dict, + 'manual': self.picks_dict} + return auto_manu[picktype] def init_graphics(self): if not self.figure: @@ -115,103 +138,97 @@ class map_projection(QtGui.QWidget): 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 + self.top_row.addWidget(QtGui.QLabel('Pick type: ')) + self.top_row.addWidget(self.comboBox_am) + self.top_row.setStretch(3, 1) # set stretch of item 1 to 1 self.main_box.addWidget(self.canvas) self.main_box.addWidget(self.toolbar) + def init_stations(self): - def get_station_names_lat_lon(parser): - station_names = [] - lat = [] - lon = [] + def stat_info_from_parser(parser): + stations_dict = {} for station in parser.stations: station_name = station[0].station_call_letters - network = station[0].network_code - if not station_name in station_names: - station_names.append(network + '.' + station_name) - lat.append(station[0].latitude) - lon.append(station[0].longitude) - return station_names, lat, lon + network_name = station[0].network_code + if not station_name in stations_dict.keys(): + st_id = network_name + '.' + station_name + stations_dict[st_id] = {'latitude': station[0].latitude, + 'longitude': station[0].longitude} + return stations_dict - station_names, lat, lon = get_station_names_lat_lon(self.parser) - self.station_names = station_names - self.lat = lat - self.lon = lon + def stat_info_from_inventory(inventory): + stations_dict = {} + for network in inventory.networks: + for station in network.stations: + station_name = station.code + network_name = network_name.code + if not station_name in stations_dict.keys(): + st_id = network_name + '.' + station_name + stations_dict[st_id] = {'latitude': station[0].latitude, + 'longitude': station[0].longitude} + return stations_dict + + read_stat = {'xml': stat_info_from_inventory, + 'dless': stat_info_from_parser} + + self.stations_dict = read_stat[self.metadata_type](self.metadata) + self.latmin = self.get_min_from_stations('latitude') + self.lonmin = self.get_min_from_stations('longitude') + self.latmax = self.get_max_from_stations('latitude') + self.lonmax = self.get_max_from_stations('longitude') def init_picks(self): - phase = self.comboBox_phase.currentText() - - def get_picks(station_names): - picks = [] - for station in station_names: + def get_picks(station_dict): + picks = {} + phase = self.comboBox_phase.currentText() + for st_id in station_dict.keys(): try: - station = station.split('.')[-1] - picks.append(self.picks_dict[station][phase]['mpp']) - except: - picks.append(np.nan) + station_name = st_id.split('.')[-1] + picks[st_id] = self.current_picks_dict()[station_name][phase]['mpp'] + except KeyError: + continue + except Exception as e: + print('Cannot display pick for station {}. Reason: {}'.format(station_name, e)) return picks def get_picks_rel(picks): - picks_rel = [] + picks_rel = {} picks_utc = [] - for pick in picks: + for pick in picks.values(): if type(pick) is obspy.core.utcdatetime.UTCDateTime: picks_utc.append(pick) minp = min(picks_utc) - for pick in picks: + for st_id, pick in picks.items(): if type(pick) is obspy.core.utcdatetime.UTCDateTime: pick -= minp - picks_rel.append(pick) + picks_rel[st_id] = pick return picks_rel - self.picks = get_picks(self.station_names) + self.picks = get_picks(self.stations_dict) self.picks_rel = get_picks_rel(self.picks) - def init_picks_active(self): - def remove_nan_picks(picks): - picks_no_nan = [] - for pick in picks: - if not np.isnan(pick): - picks_no_nan.append(pick) - return picks_no_nan - - self.picks_no_nan = remove_nan_picks(self.picks_rel) - - def init_stations_active(self): - def remove_nan_lat_lon(picks, lat, lon): - lat_no_nan = [] - lon_no_nan = [] - for index, pick in enumerate(picks): - if not np.isnan(pick): - lat_no_nan.append(lat[index]) - lon_no_nan.append(lon[index]) - return lat_no_nan, lon_no_nan - - self.lat_no_nan, self.lon_no_nan = remove_nan_lat_lon(self.picks_rel, self.lat, self.lon) - def init_lat_lon_dimensions(self): - def get_lon_lat_dim(lon, lat): - londim = max(lon) - min(lon) - latdim = max(lat) - min(lat) - return londim, latdim - - self.londim, self.latdim = get_lon_lat_dim(self.lon, self.lat) + # init minimum and maximum lon and lat dimensions + self.londim = self.lonmax - self.lonmin + self.latdim = self.latmax - self.latmin def init_x_y_dimensions(self): - def get_x_y_dim(x, y): - xdim = max(x) - min(x) - ydim = max(y) - min(y) - return xdim, ydim + # transformation of lat/lon to ax coordinate system + for st_id, coords in self.stations_dict.items(): + lat, lon = coords['latitude'], coords['longitude'] + coords['x'], coords['y'] = self.basemap(lon, lat) - self.x, self.y = self.basemap(self.lon, self.lat) - self.xdim, self.ydim = get_x_y_dim(self.x, self.y) + self.xdim = self.get_max_from_stations('x') - self.get_min_from_stations('x') + self.ydim = self.get_max_from_stations('y') - self.get_min_from_stations('y') def init_basemap(self, resolution='l'): # basemap = Basemap(projection=projection, resolution = resolution, ax=self.main_ax) basemap = Basemap(projection='lcc', resolution=resolution, ax=self.main_ax, width=5e6, height=2e6, - lat_0=(min(self.lat) + max(self.lat)) / 2., - lon_0=(min(self.lon) + max(self.lon)) / 2.) + lat_0=(self.latmin + self.latmax) / 2., + lon_0=(self.lonmin + self.lonmax) / 2.) # basemap.fillcontinents(color=None, lake_color='aqua',zorder=1) basemap.drawmapboundary(zorder=2) # fill_color='darkblue') @@ -222,60 +239,81 @@ class map_projection(QtGui.QWidget): self.basemap = basemap self.figure.tight_layout() - def init_lat_lon_grid(self): - def get_lat_lon_axis(lat, lon): - steplat = (max(lat) - min(lat)) / 250 - steplon = (max(lon) - min(lon)) / 250 - - lataxis = np.arange(min(lat), max(lat), steplat) - lonaxis = np.arange(min(lon), max(lon), steplon) - return lataxis, lonaxis - - def get_lat_lon_grid(lataxis, lonaxis): - longrid, latgrid = np.meshgrid(lonaxis, lataxis) - return latgrid, longrid - - self.lataxis, self.lonaxis = get_lat_lon_axis(self.lat, self.lon) - self.latgrid, self.longrid = get_lat_lon_grid(self.lataxis, self.lonaxis) + def init_lat_lon_grid(self, nstep=250): + # create a regular grid to display colormap + lataxis = np.linspace(self.latmin, self.latmax, nstep) + lonaxis = np.linspace(self.lonmin, self.lonmax, nstep) + self.longrid, self.latgrid = np.meshgrid(lonaxis, lataxis) def init_picksgrid(self): - self.picksgrid_no_nan = griddata((self.lat_no_nan, self.lon_no_nan), - self.picks_no_nan, (self.latgrid, self.longrid), - method='linear') ################## + picks, lats, lons = self.get_picks_lat_lon() + self.picksgrid_active = griddata((lats, lons), picks, (self.latgrid, self.longrid), + method='linear') + + def get_st_lat_lon_for_plot(self): + stations = [] + latitudes = [] + longitudes = [] + for st_id, coords in self.stations_dict.items(): + stations.append(st_id) + latitudes.append(coords['latitude']) + longitudes.append(coords['longitude']) + return stations, latitudes, longitudes + + def get_st_x_y_for_plot(self): + stations = [] + xs = [] + ys = [] + for st_id, coords in self.stations_dict.items(): + stations.append(st_id) + xs.append(coords['x']) + ys.append(coords['y']) + return stations, xs, ys + + def get_picks_lat_lon(self): + picks = [] + latitudes = [] + longitudes = [] + for st_id, pick in self.picks_rel.items(): + picks.append(pick) + latitudes.append(self.stations_dict[st_id]['latitude']) + longitudes.append(self.stations_dict[st_id]['longitude']) + return picks, latitudes, longitudes def draw_contour_filled(self, nlevel='50'): - levels = np.linspace(min(self.picks_no_nan), max(self.picks_no_nan), nlevel) - self.contourf = self.basemap.contourf(self.longrid, self.latgrid, self.picksgrid_no_nan, + levels = np.linspace(self.get_min_from_picks(), self.get_max_from_picks(), nlevel) + self.contourf = self.basemap.contourf(self.longrid, self.latgrid, self.picksgrid_active, levels, latlon=True, zorder=9, alpha=0.5) def scatter_all_stations(self): - self.sc = self.basemap.scatter(self.lon, self.lat, s=50, facecolor='none', latlon=True, + stations, lats, lons = self.get_st_lat_lon_for_plot() + self.sc = self.basemap.scatter(lons, lats, s=50, facecolor='none', latlon=True, zorder=10, picker=True, edgecolor='m', label='Not Picked') self.cid = self.canvas.mpl_connect('pick_event', self.onpick) + self._station_onpick_ids = stations if self.eventLoc: - lat, lon = self.eventLoc - self.sc_event = self.basemap.scatter(lon, lat, s=100, facecolor='red', + lats, lons = self.eventLoc + self.sc_event = self.basemap.scatter(lons, lats, s=100, facecolor='red', latlon=True, zorder=11, label='Event (might be outside map region)') def scatter_picked_stations(self): - lon = self.lon_no_nan - lat = self.lat_no_nan - + picks, lats, lons = self.get_picks_lat_lon() # 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) + if len(lons) <= 2 and len(lats) <= 2: + self.sc_picked = self.basemap.scatter(lons[0], lats[0], s=50, facecolor='white', + c=picks[0], latlon=True, zorder=11, label='Picked') + if len(lons) == 2 and len(lats) == 2: + self.sc_picked = self.basemap.scatter(lons[1], lats[1], s=50, facecolor='white', + c=picks[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') + self.sc_picked = self.basemap.scatter(lons, lats, s=50, facecolor='white', + c=picks, latlon=True, zorder=11, label='Picked') def annotate_ax(self): self.annotations = [] - for index, name in enumerate(self.station_names): - self.annotations.append(self.main_ax.annotate(' %s' % name, xy=(self.x[index], self.y[index]), + stations, xs, ys = self.get_st_x_y_for_plot() + for st, x, y in zip(stations, xs, ys): + self.annotations.append(self.main_ax.annotate(' %s' % st, xy=(x, y), fontsize='x-small', color='white', zorder=12)) self.legend = self.main_ax.legend(loc=1) @@ -284,8 +322,9 @@ class map_projection(QtGui.QWidget): cbar.set_label(label) return cbar - def refresh_drawings(self, picks=None): + def refresh_drawings(self, picks=None, autopicks=None): self.picks_dict = picks + self.autopicks_dict = autopicks self._refresh_drawings() def _refresh_drawings(self): @@ -295,9 +334,7 @@ class map_projection(QtGui.QWidget): def draw_everything(self): if self.picks_dict: self.init_picks() - self.init_picks_active() - self.init_stations_active() - if len(self.picks_no_nan) >= 3: + if len(self.picks) >= 3: self.init_picksgrid() self.draw_contour_filled() self.scatter_all_stations() @@ -311,15 +348,15 @@ class map_projection(QtGui.QWidget): self.canvas.draw() def remove_drawings(self): + if hasattr(self, 'cbar'): + self.cbar.remove() + del (self.cbar) if hasattr(self, 'sc_picked'): self.sc_picked.remove() del (self.sc_picked) if hasattr(self, 'sc_event'): self.sc_event.remove() del (self.sc_event) - if hasattr(self, 'cbar'): - self.cbar.remove() - del (self.cbar) if hasattr(self, 'contourf'): self.remove_contourf() del (self.contourf) From fe0e4be43d63ac066127cc795be5bc6e5275a41c Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 14 Jun 2018 14:08:25 +0200 Subject: [PATCH 27/70] [update] array_map uses PylotCanvas now, added grid and labels --- PyLoT.py | 3 --- pylot/core/util/array_map.py | 22 ++++++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index 96c30e4a..456f7671 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -2849,9 +2849,6 @@ class MainWindow(QMainWindow): self.init_metadata() if not self.metadata: return - self.am_figure = Figure() - self.am_canvas = PylotCanvas(self.am_figure, parent=self, panZoomX=False, panZoomY=False) - self.am_toolbar = NavigationToolbar(self.am_canvas, self) self.array_map = Array_map(self) # self.array_map_thread() self.array_layout.addWidget(self.array_map) diff --git a/pylot/core/util/array_map.py b/pylot/core/util/array_map.py index 39e4f1ad..c2464066 100644 --- a/pylot/core/util/array_map.py +++ b/pylot/core/util/array_map.py @@ -5,9 +5,9 @@ import matplotlib.pyplot as plt import numpy as np import obspy from PySide import QtGui -from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar from mpl_toolkits.basemap import Basemap -from pylot.core.util.widgets import PickDlg +from matplotlib.figure import Figure +from pylot.core.util.widgets import PickDlg, PylotCanvas from scipy.interpolate import griddata plt.interactive(False) @@ -42,6 +42,7 @@ class Array_map(QtGui.QWidget): self.init_x_y_dimensions() self.connectSignals() self.draw_everything() + self.canvas.setZoomBorders2content() def onpick(self, event): ind = event.ind @@ -111,15 +112,12 @@ class Array_map(QtGui.QWidget): 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.figure = Figure() self.main_ax = self.figure.add_subplot(111) - self.canvas = self.figure.canvas + self.canvas = PylotCanvas(self.figure, parent=self._parent, multicursor=True, + panZoomX=False, panZoomY=False) + #self.canvas.setZoomBorders2content() self.main_box = QtGui.QVBoxLayout() self.setLayout(self.main_box) @@ -143,7 +141,6 @@ class Array_map(QtGui.QWidget): self.top_row.setStretch(3, 1) # set stretch of item 1 to 1 self.main_box.addWidget(self.canvas) - self.main_box.addWidget(self.toolbar) def init_stations(self): @@ -236,6 +233,11 @@ class Array_map(QtGui.QWidget): basemap.drawcountries(zorder=4) basemap.drawstates(zorder=5) basemap.drawcoastlines(zorder=6) + # labels = [left,right,top,bottom] + parallels = np.arange(-90, 90, 5.) + basemap.drawparallels(parallels, labels=[True, True, False, False], zorder=7) + meridians = np.arange(-180, 180, 5.) + basemap.drawmeridians(meridians, labels=[False, False, True, True], zorder=7) self.basemap = basemap self.figure.tight_layout() From 46a6cdcc00b40fc2c500d477d95c6c907d320464 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 14 Jun 2018 15:50:44 +0200 Subject: [PATCH 28/70] [bugfix] remove autopicks weight>3 --- pylot/core/util/array_map.py | 31 ++++++++++++++++++++++--------- pylot/core/util/widgets.py | 2 +- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/pylot/core/util/array_map.py b/pylot/core/util/array_map.py index c2464066..e6d6646f 100644 --- a/pylot/core/util/array_map.py +++ b/pylot/core/util/array_map.py @@ -53,11 +53,16 @@ class Array_map(QtGui.QWidget): for index in ind: station = str(self._station_onpick_ids[index].split('.')[-1]) try: + data = data.select(station=station) + if not data: + self._warn('No data for station {}'.format(station)) + return pickDlg = PickDlg(self._parent, parameter=self._parent._inputs, - data=data.select(station=station), + data=data, station=station, picks=self._parent.get_current_event().getPick(station), - autopicks=self._parent.get_current_event().getAutopick(station)) + autopicks=self._parent.get_current_event().getAutopick(station), + filteroptions=self._parent.filteroptions) except Exception as e: message = 'Could not generate Plot for station {st}.\n {er}'.format(st=station, er=e) self._warn(message) @@ -183,7 +188,11 @@ class Array_map(QtGui.QWidget): for st_id in station_dict.keys(): try: station_name = st_id.split('.')[-1] - picks[st_id] = self.current_picks_dict()[station_name][phase]['mpp'] + pick = self.current_picks_dict()[station_name][phase] + if pick['picker'] == 'auto': + if pick['weight'] > 3: + continue + picks[st_id] = pick['mpp'] except KeyError: continue except Exception as e: @@ -196,10 +205,10 @@ class Array_map(QtGui.QWidget): for pick in picks.values(): if type(pick) is obspy.core.utcdatetime.UTCDateTime: picks_utc.append(pick) - minp = min(picks_utc) + self._earliest_picktime = min(picks_utc) for st_id, pick in picks.items(): if type(pick) is obspy.core.utcdatetime.UTCDateTime: - pick -= minp + pick -= self._earliest_picktime picks_rel[st_id] = pick return picks_rel @@ -239,7 +248,8 @@ class Array_map(QtGui.QWidget): meridians = np.arange(-180, 180, 5.) basemap.drawmeridians(meridians, labels=[False, False, True, True], zorder=7) self.basemap = basemap - self.figure.tight_layout() + self.figure._tight = True + self.figure.tight_layout(1.15) def init_lat_lon_grid(self, nstep=250): # create a regular grid to display colormap @@ -249,8 +259,11 @@ class Array_map(QtGui.QWidget): def init_picksgrid(self): picks, lats, lons = self.get_picks_lat_lon() - self.picksgrid_active = griddata((lats, lons), picks, (self.latgrid, self.longrid), - method='linear') + try: + self.picksgrid_active = griddata((lats, lons), picks, (self.latgrid, self.longrid), + method='linear') + except Exception as e: + self._warn('Could not init picksgrid: {}'.format(e)) def get_st_lat_lon_for_plot(self): stations = [] @@ -342,7 +355,7 @@ class Array_map(QtGui.QWidget): self.scatter_all_stations() if self.picks_dict: self.scatter_picked_stations() - self.cbar = self.add_cbar(label='Time relative to first onset [s]') + self.cbar = self.add_cbar(label='Time relative to first onset ({}) [s]'.format(self._earliest_picktime)) self.comboBox_phase.setEnabled(True) else: self.comboBox_phase.setEnabled(False) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 0df1b784..28480ef7 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -1368,7 +1368,7 @@ class PickDlg(QDialog): self.cur_ylim = None # set attribute holding data - if data is None: + if data is None or not data: try: data = parent.get_data().getWFData().copy() self.data = data.select(station=station) From 0168d8923d2e1dd02cefa07a777731c2758d4333 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 14 Jun 2018 16:17:06 +0200 Subject: [PATCH 29/70] [minor] tighten PyLoT tabs layouts --- PyLoT.py | 5 +++++ pylot/styles/bright.qss | 6 +++--- pylot/styles/dark.qss | 6 +++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index 456f7671..afa17c7d 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -637,6 +637,11 @@ class MainWindow(QMainWindow): array_tab.setLayout(self.array_layout) events_tab.setLayout(self.events_layout) + # tighten up layouts inside tabs + for layout in [self.wf_layout, self.array_layout, self.events_layout]: + layout.setSpacing(0) + layout.setContentsMargins(0, 0, 0, 0) + # add tabs to main tab widget self.tabs.addTab(wf_tab, 'Waveform Plot') self.tabs.addTab(array_tab, 'Array Map') diff --git a/pylot/styles/bright.qss b/pylot/styles/bright.qss index 71e5c5a3..5f3de6a7 100644 --- a/pylot/styles/bright.qss +++ b/pylot/styles/bright.qss @@ -179,9 +179,9 @@ background-color:transparent; QTabWidget::pane{ background-color:rgba(0, 0, 0, 255); -border-style:solid; -border-color:rgba(245, 245, 245, 255); -border-width:1px; +margin: 0px, 0px, 0px, 0px; +padding: 0px; +border-width:0px; } QTabWidget::tab{ diff --git a/pylot/styles/dark.qss b/pylot/styles/dark.qss index fc866e20..0ca4cd46 100644 --- a/pylot/styles/dark.qss +++ b/pylot/styles/dark.qss @@ -178,9 +178,9 @@ background-color:transparent; QTabWidget::pane{ background-color:rgba(70, 70, 80, 255); -border-style:solid; -border-color:rgba(70, 70, 80, 255); -border-width:1px; +margin: 0px, 0px, 0px, 0px; +padding: 0px; +border-width:0px; } QTabWidget::tab{ From 7c0de4497466dd0221189dad81535b7517d94df3 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 15 Jun 2018 14:49:26 +0200 Subject: [PATCH 30/70] [update] array_map legend inaxes, add lat/lon status, some fixes and improvements --- pylot/core/util/array_map.py | 47 +++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/pylot/core/util/array_map.py b/pylot/core/util/array_map.py index e6d6646f..91dee54e 100644 --- a/pylot/core/util/array_map.py +++ b/pylot/core/util/array_map.py @@ -7,6 +7,7 @@ import obspy from PySide import QtGui from mpl_toolkits.basemap import Basemap from matplotlib.figure import Figure +from mpl_toolkits.axes_grid1.inset_locator import inset_axes from pylot.core.util.widgets import PickDlg, PylotCanvas from scipy.interpolate import griddata @@ -92,6 +93,7 @@ class Array_map(QtGui.QWidget): def connectSignals(self): self.comboBox_phase.currentIndexChanged.connect(self._refresh_drawings) self.comboBox_am.currentIndexChanged.connect(self._refresh_drawings) + self.canvas.mpl_connect('motion_notify_event', self.mouse_moved) #self.zoom_id = self.basemap.ax.figure.canvas.mpl_connect('scroll_event', self.zoom) def _from_dict(self, function, key): @@ -109,6 +111,14 @@ class Array_map(QtGui.QWidget): def get_max_from_picks(self): return max(self.picks_rel.values()) + def mouse_moved(self, event): + if not event.inaxes == self.main_ax: + return + x = event.xdata + y = event.ydata + lat, lon = self.basemap(x, y, inverse=True) + self.status_label.setText('Latitude: {}, Longitude: {}'.format(lat, lon)) + def current_picks_dict(self): picktype = self.comboBox_am.currentText() auto_manu = {'auto': self.autopicks_dict, @@ -119,16 +129,17 @@ class Array_map(QtGui.QWidget): if not self.figure: self.figure = Figure() + self.status_label = QtGui.QLabel() + self.main_ax = self.figure.add_subplot(111) self.canvas = PylotCanvas(self.figure, parent=self._parent, multicursor=True, panZoomX=False, panZoomY=False) - #self.canvas.setZoomBorders2content() self.main_box = QtGui.QVBoxLayout() self.setLayout(self.main_box) self.top_row = QtGui.QHBoxLayout() - self.main_box.addLayout(self.top_row) + self.main_box.addLayout(self.top_row, 1) self.comboBox_phase = QtGui.QComboBox() self.comboBox_phase.insertItem(0, 'P') @@ -145,7 +156,8 @@ class Array_map(QtGui.QWidget): self.top_row.addWidget(self.comboBox_am) self.top_row.setStretch(3, 1) # set stretch of item 1 to 1 - self.main_box.addWidget(self.canvas) + self.main_box.addWidget(self.canvas, 1) + self.main_box.addWidget(self.status_label, 0) def init_stations(self): @@ -231,8 +243,10 @@ class Array_map(QtGui.QWidget): def init_basemap(self, resolution='l'): # basemap = Basemap(projection=projection, resolution = resolution, ax=self.main_ax) + width = 5e6 + height = 2e6 basemap = Basemap(projection='lcc', resolution=resolution, ax=self.main_ax, - width=5e6, height=2e6, + width=width, height=height, lat_0=(self.latmin + self.latmax) / 2., lon_0=(self.lonmin + self.lonmax) / 2.) @@ -244,12 +258,16 @@ class Array_map(QtGui.QWidget): basemap.drawcoastlines(zorder=6) # labels = [left,right,top,bottom] parallels = np.arange(-90, 90, 5.) - basemap.drawparallels(parallels, labels=[True, True, False, False], zorder=7) + parallels_small = np.arange(-90, 90, 2.5) + basemap.drawparallels(parallels_small, linewidth=0.5, zorder=7) + basemap.drawparallels(parallels, zorder=7) meridians = np.arange(-180, 180, 5.) - basemap.drawmeridians(meridians, labels=[False, False, True, True], zorder=7) + meridians_small = np.arange(-180, 180, 2.5) + basemap.drawmeridians(meridians_small, linewidth=0.5, zorder=7) + basemap.drawmeridians(meridians, zorder=7) self.basemap = basemap self.figure._tight = True - self.figure.tight_layout(1.15) + self.figure.tight_layout() def init_lat_lon_grid(self, nstep=250): # create a regular grid to display colormap @@ -331,10 +349,20 @@ class Array_map(QtGui.QWidget): self.annotations.append(self.main_ax.annotate(' %s' % st, xy=(x, y), fontsize='x-small', color='white', zorder=12)) self.legend = self.main_ax.legend(loc=1) + self.legend.get_frame().set_facecolor((1, 1, 1, 0.75)) def add_cbar(self, label): - cbar = self.main_ax.figure.colorbar(self.sc_picked, fraction=0.025) + self.cbax_bg = inset_axes(self.main_ax, width="6%", height="75%", loc=5) + cbax = inset_axes(self.main_ax, width='2%', height='70%', loc=5) + cbar = self.main_ax.figure.colorbar(self.sc_picked, cax = cbax) cbar.set_label(label) + cbax.yaxis.tick_left() + cbax.yaxis.set_label_position('left') + for spine in self.cbax_bg.spines.values(): + spine.set_visible(False) + self.cbax_bg.yaxis.set_ticks([]) + self.cbax_bg.xaxis.set_ticks([]) + self.cbax_bg.patch.set_facecolor((1, 1, 1, 0.75)) return cbar def refresh_drawings(self, picks=None, autopicks=None): @@ -365,7 +393,8 @@ class Array_map(QtGui.QWidget): def remove_drawings(self): if hasattr(self, 'cbar'): self.cbar.remove() - del (self.cbar) + self.cbax_bg.remove() + del (self.cbar, self.cbax_bg) if hasattr(self, 'sc_picked'): self.sc_picked.remove() del (self.sc_picked) From ec32981787df4af32dead5803912695c116467d7 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 19 Jun 2018 10:26:17 +0200 Subject: [PATCH 31/70] [minor] improve current event highlighting --- PyLoT.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PyLoT.py b/PyLoT.py index afa17c7d..71386963 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -3066,7 +3066,7 @@ class MainWindow(QMainWindow): set_foreground_color(column, QtGui.QColor(*(180, 180, 180, 255))) if event == current_event: - set_foreground_color(column, QtGui.QColor(*(0, 143, 143, 255))) + set_background_color(column, QtGui.QColor(*(0, 143, 143, 255))) # manipulate items item_ref.setBackground(self._ref_test_colors['ref']) From ca886d4355acad3e4bc6e0af70f617f3ffe90fc7 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 19 Jun 2018 10:35:34 +0200 Subject: [PATCH 32/70] [update] on obspyDMT compatibility (WIP) --- PyLoT.py | 11 ++++++----- pylot/core/util/widgets.py | 33 ++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index 71386963..44d27fed 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -139,6 +139,7 @@ class MainWindow(QMainWindow): self.apd_local = None self.apd_sge = None self.stations_highlighted = [] + self.obspy_dmt = False self.poS_id = None self.ae_id = None @@ -1006,7 +1007,6 @@ class MainWindow(QMainWindow): # TODO: add dataStructure class for obspyDMT here, this is just a workaround! eventpath = self.get_current_event_path(eventbox) basepath = eventpath.split(os.path.basename(eventpath))[0] - obspy_dmt = check_obspydmt_structure(basepath) if self.dataStructure: if not eventpath: return @@ -1700,9 +1700,9 @@ class MainWindow(QMainWindow): self.fnames_syn = [] eventpath = self.get_current_event_path() basepath = eventpath.split(os.path.basename(eventpath))[0] - obspy_dmt = check_obspydmt_structure(basepath) - self.dataPlot.activateObspyDMToptions(obspy_dmt) - if obspy_dmt: + self.obspy_dmt = check_obspydmt_structure(basepath) + self.dataPlot.activateObspyDMToptions(self.obspy_dmt) + if self.obspy_dmt: self.prepareObspyDMT_data(eventpath) def loadWaveformData(self): @@ -2392,7 +2392,8 @@ class MainWindow(QMainWindow): self.init_fig_dict() #if not self.tap: # init TuneAutopicker object - self.tap = TuneAutopicker(self) + wftype = self.dataPlot.qcombo_processed.currentText() if self.obspy_dmt else None + self.tap = TuneAutopicker(self, wftype) # first call of update to init tabs with empty canvas self.update_autopicker() # connect update signal of TuneAutopicker with update function diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 28480ef7..4320232e 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -3008,13 +3008,13 @@ class TuneAutopicker(QWidget): :type: PyLoT Mainwindow ''' - def __init__(self, parent): + def __init__(self, parent, wftype=None): QtGui.QWidget.__init__(self, parent, 1) self._style = parent._style self.setWindowTitle('PyLoT - Tune Autopicker') self.parameter = self.parent()._inputs self.fig_dict = self.parent().fig_dict - self.data = Data() + self.wftype = wftype self.pdlg_widget = None self.pylot_picks = None self.init_main_layouts() @@ -3072,18 +3072,19 @@ class TuneAutopicker(QWidget): self.stationBox.activated.connect(self.fill_tabs) def fill_stationbox(self): - fnames = self.parent().getWFFnames_from_eventbox(eventbox=self.eventBox) - self.data.setWFData(fnames) + #fnames = self.parent().fnames #getWFFnames_from_eventbox(eventbox=self.eventBox) + #self.data.setWFData(fnames) + self.data = self.parent().data wfdat = self.data.getWFData() # all available streams # remove possible underscores in station names - wfdat = remove_underscores(wfdat) - # rotate misaligned stations to ZNE - # check for gaps and doubled channels - check4gaps(wfdat) - check4doubled(wfdat) - wfdat = check4rotated(wfdat, self.parent().metadata, verbosity=0) - # trim station components to same start value - trim_station_components(wfdat, trim_start=True, trim_end=False) + # wfdat = remove_underscores(wfdat) + # # rotate misaligned stations to ZNE + # # check for gaps and doubled channels + # check4gaps(wfdat) + # check4doubled(wfdat) + # wfdat = check4rotated(wfdat, self.parent().metadata, verbosity=0) + # # trim station components to same start value + # trim_station_components(wfdat, trim_start=True, trim_end=False) self.stationBox.clear() stations = [] for trace in self.data.getWFData(): @@ -3145,7 +3146,9 @@ class TuneAutopicker(QWidget): return self.eventBox.currentText().split('/')[-1] def get_current_event_fp(self): - return self.eventBox.currentText() + wfext = self.wftype if self.wftype else '' + fp = os.path.join(self.eventBox.currentText(), wfext) + return fp def get_current_event_picks(self, station): event = self.get_current_event() @@ -3175,11 +3178,11 @@ class TuneAutopicker(QWidget): self.pdlg_widget = None return station = self.get_current_station() - data = self.data.getWFData() + wfdata = self.data.getWFData() metadata = self.parent().metadata event = self.get_current_event() filteroptions = self.parent().filteroptions - self.pickDlg = PickDlg(self.parent(), data=data.select(station=station), + self.pickDlg = PickDlg(self.parent(), data=wfdata.select(station=station).copy(), station=station, parameter=self.parameter, picks=self.get_current_event_picks(station), autopicks=self.get_current_event_autopicks(station), From 7de8c2ee8b6db3a8bc8a2916a3f3491fe6251b04 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 19 Jun 2018 11:03:43 +0200 Subject: [PATCH 33/70] [minor] info on number of traces for main plot --- PyLoT.py | 6 ++++-- pylot/core/util/widgets.py | 25 ++++++++++++++++--------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index 44d27fed..ce5120cd 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -3332,9 +3332,11 @@ class MainWindow(QMainWindow): self.fill_eventbox() self.getPlotWidget().draw() if self.plot_method == 'fast': - self.dataPlot.setPermTextMid('MIN/MAX plot', color='red') + self.dataPlot.setPermText(1, ' MIN/MAX plot ', color='red') else: - self.dataPlot.setPermTextMid() + self.dataPlot.setPermText(1) + self.dataPlot.setPermText(0, '| Number of traces: {} |'.format(len(self.getPlotWidget().getPlotDict()))) + def _setDirty(self): self.setDirty(True) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 4320232e..fd3b1f26 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -497,19 +497,24 @@ class WaveformWidgetPG(QtGui.QWidget): def init_labels(self): self.label_layout.addWidget(self.status_label) - self.label_layout.addWidget(self.perm_label_mid) + for label in self.perm_labels: + self.label_layout.addWidget(label) self.label_layout.addWidget(self.syn_checkbox) self.label_layout.addWidget(self.qcombo_processed) self.syn_checkbox.setLayoutDirection(Qt.RightToLeft) self.label_layout.setStretch(0, 4) - self.label_layout.setStretch(1, 2) - self.label_layout.setStretch(2, 3) - self.label_layout.setStretch(3, 1) + self.label_layout.setStretch(1, 0) + self.label_layout.setStretch(2, 0) + self.label_layout.setStretch(3, 0) + self.label_layout.setStretch(4, 3) + self.label_layout.setStretch(5, 1) def add_labels(self): self.status_label = QtGui.QLabel() - self.perm_label_mid = QtGui.QLabel() - self.perm_label_mid.setAlignment(4) + self.perm_labels = [] + for index in range(3): + label = QtGui.QLabel() + self.perm_labels.append(label) self.qcombo_processed = QtGui.QComboBox() self.syn_checkbox = QtGui.QCheckBox('synthetics') self.addQCboxItem('raw', 'black') @@ -524,9 +529,11 @@ class WaveformWidgetPG(QtGui.QWidget): self.syn_checkbox.setVisible(activate) self.qcombo_processed.setVisible(activate) - def setPermTextMid(self, text=None, color='black'): - self.perm_label_mid.setText(text) - self.perm_label_mid.setStyleSheet('color: {}'.format(color)) + def setPermText(self, number, text=None, color='black'): + if not 0 <= number < len(self.perm_labels): + raise ValueError('No label for number {}'.format(number)) + self.perm_labels[number].setText(text) + self.perm_labels[number].setStyleSheet('color: {}'.format(color)) def addQCboxItem(self, text=None, color='black'): item = QtGui.QStandardItem(text) From 47d6aeabff94270ed89c340d089a0031da3f5099 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 19 Jun 2018 11:28:41 +0200 Subject: [PATCH 34/70] [minor] used event highlighting of eventlist also for eventbox --- PyLoT.py | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index ce5120cd..9dac4716 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -1229,6 +1229,8 @@ class MainWindow(QMainWindow): tv.verticalHeader().hide() tv.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + current_event = self.get_current_event() + eventBox.setView(tv) eventBox.clear() model = eventBox.model() @@ -1316,6 +1318,10 @@ class MainWindow(QMainWindow): if event_test and select_events == 'ref' or self.isEmpty(event_path): for item in itemlist: item.setEnabled(False) + + #item color + self.setItemColor(itemlist, id, event, current_event) + model.appendRow(itemlist) if not event.path == self.eventBox.itemText(id).strip(): message = ('Path missmatch creating eventbox.\n' @@ -2949,14 +2955,6 @@ class MainWindow(QMainWindow): event.addNotes(notes) self.fill_eventbox() - def set_background_color(items, color): - for item in items: - item.setBackground(color) - - def set_foreground_color(items, color): - for item in items: - item.setForeground(color) - current_event = self.get_current_event() # generate delete icon @@ -3060,14 +3058,7 @@ class MainWindow(QMainWindow): item_nmp, item_nap, item_ref, item_test, item_notes] self.project._table.append(column) - if index%2: - set_background_color(column, QtGui.QColor(*(245, 245, 245, 255))) - - if self.isEmpty(event.path): - set_foreground_color(column, QtGui.QColor(*(180, 180, 180, 255))) - - if event == current_event: - set_background_color(column, QtGui.QColor(*(0, 143, 143, 255))) + self.setItemColor(column, index, event, current_event) # manipulate items item_ref.setBackground(self._ref_test_colors['ref']) @@ -3089,6 +3080,24 @@ class MainWindow(QMainWindow): self.events_layout.addWidget(self.event_table) self.tabs.setCurrentIndex(tabindex) + def setItemColor(self, item_list, index, event, current_event): + def set_background_color(items, color): + for item in items: + item.setBackground(color) + + def set_foreground_color(items, color): + for item in items: + item.setForeground(color) + + if index % 2: + set_background_color(item_list, QtGui.QColor(*(245, 245, 245, 255))) + + if self.isEmpty(event.path): + set_foreground_color(item_list, QtGui.QColor(*(180, 180, 180, 255))) + + if event == current_event: + set_background_color(item_list, QtGui.QColor(*(0, 143, 143, 255))) + def read_metadata_thread(self, fninv): self.rm_thread = Thread(self, read_metadata, arg=fninv, progressText='Reading metadata...', pb_widget=self.mainProgressBarWidget) From 08124174b1a8fab1d0aa362050d91d931a834e1f Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 20 Jun 2018 11:47:10 +0200 Subject: [PATCH 35/70] [update] autopicker - obspyDMT (WIP) --- autoPyLoT.py | 42 ++++++++++++++++++++++++++----------- pylot/core/pick/autopick.py | 2 ++ pylot/core/pick/charfuns.py | 2 +- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/autoPyLoT.py b/autoPyLoT.py index eb355609..79486fc5 100755 --- a/autoPyLoT.py +++ b/autoPyLoT.py @@ -34,7 +34,7 @@ __version__ = _getVersionString() def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, eventid=None, savepath=None, - savexml=True, station='all', iplot=0, ncores=0): + savexml=True, station='all', iplot=0, ncores=0, obspyDMT_wfpath=False): """ Determine phase onsets automatically utilizing the automatic picking algorithms by Kueperkoch et al. 2010/2012. @@ -114,6 +114,8 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even locflag = input_dict['locflag'] if 'savexml' in input_dict: savexml = input_dict['savexml'] + if 'obspyDMT_wfpath' in input_dict: + obspyDMT_wfpath = input_dict['obspyDMT_wfpath'] if not parameter: if inputfile: @@ -175,6 +177,14 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even print("!!No source parameter estimation possible!!") print(" !!! ") + wfpath_extension = '' + if obspyDMT_wfpath not in [None, False]: + wfpath_extension = obspyDMT_wfpath + print('Using obspyDMT structure. There will be no restitution, as pre-processed data are expected.') + if wfpath_extension != 'processed': + print('WARNING: Expecting wfpath_extension to be "processed" for' + ' pre-processed data but received "{}" instead!!!'.format(wfpath_extension)) + if not input_dict: # started in production mode datapath = datastructure.expandDataPath() @@ -184,16 +194,16 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even events = [events for events in glob.glob(os.path.join(datapath, '*')) if os.path.isdir(events)] elif fnames == 'None' and parameter['eventID'] is not '*' and not type(parameter['eventID']) == list: # single event processing - events = glob.glob(os.path.join(datapath, parameter['eventID'])) + events = glob.glob(os.path.join(datapath, parameter['eventID'], wfpath_extension)) elif fnames == 'None' and type(parameter['eventID']) == list: # multiple event processing events = [] for eventID in parameter['eventID']: - events.append(os.path.join(datapath, eventID)) + events.append(os.path.join(datapath, eventID, wfpath_extension)) else: # autoPyLoT was initialized from GUI events = [] - events.append(eventid) + events.append(os.path.join(eventid, wfpath_extension)) evID = os.path.split(eventid)[-1] locflag = 2 else: @@ -204,7 +214,8 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even for eventID in eventid: events.append(os.path.join(datapath, parameter['database'], - eventID)) + eventID, + wfpath_extension)) if not events: print('autoPyLoT: No events given. Return!') @@ -218,7 +229,10 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even allpicks = {} glocflag = locflag for eventpath in events: - evID = os.path.split(eventpath)[-1] + if not wfpath_extension: + evID = os.path.split(eventpath)[-1] + else: + evID = os.path.split(os.path.split(eventpath)[0])[-1] fext = '.xml' filename = os.path.join(eventpath, 'PyLoT_' + evID + fext) try: @@ -267,13 +281,17 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even wfdat = check4gaps(wfdat) wfdat = check4doubled(wfdat) wfdat = trim_station_components(wfdat, trim_start=True, trim_end=False) - metadata = read_metadata(parameter.get('invdir')) - # rotate stations to ZNE - wfdat = check4rotated(wfdat, metadata) + if not wfpath_extension: + metadata = read_metadata(parameter.get('invdir')) + else: + metadata = None corr_dat = None - if locflag: - print("Restitute data ...") - corr_dat = restitute_data(wfdat.copy(), *metadata, ncores=ncores) + if metadata: + # rotate stations to ZNE + wfdat = check4rotated(wfdat, metadata) + if locflag: + print("Restitute data ...") + corr_dat = restitute_data(wfdat.copy(), *metadata, ncores=ncores) if not corr_dat and locflag: locflag = 2 print('Working on event %s. Stations: %s' % (eventpath, station)) diff --git a/pylot/core/pick/autopick.py b/pylot/core/pick/autopick.py index c1a5704c..00810447 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -283,6 +283,8 @@ def autopickstation(wfstream, pickparam, verbose=False, if use_taup is True: Lc = np.inf print('autopickstation: use_taup flag active.') + if not metadata: + metadata = [None, None] if not metadata[1]: print('Warning: Could not use TauPy to estimate onsets as there are no metadata given.') else: diff --git a/pylot/core/pick/charfuns.py b/pylot/core/pick/charfuns.py index a62870eb..f3aa8a64 100644 --- a/pylot/core/pick/charfuns.py +++ b/pylot/core/pick/charfuns.py @@ -78,7 +78,7 @@ class CharacteristicFunction(object): return self.cut def setCut(self, cut): - self.cut = cut + self.cut = (int(cut[0]), int(cut[1])) def getTime1(self): return self.t1 From 910ed6667658f4bf34d9beddbbbc7dec7426ae66 Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 20 Jun 2018 13:49:27 +0200 Subject: [PATCH 36/70] [new] only load relevant waveforms into TAP widget --- PyLoT.py | 6 +-- pylot/core/util/widgets.py | 104 +++++++++++++++++++++++++------------ 2 files changed, 73 insertions(+), 37 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index 9dac4716..3cee4ef9 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -2294,13 +2294,14 @@ class MainWindow(QMainWindow): self.update_status('picking on station {0}'.format(station)) data = self.get_data().getOriginalWFData().copy() event = self.get_current_event() + wftype = self.dataPlot.qcombo_processed.currentText() if self.obspy_dmt else None pickDlg = PickDlg(self, parameter=self._inputs, data=data.select(station=station), station=station, network=network, picks=self.getPicksOnStation(station, 'manual'), autopicks=self.getPicksOnStation(station, 'auto'), metadata=self.metadata, event=event, - filteroptions=self.filteroptions) + filteroptions=self.filteroptions, wftype=wftype) if self.filterActionP.isChecked() or self.filterActionS.isChecked(): pickDlg.currentPhase = self.getSeismicPhase() pickDlg.filterWFData() @@ -2398,8 +2399,7 @@ class MainWindow(QMainWindow): self.init_fig_dict() #if not self.tap: # init TuneAutopicker object - wftype = self.dataPlot.qcombo_processed.currentText() if self.obspy_dmt else None - self.tap = TuneAutopicker(self, wftype) + self.tap = TuneAutopicker(self, self.obspy_dmt) # first call of update to init tabs with empty canvas self.update_autopicker() # connect update signal of TuneAutopicker with update function diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index fd3b1f26..dd9de3c6 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -26,6 +26,7 @@ from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT from matplotlib.widgets import MultiCursor from matplotlib.tight_layout import get_renderer, get_subplotspec_list, get_tight_layout_figure from scipy.signal import argrelmin, argrelmax +from obspy import read from PySide import QtCore, QtGui from PySide.QtGui import QAction, QApplication, QCheckBox, QComboBox, \ @@ -1314,7 +1315,7 @@ class PickDlg(QDialog): def __init__(self, parent=None, data=None, station=None, network=None, picks=None, autopicks=None, rotate=False, parameter=None, embedded=False, metadata=None, - event=None, filteroptions=None, model='iasp91'): + event=None, filteroptions=None, model='iasp91', wftype=None): super(PickDlg, self).__init__(parent, 1) self.orig_parent = parent self.setAttribute(Qt.WA_DeleteOnClose) @@ -1326,6 +1327,7 @@ class PickDlg(QDialog): self.network = network self.rotate = rotate self.metadata = metadata + self.wftype = wftype self.pylot_event = event self.components = 'ZNE' self.currentPhase = None @@ -1415,8 +1417,12 @@ class PickDlg(QDialog): actionS.setChecked(self.getChannelSettingsS(channel)) # plot data + title = self.getStation() + if self.wftype is not None: + title += ' | ({})'.format(self.wftype) + self.multicompfig.plotWFData(wfdata=self.getWFData(), - title=self.getStation()) + title=title) self.multicompfig.setZoomBorders2content() @@ -2583,6 +2589,9 @@ class PickDlg(QDialog): filtops_str = transformFilteroptions2String(filtoptions) title += ' | Filteroptions: {}'.format(filtops_str) + if self.wftype is not None: + title += ' | ({})'.format(self.wftype) + plot_additional = bool(self.compareChannel.currentText()) additional_channel = self.compareChannel.currentText() scale_channel = self.scaleChannel.currentText() @@ -3015,13 +3024,15 @@ class TuneAutopicker(QWidget): :type: PyLoT Mainwindow ''' - def __init__(self, parent, wftype=None): + def __init__(self, parent, obspy_dmt=False): QtGui.QWidget.__init__(self, parent, 1) self._style = parent._style self.setWindowTitle('PyLoT - Tune Autopicker') self.parameter = self.parent()._inputs self.fig_dict = self.parent().fig_dict - self.wftype = wftype + self.data = Data() + self.obspy_dmt = obspy_dmt + self.wftype = None self.pdlg_widget = None self.pylot_picks = None self.init_main_layouts() @@ -3078,36 +3089,57 @@ class TuneAutopicker(QWidget): self.eventBox.activated.connect(self.fill_tabs) self.stationBox.activated.connect(self.fill_tabs) + def catch_station_ids(self): + self.station_ids = {} + eventpath = self.get_current_event_fp() + self.wftype = 'processed' if self.obspy_dmt else '' + wf_path = os.path.join(eventpath, self.wftype) + if not os.path.exists(wf_path) and self.obspy_dmt: + self.wftype = 'raw' + wf_path = os.path.join(eventpath, self.wftype) + for filename in os.listdir(wf_path): + filename = os.path.join(eventpath, self.wftype, filename) + try: + st = read(filename, headonly=True) + except Exception as e: + print('Warning: Could not read file {} as a stream object: {}'.format(filename, e)) + continue + for trace in st: + network = trace.stats.network + station = trace.stats.station + location = trace.stats.location + station_id = '{}.{}.{}'.format(network, station, location) + if not station_id in self.station_ids: + self.station_ids[station_id] = [] + self.station_ids[station_id].append(filename) + def fill_stationbox(self): - #fnames = self.parent().fnames #getWFFnames_from_eventbox(eventbox=self.eventBox) - #self.data.setWFData(fnames) - self.data = self.parent().data - wfdat = self.data.getWFData() # all available streams - # remove possible underscores in station names - # wfdat = remove_underscores(wfdat) - # # rotate misaligned stations to ZNE - # # check for gaps and doubled channels - # check4gaps(wfdat) - # check4doubled(wfdat) - # wfdat = check4rotated(wfdat, self.parent().metadata, verbosity=0) - # # trim station components to same start value - # trim_station_components(wfdat, trim_start=True, trim_end=False) self.stationBox.clear() - stations = [] - for trace in self.data.getWFData(): - station = trace.stats.station - network = trace.stats.network - ns_tup = (str(network), str(station)) - if not ns_tup in stations: - stations.append(ns_tup) - stations.sort() model = self.stationBox.model() - for network, station in stations: - item = QtGui.QStandardItem(network + '.' + station) - if station in self.get_current_event().pylot_picks: + + self.catch_station_ids() + st_ids_list = list(self.station_ids.keys()) + st_ids_list.sort() + for station_id in st_ids_list: + item = QtGui.QStandardItem(station_id) + if station_id.split('.')[1] in self.get_current_event().pylot_picks: item.setBackground(self.parent()._ref_test_colors['ref']) model.appendRow(item) + def load_wf_data(self): + fnames = self.station_ids[self.get_current_station_id()] + self.data.setWFData(fnames) + wfdat = self.data.getWFData() # all available streams + # remove possible underscores in station names + wfdat = remove_underscores(wfdat) + # rotate misaligned stations to ZNE + # check for gaps and doubled channels + check4gaps(wfdat) + check4doubled(wfdat) + wfdat = check4rotated(wfdat, self.parent().metadata, verbosity=0) + # trim station components to same start value + trim_station_components(wfdat, trim_start=True, trim_end=False) + def init_figure_tabs(self): self.figure_tabs = QtGui.QTabWidget() self.fill_figure_tabs() @@ -3153,9 +3185,7 @@ class TuneAutopicker(QWidget): return self.eventBox.currentText().split('/')[-1] def get_current_event_fp(self): - wfext = self.wftype if self.wftype else '' - fp = os.path.join(self.eventBox.currentText(), wfext) - return fp + return self.eventBox.currentText() def get_current_event_picks(self, station): event = self.get_current_event() @@ -3169,7 +3199,10 @@ class TuneAutopicker(QWidget): return event.pylot_autopicks[station] def get_current_station(self): - return str(self.stationBox.currentText()).split('.')[-1] + return str(self.stationBox.currentText()).split('.')[1] + + def get_current_station_id(self): + return str(self.stationBox.currentText()) def gen_tab_widget(self, name, canvas): widget = QtGui.QWidget() @@ -3184,17 +3217,19 @@ class TuneAutopicker(QWidget): self.pdlg_widget.setParent(None) self.pdlg_widget = None return + self.load_wf_data() station = self.get_current_station() wfdata = self.data.getWFData() metadata = self.parent().metadata event = self.get_current_event() filteroptions = self.parent().filteroptions + wftype = self.wftype if self.obspy_dmt else '' self.pickDlg = PickDlg(self.parent(), data=wfdata.select(station=station).copy(), station=station, parameter=self.parameter, picks=self.get_current_event_picks(station), autopicks=self.get_current_event_autopicks(station), metadata=metadata, event=event, filteroptions=filteroptions, - embedded=True) + embedded=True, wftype=wftype) self.pickDlg.update_picks.connect(self.picks_from_pickdlg) self.pickDlg.update_picks.connect(self.fill_eventbox) self.pickDlg.update_picks.connect(self.fill_stationbox) @@ -3381,7 +3416,8 @@ class TuneAutopicker(QWidget): 'iplot': 2, 'fig_dict': self.fig_dict, 'locflag': 0, - 'savexml': False} + 'savexml': False, + 'obspyDMT_wfpath': self.obspy_dmt} for key in self.fig_dict.keys(): if not key == 'plot_style': self.fig_dict[key].clear() From 7ad36c2305e8cfa61c554a75889b02953ba39a2e Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 20 Jun 2018 13:55:59 +0200 Subject: [PATCH 37/70] [bugfix] take width of mainwindow for min/max plot estimation before width was only 80px for initial plot --- pylot/core/util/widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index dd9de3c6..af41dcdb 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -659,7 +659,7 @@ class WaveformWidgetPG(QtGui.QWidget): create min/max array for fast plotting (approach based on obspy __plot_min_max function) :returns data, time_ax ''' - npixel = self.width() + npixel = self.orig_parent.width() ndata = len(trace.data) pts_per_pixel = ndata/npixel if pts_per_pixel < 2: From 2a8efd09043ee386dfdab65d4516723aa8c39b15 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 21 Jun 2018 13:24:24 +0200 Subject: [PATCH 38/70] [bugfix] autoPyLoT <-> obspyDMT --- PyLoT.py | 5 +++-- pylot/core/util/widgets.py | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index 3cee4ef9..b5e5788b 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -2481,6 +2481,7 @@ class MainWindow(QMainWindow): # export current picks etc. self.exportAllEvents(['.xml']) + wfpath = self.dataPlot.qcombo_processed.currentText() if self.obspy_dmt else '' # define arguments for picker args = {'parameter': self._inputs, 'station': 'all', @@ -2490,8 +2491,8 @@ class MainWindow(QMainWindow): 'fig_dict': None, 'fig_dict_wadatijack': self.fig_dict_wadatijack, 'locflag': 0, - 'savexml': False} - + 'savexml': False, + 'obspyDMT_wfpath': wfpath} # init pick thread self.mp_thread = QtCore.QThreadPool() self.mp_worker = Worker(autoPyLoT, args, redirect_stdout=True) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index af41dcdb..1c902c4d 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -3409,6 +3409,7 @@ class TuneAutopicker(QWidget): if not station: self._warn('No station selected') return + wfpath = self.wftype if self.obspy_dmt else '' args = {'parameter': self.parameter, 'station': station, 'fnames': 'None', @@ -3417,7 +3418,7 @@ class TuneAutopicker(QWidget): 'fig_dict': self.fig_dict, 'locflag': 0, 'savexml': False, - 'obspyDMT_wfpath': self.obspy_dmt} + 'obspyDMT_wfpath': wfpath} for key in self.fig_dict.keys(): if not key == 'plot_style': self.fig_dict[key].clear() From a5667c1e06f9972051de7c082510d9a8d7ec8578 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 21 Jun 2018 14:23:52 +0200 Subject: [PATCH 39/70] [bugfix] nextStation not working with deleted PickDlg --- PyLoT.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index b5e5788b..0ff010ea 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -140,6 +140,7 @@ class MainWindow(QMainWindow): self.apd_sge = None self.stations_highlighted = [] self.obspy_dmt = False + self.nextStation = False self.poS_id = None self.ae_id = None @@ -2284,7 +2285,7 @@ class MainWindow(QMainWindow): if nwst in self.stations_highlighted: self.toggle_station_color(wfID, network, station) - def pickDialog(self, wfID, network=None, station=None, nextStation=False): + def pickDialog(self, wfID, network=None, station=None): if not network: network = self.getNetworkName(wfID) if not station: @@ -2305,7 +2306,8 @@ class MainWindow(QMainWindow): if self.filterActionP.isChecked() or self.filterActionS.isChecked(): pickDlg.currentPhase = self.getSeismicPhase() pickDlg.filterWFData() - pickDlg.nextStation.setChecked(nextStation) + pickDlg.nextStation.setChecked(self.nextStation) + pickDlg.nextStation.stateChanged.connect(self.toggle_next_station) if pickDlg.exec_(): if pickDlg._dirty: self.setDirty(True) @@ -2315,13 +2317,13 @@ class MainWindow(QMainWindow): self.enableSaveEventAction() if replot1 or replot2: self.plotWaveformDataThread() - self.drawPicks() + self.draw() else: self.drawPicks(station) self.draw() - if pickDlg.nextStation.isChecked(): - self.pickDialog(wfID - 1, nextStation=pickDlg.nextStation.isChecked()) + if self.nextStation: + self.pickDialog(wfID - 1) else: self.update_status('picks discarded ({0})'.format(station)) if not self.get_loc_flag() and self.check4Loc(): @@ -2330,6 +2332,9 @@ class MainWindow(QMainWindow): elif self.get_loc_flag() and not self.check4Loc(): self.set_loc_flag(False) + def toggle_next_station(self, signal): + self.nextStation = bool(signal) + def addListItem(self, text): self.listWidget.addItem(text) self.listWidget.scrollToBottom() From 1b5f58bbbd0dcd914badd167b66d592837179aec Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 21 Jun 2018 14:24:15 +0200 Subject: [PATCH 40/70] [minor] prefer processed data on init --- pylot/core/util/widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 1c902c4d..23525d5c 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -518,8 +518,8 @@ class WaveformWidgetPG(QtGui.QWidget): self.perm_labels.append(label) self.qcombo_processed = QtGui.QComboBox() self.syn_checkbox = QtGui.QCheckBox('synthetics') - self.addQCboxItem('raw', 'black') self.addQCboxItem('processed', 'green') + self.addQCboxItem('raw', 'black') #self.perm_qcbox_right.setAlignment(2) self.setLayout(self.main_layout) From 34508fc4a31e83ab61fa487490361117ac5e8110 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 21 Jun 2018 15:04:58 +0200 Subject: [PATCH 41/70] [bugfix] addressing PyLoTCanvas already deleted setParent(None) -> del(widget), not fully working on autopickwidget --- pylot/core/util/widgets.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 23525d5c..95d42fca 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -16,6 +16,9 @@ import time import numpy as np +import matplotlib +matplotlib.use('QT4Agg') + from matplotlib.figure import Figure try: @@ -1400,7 +1403,7 @@ class PickDlg(QDialog): # fill compare and scale channels self.compareChannel.addItem('-', None) - self.scaleChannel.addItem('normalized', None) + self.scaleChannel.addItem('individual', None) for trace in self.getWFData(): channel = trace.stats.channel @@ -1601,7 +1604,7 @@ class PickDlg(QDialog): _dialtoolbar.addWidget(QtGui.QLabel('Compare to channel: ')) _dialtoolbar.addWidget(self.compareChannel) _dialtoolbar.addSeparator() - _dialtoolbar.addWidget(QtGui.QLabel('Scale by: ')) + _dialtoolbar.addWidget(QtGui.QLabel('Scaling: ')) _dialtoolbar.addWidget(self.scaleChannel) # layout the innermost widget @@ -2942,7 +2945,7 @@ class AutoPickWidget(MultiEventWidget): def reinitEvents2plot(self): for eventID, eventDict in self.events2plot.items(): for widget_key, widget in eventDict.items(): - widget.setParent(None) + del(widget) self.events2plot = {} self.eventbox.clear() self.refresh_plot_tabs() @@ -3473,9 +3476,7 @@ class TuneAutopicker(QWidget): def clear_all(self): if hasattr(self, 'pdlg_widget'): if self.pdlg_widget: - self.pdlg_widget.setParent(None) - # TODO: removing widget by parent deletion raises exception when activating stationbox: - # RuntimeError: Internal C++ object (PylotCanvas) already deleted. + del(self.pdlg_widget) if hasattr(self, 'overview'): self.overview.setParent(None) if hasattr(self, 'p_tabs'): From b607da7262a7a2fd47c4a110fdf4e542102d0f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Mon, 25 Jun 2018 10:30:36 +0200 Subject: [PATCH 42/70] [Bugfix] it was not sure that enough waveform remains for processing after cutting with improper cut times --- pylot/core/pick/autopick.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylot/core/pick/autopick.py b/pylot/core/pick/autopick.py index 00810447..ca1a6d07 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -333,7 +333,7 @@ def autopickstation(wfstream, pickparam, verbose=False, return Ldiff = Lwf - abs(Lc) - if Ldiff < 0 or pstop <= pstart: + if Ldiff <= 0 or pstop <= pstart or pstop - pstart <= thosmw: msg = 'autopickstation: Cutting times are too large for actual ' \ 'waveform!\nUsing entire waveform instead!' if verbose: print(msg) From 04e75abcf5dd09ca443bfd2e532df7723532c935 Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 25 Jun 2018 14:21:34 +0200 Subject: [PATCH 43/70] [bugfix] read_metadata obspyDMT --- autoPyLoT.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/autoPyLoT.py b/autoPyLoT.py index 79486fc5..3c88742f 100755 --- a/autoPyLoT.py +++ b/autoPyLoT.py @@ -178,7 +178,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even print(" !!! ") wfpath_extension = '' - if obspyDMT_wfpath not in [None, False]: + if obspyDMT_wfpath not in [None, False, 'False']: wfpath_extension = obspyDMT_wfpath print('Using obspyDMT structure. There will be no restitution, as pre-processed data are expected.') if wfpath_extension != 'processed': @@ -281,10 +281,12 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even wfdat = check4gaps(wfdat) wfdat = check4doubled(wfdat) wfdat = trim_station_components(wfdat, trim_start=True, trim_end=False) - if not wfpath_extension: - metadata = read_metadata(parameter.get('invdir')) - else: - metadata = None + metadata = read_metadata(parameter.get('invdir')) + # TODO: (idea) read metadata from obspy_dmt database + # if not wfpath_extension: + # metadata = read_metadata(parameter.get('invdir')) + # else: + # metadata = None corr_dat = None if metadata: # rotate stations to ZNE @@ -530,9 +532,12 @@ if __name__ == "__main__": parser.add_argument('-c', '-C', '--ncores', type=int, action='store', default=0, help='''optional, number of CPU cores used for parallel processing (default: all available(=0))''') + parser.add_argument('-dmt', '-DMT', '--obspy_dmt_wfpath', type=str, + action='store', default=False, + help='''optional, wftype (raw, processed) used for obspyDMT database structure''') cla = parser.parse_args() picks = autoPyLoT(inputfile=str(cla.inputfile), fnames=str(cla.fnames), eventid=str(cla.eventid), savepath=str(cla.spath), - ncores=cla.ncores, iplot=int(cla.iplot)) + ncores=cla.ncores, iplot=int(cla.iplot), obspyDMT_wfpath=str(cla.obspy_dmt_wfpath)) From 77b4458ab5dab15b561a6753ae542577bdce0ecc Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 25 Jun 2018 14:22:14 +0200 Subject: [PATCH 44/70] [idea] change read_metadata to also read files without specific file ending --- pylot/core/util/dataprocessing.py | 63 +++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/pylot/core/util/dataprocessing.py b/pylot/core/util/dataprocessing.py index 6b952164..a83d3f1e 100644 --- a/pylot/core/util/dataprocessing.py +++ b/pylot/core/util/dataprocessing.py @@ -196,6 +196,69 @@ def read_metadata(path_to_inventory): return invtype, robj +# idea to optimize read_metadata +# def read_metadata_new(path_to_inventory): +# metadata_objects = [] +# # read multiple files from directory +# if os.path.isdir(path_to_inventory): +# fnames = os.listdir(path_to_inventory) +# # read single file +# elif os.path.isfile(path_to_inventory): +# fnames = [path_to_inventory] +# else: +# print("Neither dataless-SEED file, inventory-xml file nor " +# "RESP-file found!") +# print("!!WRONG CALCULATION OF SOURCE PARAMETERS!!") +# fnames = [] +# +# for fname in fnames: +# path_to_inventory_filename = os.path.join(path_to_inventory, fname) +# try: +# ftype, robj = read_metadata_file(path_to_inventory_filename) +# metadata_objects.append((ftype, robj)) +# except Exception as e: +# print('Could not read metadata file {} ' +# 'because of the following Exception: {}'.format(path_to_inventory_filename, e)) +# return metadata_objects + + +# def read_metadata_file(path_to_inventory_filename): +# # functions used to read metadata for different file endings (or file types) +# read_functions = {'dless': _read_dless, +# 'dseed': _read_dless, +# 'xml': _read_inventory_file, +# 'resp': _read_inventory_file} +# file_ending = path_to_inventory_filename.split('.')[-1] +# if file_ending in read_functions.keys(): +# robj, exc = read_functions[file_ending](path_to_inventory_filename) +# if exc is not None: +# raise exc +# return file_ending, robj +# # in case file endings did not match the above keys, try and error +# for file_type in ['dless', 'xml']: +# robj, exc = read_functions[file_type](path_to_inventory_filename) +# if exc is None: +# return file_type, robj +# +# +# def _read_dless(path_to_inventory): +# exc = None +# try: +# parser = Parser(path_to_inventory) +# except Exception as exc: +# parser = None +# return parser, exc +# +# +# def _read_inventory_file(path_to_inventory): +# exc = None +# try: +# inv = read_inventory(path_to_inventory) +# except Exception as exc: +# inv = None +# return inv, exc + + def restitute_trace(input_tuple): tr, invtype, inobj, unit, force = input_tuple From b18298c4db7c8b8cfc96e437c988f07a43d805a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Mon, 25 Jun 2018 15:24:36 +0200 Subject: [PATCH 45/70] Additional screen output of derived onset time, [Bugfix] Use of argrelmax not reliable. --- pylot/core/pick/autopick.py | 3 +-- pylot/core/pick/picker.py | 10 ++++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pylot/core/pick/autopick.py b/pylot/core/pick/autopick.py index ca1a6d07..40357c7a 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -564,7 +564,6 @@ def autopickstation(wfstream, pickparam, verbose=False, SNRPdB, FM) print(msg) - msg = 'autopickstation: Refined P-Pick: {} s | P-Error: {} s'.format(mpickP, Perror) print(msg) Sflag = 1 @@ -843,7 +842,7 @@ def autopickstation(wfstream, pickparam, verbose=False, lpickS = lpick[ipick] Serror = pickerr[ipick] - msg = 'autopickstation: Refined S-Pick: {} s | S-Error: {} s'.format(mpickS, Serror) + msg = 'autopickstation: Refined S-Pick: {} s | S-Error: {} s'.format(hdat[0].stats.starttime + mpickS, Serror) print(msg) # get SNR diff --git a/pylot/core/pick/picker.py b/pylot/core/pick/picker.py index 3c0714bc..381000b0 100644 --- a/pylot/core/pick/picker.py +++ b/pylot/core/pick/picker.py @@ -253,13 +253,15 @@ class AICPicker(AutoPicker): except IndexError: print("Slope Calculation: empty array islope, check signal window") return - if len(dataslope) <= 1: + if len(dataslope) <= 2: print('No or not enough data in slope window found!') return - imaxs, = argrelmax(dataslope) - if imaxs.size: + try: + imaxs, = argrelmax(dataslope) + imaxs.size imax = imaxs[0] - else: + except ValueError as e: + print(e, 'picker: argrelmax not working!') imax = np.argmax(dataslope) iislope = islope[0][0:imax + 1] if len(iislope) < 2: From 7d175a4bc9424b4740c93e6e086d6762daa2bba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Mon, 25 Jun 2018 15:30:10 +0200 Subject: [PATCH 46/70] Accidently screen output got lost. --- pylot/core/pick/autopick.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pylot/core/pick/autopick.py b/pylot/core/pick/autopick.py index 40357c7a..8afcaade 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -564,6 +564,8 @@ def autopickstation(wfstream, pickparam, verbose=False, SNRPdB, FM) print(msg) + msg = 'autopickstation: Refind P-Pick: {} s | P-Error: {} s'.format(zdat[0].stats.starttime \ + + mpickP, Perror) print(msg) Sflag = 1 From d4b76bdecb6c251fc55ef9653fa21c3e9c70451e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Mon, 25 Jun 2018 15:31:58 +0200 Subject: [PATCH 47/70] Cosmetics --- pylot/core/pick/autopick.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pylot/core/pick/autopick.py b/pylot/core/pick/autopick.py index 8afcaade..aecd6251 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -844,7 +844,8 @@ def autopickstation(wfstream, pickparam, verbose=False, lpickS = lpick[ipick] Serror = pickerr[ipick] - msg = 'autopickstation: Refined S-Pick: {} s | S-Error: {} s'.format(hdat[0].stats.starttime + mpickS, Serror) + msg = 'autopickstation: Refined S-Pick: {} s | S-Error: {} s'.format(hdat[0].stats.starttime \ + + mpickS, Serror) print(msg) # get SNR From 3845e7291ea52fcc47f94910d6a01e4ef4a3011b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Mon, 25 Jun 2018 15:56:15 +0200 Subject: [PATCH 48/70] Relaxed condition for slope determination, plot interims results even if picking failed. --- pylot/core/pick/picker.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pylot/core/pick/picker.py b/pylot/core/pick/picker.py index 381000b0..56db3df2 100644 --- a/pylot/core/pick/picker.py +++ b/pylot/core/pick/picker.py @@ -253,7 +253,7 @@ class AICPicker(AutoPicker): except IndexError: print("Slope Calculation: empty array islope, check signal window") return - if len(dataslope) <= 2: + if len(dataslope) < 2: print('No or not enough data in slope window found!') return try: @@ -300,8 +300,9 @@ class AICPicker(AutoPicker): datafit = np.polyval(P, xslope) if datafit[0] >= datafit[-1]: print('AICPicker: Negative slope, bad onset skipped!') - return - self.slope = 1 / (len(dataslope) * self.Data[0].stats.delta) * (datafit[-1] - datafit[0]) + #return + else: + self.slope = 1 / (len(dataslope) * self.Data[0].stats.delta) * (datafit[-1] - datafit[0]) else: self.SNR = None @@ -342,8 +343,11 @@ class AICPicker(AutoPicker): label='Slope Window') ax2.plot(self.Tcf[iislope], datafit, 'g', linewidth=2, label='Slope') - ax1.set_title('Station %s, SNR=%7.2f, Slope= %12.2f counts/s' % (self.Data[0].stats.station, - self.SNR, self.slope)) + if self.slope is not None: + ax1.set_title('Station %s, SNR=%7.2f, Slope= %12.2f counts/s' % (self.Data[0].stats.station, + self.SNR, self.slope)) + else: + ax1.set_title('Station %s, SNR=%7.2f' % (self.Data[0].stats.station, self.SNR)) ax2.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime) ax2.set_ylabel('Counts') ax2.set_yticks([]) From 8487d696c6c3facbc8983018e241f5b3b992550f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Mon, 25 Jun 2018 15:59:52 +0200 Subject: [PATCH 49/70] Cosmetics --- pylot/core/pick/picker.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pylot/core/pick/picker.py b/pylot/core/pick/picker.py index 56db3df2..3ec82b6c 100644 --- a/pylot/core/pick/picker.py +++ b/pylot/core/pick/picker.py @@ -300,7 +300,6 @@ class AICPicker(AutoPicker): datafit = np.polyval(P, xslope) if datafit[0] >= datafit[-1]: print('AICPicker: Negative slope, bad onset skipped!') - #return else: self.slope = 1 / (len(dataslope) * self.Data[0].stats.delta) * (datafit[-1] - datafit[0]) From 88ddbc1efc67bd5383969e13ea58f55891f4d9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Tue, 26 Jun 2018 10:51:39 +0200 Subject: [PATCH 50/70] [Bugfix] Time array improper calculated (rounding errors?) --- pylot/core/analysis/magnitude.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pylot/core/analysis/magnitude.py b/pylot/core/analysis/magnitude.py index 1983bf7c..7f813172 100644 --- a/pylot/core/analysis/magnitude.py +++ b/pylot/core/analysis/magnitude.py @@ -6,6 +6,7 @@ Revised/extended summer 2017. :author: Ludger Küperkoch / MAGS2 EP3 working group """ + import matplotlib.pyplot as plt import numpy as np import obspy.core.event as ope @@ -219,7 +220,7 @@ class LocalMagnitude(Magnitude): sqH = np.sqrt(power_sum) # get time array - th = np.arange(0, len(sqH) * dt, dt) + th=np.arange(0, st[0].stats.npts/st[0].stats.sampling_rate, st[0].stats.delta) # get maximum peak within pick window iwin = getsignalwin(th, t0 - stime, self.calc_win) ii = min([iwin[len(iwin) - 1], len(th)]) From f43478d0c081d588acde18a7016a9a48ec0277db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Tue, 26 Jun 2018 11:58:08 +0200 Subject: [PATCH 51/70] Consistent calculation of SNR, using maximum (not mean) of signal window, more stable! --- pylot/core/pick/picker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylot/core/pick/picker.py b/pylot/core/pick/picker.py index 3ec82b6c..5328ca90 100644 --- a/pylot/core/pick/picker.py +++ b/pylot/core/pick/picker.py @@ -239,7 +239,7 @@ class AICPicker(AutoPicker): print(msg) return # calculate SNR from CF - self.SNR = max(abs(self.Data[0].data[isignal] - np.mean(self.Data[0].data[isignal]))) / \ + self.SNR = max(abs(self.Data[0].data[isignal])) / \ max(abs(self.Data[0].data[inoise] - np.mean(self.Data[0].data[inoise]))) # calculate slope from CF after initial pick # get slope window From 4d1c3985f4ab14148ffba5084e7edea8c8c55ad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Tue, 26 Jun 2018 12:25:03 +0200 Subject: [PATCH 52/70] [Bugfix] Input argument iplot was fixed to 1. --- pylot/core/pick/autopick.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pylot/core/pick/autopick.py b/pylot/core/pick/autopick.py index aecd6251..baa450e1 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -100,9 +100,9 @@ def autopickevent(data, param, iplot=0, fig_dict=None, fig_dict_wadatijack=None, # quality control # median check and jackknife on P-onset times - jk_checked_onsets = checkPonsets(all_onsets, mdttolerance, jackfactor, 1, fig_dict_wadatijack) + jk_checked_onsets = checkPonsets(all_onsets, mdttolerance, jackfactor, iplot, fig_dict_wadatijack) # check S-P times (Wadati) - wadationsets = wadaticheck(jk_checked_onsets, wdttolerance, 1, fig_dict_wadatijack) + wadationsets = wadaticheck(jk_checked_onsets, wdttolerance, iplot, fig_dict_wadatijack) return wadationsets From 19f943627a88d3777a05b1a304ca1896d8fcf0b5 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 26 Jun 2018 17:07:38 +0200 Subject: [PATCH 53/70] [bugfixes] autopylot --- autoPyLoT.py | 18 +++--- pylot/core/io/data.py | 2 +- pylot/core/util/dataprocessing.py | 101 +++++++++++++++++++----------- pylot/core/util/widgets.py | 1 + 4 files changed, 76 insertions(+), 46 deletions(-) diff --git a/autoPyLoT.py b/autoPyLoT.py index 3c88742f..bf482d1f 100755 --- a/autoPyLoT.py +++ b/autoPyLoT.py @@ -194,16 +194,16 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even events = [events for events in glob.glob(os.path.join(datapath, '*')) if os.path.isdir(events)] elif fnames == 'None' and parameter['eventID'] is not '*' and not type(parameter['eventID']) == list: # single event processing - events = glob.glob(os.path.join(datapath, parameter['eventID'], wfpath_extension)) + events = glob.glob(os.path.join(datapath, parameter['eventID'])) elif fnames == 'None' and type(parameter['eventID']) == list: # multiple event processing events = [] for eventID in parameter['eventID']: - events.append(os.path.join(datapath, eventID, wfpath_extension)) + events.append(os.path.join(datapath, eventID)) else: # autoPyLoT was initialized from GUI events = [] - events.append(os.path.join(eventid, wfpath_extension)) + events.append(eventid) evID = os.path.split(eventid)[-1] locflag = 2 else: @@ -214,8 +214,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even for eventID in eventid: events.append(os.path.join(datapath, parameter['database'], - eventID, - wfpath_extension)) + eventID)) if not events: print('autoPyLoT: No events given. Return!') @@ -229,10 +228,9 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even allpicks = {} glocflag = locflag for eventpath in events: - if not wfpath_extension: - evID = os.path.split(eventpath)[-1] - else: - evID = os.path.split(os.path.split(eventpath)[0])[-1] + evID = os.path.split(eventpath)[-1] + if wfpath_extension: + event_datapath = os.path.join(eventpath, wfpath_extension) fext = '.xml' filename = os.path.join(eventpath, 'PyLoT_' + evID + fext) try: @@ -245,7 +243,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even pylot_event = Event(eventpath) # event should be path to event directory data.setEvtData(pylot_event) if fnames == 'None': - data.setWFData(glob.glob(os.path.join(datapath, eventpath, '*'))) + data.setWFData(glob.glob(os.path.join(datapath, event_datapath, '*'))) # the following is necessary because within # multiple event processing no event ID is provided # in autopylot.in diff --git a/pylot/core/io/data.py b/pylot/core/io/data.py index f10242db..e84badea 100644 --- a/pylot/core/io/data.py +++ b/pylot/core/io/data.py @@ -43,7 +43,7 @@ class Data(object): elif isinstance(evtdata, dict): evt = readPILOTEvent(**evtdata) evtdata = evt - elif isinstance(evtdata, str): + elif type(evtdata) in [str, unicode]: try: cat = read_events(evtdata) if len(cat) is not 1: diff --git a/pylot/core/util/dataprocessing.py b/pylot/core/util/dataprocessing.py index a83d3f1e..cd8cd004 100644 --- a/pylot/core/util/dataprocessing.py +++ b/pylot/core/util/dataprocessing.py @@ -222,41 +222,72 @@ def read_metadata(path_to_inventory): # return metadata_objects -# def read_metadata_file(path_to_inventory_filename): -# # functions used to read metadata for different file endings (or file types) -# read_functions = {'dless': _read_dless, -# 'dseed': _read_dless, -# 'xml': _read_inventory_file, -# 'resp': _read_inventory_file} -# file_ending = path_to_inventory_filename.split('.')[-1] -# if file_ending in read_functions.keys(): -# robj, exc = read_functions[file_ending](path_to_inventory_filename) -# if exc is not None: -# raise exc -# return file_ending, robj -# # in case file endings did not match the above keys, try and error -# for file_type in ['dless', 'xml']: -# robj, exc = read_functions[file_type](path_to_inventory_filename) -# if exc is None: -# return file_type, robj -# -# -# def _read_dless(path_to_inventory): -# exc = None -# try: -# parser = Parser(path_to_inventory) -# except Exception as exc: -# parser = None -# return parser, exc -# -# -# def _read_inventory_file(path_to_inventory): -# exc = None -# try: -# inv = read_inventory(path_to_inventory) -# except Exception as exc: -# inv = None -# return inv, exc +def read_metadata_iterator(path_to_inventory, station_seed_id): + ''' + # search for metadata for a specific station iteratively + ''' + station, network, location, channel = station_seed_id.split('.') + fnames = glob.glob(os.path.join(path_to_inventory, '*' + station_seed_id + '*')) + if not fnames: + # search for station name in filename + fnames = glob.glob(os.path.join(path_to_inventory, '*' + station + '*')) + if not fnames: + # search for network name in filename + fnames = glob.glob(os.path.join(path_to_inventory, '*' + network + '*')) + if not fnames: + print('Could not find filenames matching station name, network name or seed id') + return + for fname in fnames: + invtype, robj = read_metadata_file(os.path.join(path_to_inventory, fname)) + try: + robj.get_coordinates(station_seed_id) + return invtype, robj + except Exception as e: + continue + print('Could not find metadata for station_seed_id {} in path {}'.format(station_seed_id, path_to_inventory)) + + + +def read_metadata_file(path_to_inventory_filename): + ''' + function reading metadata files (either dataless seed, xml or resp) + :param path_to_inventory_filename: + :return: file type/ending, inventory object (Parser or Inventory) + ''' + # functions used to read metadata for different file endings (or file types) + read_functions = {'dless': _read_dless, + 'dseed': _read_dless, + 'xml': _read_inventory_file, + 'resp': _read_inventory_file} + file_ending = path_to_inventory_filename.split('.')[-1] + if file_ending in read_functions.keys(): + robj, exc = read_functions[file_ending](path_to_inventory_filename) + if exc is not None: + raise exc + return file_ending, robj + # in case file endings did not match the above keys, try and error + for file_type in ['dless', 'xml']: + robj, exc = read_functions[file_type](path_to_inventory_filename) + if exc is None: + return file_type, robj + + +def _read_dless(path_to_inventory): + exc = None + try: + parser = Parser(path_to_inventory) + except Exception as exc: + parser = None + return parser, exc + + +def _read_inventory_file(path_to_inventory): + exc = None + try: + inv = read_inventory(path_to_inventory) + except Exception as exc: + inv = None + return inv, exc def restitute_trace(input_tuple): diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 95d42fca..b94998eb 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -3476,6 +3476,7 @@ class TuneAutopicker(QWidget): def clear_all(self): if hasattr(self, 'pdlg_widget'): if self.pdlg_widget: + self.pdlg_widget.setParent(None) del(self.pdlg_widget) if hasattr(self, 'overview'): self.overview.setParent(None) From 3a66ec1c95447e0e812cab67d7d6d44461fd6abe Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 27 Jun 2018 14:20:11 +0200 Subject: [PATCH 54/70] [bugfix] print a warning in case saveData fails --- PyLoT.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/PyLoT.py b/PyLoT.py index 0ff010ea..86199243 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -1428,7 +1428,10 @@ class MainWindow(QMainWindow): def exportAllEvents(self, outformats=['.xml']): for event in self.project.eventlist: self.get_data().setEvtData(event) - self.saveData(event, event.path, outformats) + try: + self.saveData(event, event.path, outformats) + except Exception as e: + print('WARNING! Could not save event {}. Reason: {}'.format(event.path, e)) def enableSaveEventAction(self): self.saveEventAction.setEnabled(True) From 8ae0449c0160264e2c710426a0427d84b915a466 Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 27 Jun 2018 14:21:20 +0200 Subject: [PATCH 55/70] [new] metadata class (WIP) --- pylot/core/util/dataprocessing.py | 247 ++++++++++++++++++++++-------- 1 file changed, 180 insertions(+), 67 deletions(-) diff --git a/pylot/core/util/dataprocessing.py b/pylot/core/util/dataprocessing.py index cd8cd004..ee74a960 100644 --- a/pylot/core/util/dataprocessing.py +++ b/pylot/core/util/dataprocessing.py @@ -12,6 +12,186 @@ from pylot.core.util.utils import key_for_set_value, find_in_list, \ remove_underscores, gen_Pool +class Metadata(object): + def __init__(self, inventory=None): + self.inventories = [] + if os.path.isdir(inventory): + self.add_inventory(inventory) + if os.path.isfile(inventory): + self.add_inventory_file(inventory) + self.seed_ids = {} + self.inventory_files = {} + + + def add_inventory(self, path_to_inventory): + # add paths to list of inventories + assert (os.path.isdir(path_to_inventory)), '{} is no directory'.format(path_to_inventory) + if not path_to_inventory in self.inventories: + self.inventories.append(path_to_inventory) + + + def add_inventory_file(self, path_to_inventory_file): + assert (os.path.isfile(path_to_inventory_file)), '{} is no directory'.format(path_to_inventory_file) + self.add_inventory(os.path.split(path_to_inventory_file)[0]) + if not path_to_inventory_file in self.inventory_files.keys(): + self.read_single_file(path_to_inventory_file) + + + def remove_inventory(self, path_to_inventory): + if not path_to_inventory in self.inventories: + print('Path {} not in inventories list.'.format(path_to_inventory)) + return + self.inventories.remove(path_to_inventory) + + + def get_metadata(self, seed_id): + # get metadata for a specific seed_id, if not already read, try to read from inventories + if not seed_id in self.seed_ids.keys(): + self._read_inventory_data(seed_id) + # if seed id is not found read all inventories and try to find it there + if not seed_id in self.seed_ids.keys(): + print('No data found for seed id {}. Trying to find it in all known inventories...'.format(seed_id)) + self.read_all() + for inv_fname, metadata in self.inventory_files.items(): + # use get_coordinates to check for seed_id + if metadata['data'].get_coordinates(seed_id): + self.seed_ids[seed_id] = inv_fname + return metadata + print('Could not find metadata for station {}'.format(seed_id)) + return None + fname = self.seed_ids[seed_id] + return self.inventory_files[fname] + + + def read_all(self): + for inventory in self.inventories: + for inv_fname in os.listdir(inventory): + inv_fname = os.path.join(inventory, inv_fname) + if not self.read_single_file(inv_fname): + continue + + + def read_single_file(self, inv_fname): + if not inv_fname in self.inventory_files.keys(): + pass + else: + if not self.inventory_files[inv_fname]: + pass + else: + return + try: + invtype, robj = self._read_metadata_file(inv_fname) + if robj == None: + return + except Exception as e: + print('Could not read file {}'.format(inv_fname)) + return + self.inventory_files[inv_fname] = {'invtype': invtype, + 'data': robj} + return True + + + def get_coordinates(self, seed_id): + metadata = self.get_metadata(seed_id) + return metadata['data'].get_coordinates(seed_id) + + + def get_paz(self, seed_id, time=None): + metadata = self.get_metadata(seed_id) + if metadata['invtype'] in ['dless', 'dseed']: + return metadata['data'].get_paz(seed_id) + elif metadata['invtype'] in ['resp', 'xml']: + if not time: + print('Time needed to extract metadata from station inventory.') + return None + resp = metadata['data'].get_response(seed_id, time) + return resp.get_paz(seed_id) + + + def _read_inventory_data(self, seed_id=None): + for inventory in self.inventories: + if self._read_metadata_iterator(path_to_inventory=inventory, station_seed_id=seed_id): + return + + + def _read_metadata_iterator(self, path_to_inventory, station_seed_id): + ''' + search for metadata for a specific station iteratively + ''' + station, network, location, channel = station_seed_id.split('.') + fnames = glob.glob(os.path.join(path_to_inventory, '*' + station_seed_id + '*')) + if not fnames: + # search for station name in filename + fnames = glob.glob(os.path.join(path_to_inventory, '*' + station + '*')) + if not fnames: + # search for network name in filename + fnames = glob.glob(os.path.join(path_to_inventory, '*' + network + '*')) + if not fnames: + print('Could not find filenames matching station name, network name or seed id') + return + for fname in fnames: + if fname in self.inventory_files.keys(): + if self.inventory_files[fname]: + # file already read + continue + invtype, robj = self._read_metadata_file(os.path.join(path_to_inventory, fname)) + try: + robj.get_coordinates(station_seed_id) + self.inventory_files[fname] = {'invtype': invtype, + 'data': robj} + if station_seed_id in self.seed_ids.keys(): + print('WARNING: Overwriting metadata for station {}'.format(station_seed_id)) + self.seed_ids[station_seed_id] = fname + return True + except Exception as e: + continue + print('Could not find metadata for station_seed_id {} in path {}'.format(station_seed_id, path_to_inventory)) + + + def _read_metadata_file(self, path_to_inventory_filename): + ''' + function reading metadata files (either dataless seed, xml or resp) + :param path_to_inventory_filename: + :return: file type/ending, inventory object (Parser or Inventory) + ''' + # functions used to read metadata for different file endings (or file types) + read_functions = {'dless': self._read_dless, + 'dseed': self._read_dless, + 'xml': self._read_inventory_file, + 'resp': self._read_inventory_file} + file_ending = path_to_inventory_filename.split('.')[-1] + if file_ending in read_functions.keys(): + robj, exc = read_functions[file_ending](path_to_inventory_filename) + if exc is not None: + raise exc + return file_ending, robj + # in case file endings did not match the above keys, try and error + for file_type in ['dless', 'xml']: + robj, exc = read_functions[file_type](path_to_inventory_filename) + if exc is None: + return file_type, robj + return None, None + + + def _read_dless(self, path_to_inventory): + exc = None + try: + parser = Parser(path_to_inventory) + except Exception as exc: + parser = None + return parser, exc + + + def _read_inventory_file(self, path_to_inventory): + exc = None + try: + inv = read_inventory(path_to_inventory) + except Exception as exc: + inv = None + return inv, exc + + + def time_from_header(header): """ Function takes in the second line from a .gse file and takes out the date and time from that line. @@ -222,73 +402,6 @@ def read_metadata(path_to_inventory): # return metadata_objects -def read_metadata_iterator(path_to_inventory, station_seed_id): - ''' - # search for metadata for a specific station iteratively - ''' - station, network, location, channel = station_seed_id.split('.') - fnames = glob.glob(os.path.join(path_to_inventory, '*' + station_seed_id + '*')) - if not fnames: - # search for station name in filename - fnames = glob.glob(os.path.join(path_to_inventory, '*' + station + '*')) - if not fnames: - # search for network name in filename - fnames = glob.glob(os.path.join(path_to_inventory, '*' + network + '*')) - if not fnames: - print('Could not find filenames matching station name, network name or seed id') - return - for fname in fnames: - invtype, robj = read_metadata_file(os.path.join(path_to_inventory, fname)) - try: - robj.get_coordinates(station_seed_id) - return invtype, robj - except Exception as e: - continue - print('Could not find metadata for station_seed_id {} in path {}'.format(station_seed_id, path_to_inventory)) - - - -def read_metadata_file(path_to_inventory_filename): - ''' - function reading metadata files (either dataless seed, xml or resp) - :param path_to_inventory_filename: - :return: file type/ending, inventory object (Parser or Inventory) - ''' - # functions used to read metadata for different file endings (or file types) - read_functions = {'dless': _read_dless, - 'dseed': _read_dless, - 'xml': _read_inventory_file, - 'resp': _read_inventory_file} - file_ending = path_to_inventory_filename.split('.')[-1] - if file_ending in read_functions.keys(): - robj, exc = read_functions[file_ending](path_to_inventory_filename) - if exc is not None: - raise exc - return file_ending, robj - # in case file endings did not match the above keys, try and error - for file_type in ['dless', 'xml']: - robj, exc = read_functions[file_type](path_to_inventory_filename) - if exc is None: - return file_type, robj - - -def _read_dless(path_to_inventory): - exc = None - try: - parser = Parser(path_to_inventory) - except Exception as exc: - parser = None - return parser, exc - - -def _read_inventory_file(path_to_inventory): - exc = None - try: - inv = read_inventory(path_to_inventory) - except Exception as exc: - inv = None - return inv, exc - def restitute_trace(input_tuple): tr, invtype, inobj, unit, force = input_tuple From 5870843a033591436f27b4a1ca629d7526028b90 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 28 Jun 2018 10:31:48 +0200 Subject: [PATCH 56/70] [bugfix] event_datapath not set if not obspyDMT --- autoPyLoT.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/autoPyLoT.py b/autoPyLoT.py index bf482d1f..2d6a1c14 100755 --- a/autoPyLoT.py +++ b/autoPyLoT.py @@ -229,8 +229,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even glocflag = locflag for eventpath in events: evID = os.path.split(eventpath)[-1] - if wfpath_extension: - event_datapath = os.path.join(eventpath, wfpath_extension) + event_datapath = os.path.join(eventpath, wfpath_extension) fext = '.xml' filename = os.path.join(eventpath, 'PyLoT_' + evID + fext) try: From 4cb3f72ba81fdfa301a29d2a2af892aefc635687 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 28 Jun 2018 15:22:40 +0200 Subject: [PATCH 57/70] [bugfixes] location/magnitude w ludger --- PyLoT.py | 44 ++++++-------------------------- autoPyLoT.py | 8 +++--- pylot/core/analysis/magnitude.py | 9 +++++-- pylot/core/util/widgets.py | 1 - 4 files changed, 18 insertions(+), 44 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index 86199243..379c2f85 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -2498,7 +2498,6 @@ class MainWindow(QMainWindow): 'iplot': 0, 'fig_dict': None, 'fig_dict_wadatijack': self.fig_dict_wadatijack, - 'locflag': 0, 'savexml': False, 'obspyDMT_wfpath': wfpath} # init pick thread @@ -2756,55 +2755,28 @@ class MainWindow(QMainWindow): """ if not self.okToContinue(): return - settings = QSettings() - # get location tool hook - loctool = settings.value("loc/tool", "nll") + parameter = self._inputs + loctool = 'nll' lt = locateTool[loctool] # get working directory - locroot = settings.value("{0}/rootPath".format(loctool), None) + locroot = parameter['nllocroot'] if locroot is None: self.PyLoTprefs() self.locate_event() - infile = settings.value("{0}/inputFile".format(loctool), None) + ctrfile = parameter['ctrfile'] - if not infile: - caption = 'Select {0} input file'.format(loctool) - filt = "Supported file formats" \ - " (*.in *.ini *.conf *.cfg)" - ans = QFileDialog().getOpenFileName(self, caption=caption, - filter=filt, dir=locroot) - if ans[0]: - infile = ans[0] - else: - QMessageBox.information(self, - self.tr('No infile selected'), - self.tr('Inputfile necessary for localization.')) - return - settings.setValue("{0}/inputFile".format(loctool), infile) - settings.sync() - if loctool == 'nll': - ttt = settings.value("{0}/travelTimeTables", None) - ok = False - if ttt is None: - while not ok: - text, ok = QInputDialog.getText(self, 'Pattern for travel time tables', - 'Base name of travel time tables', - echo=QLineEdit.Normal, - text="ttime") - ttt = text - - outfile = settings.value("{0}/outputFile".format(loctool), - os.path.split(os.tempnam())[-1]) + ttt = parameter['ttpatter'] + outfile = parameter['outpatter'] eventname = self.get_current_event_name() obsdir = os.path.join(self._inputs['rootpath'], self._inputs['datapath'], self._inputs['database'], eventname) self.saveData(event=self.get_current_event(), directory=obsdir, outformats='.obs') filename = 'PyLoT_' + eventname locpath = os.path.join(locroot, 'loc', filename) phasefile = os.path.join(obsdir, filename + '.obs') - lt.modify_inputs(infile, locroot, filename, phasefile, ttt) + lt.modify_inputs(ctrfile, locroot, filename, phasefile, ttt) try: - lt.locate(infile) + lt.locate(ctrfile) except RuntimeError as e: print(e.message) #finally: diff --git a/autoPyLoT.py b/autoPyLoT.py index 2d6a1c14..a8eebabb 100755 --- a/autoPyLoT.py +++ b/autoPyLoT.py @@ -94,7 +94,6 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even fig_dict = None fig_dict_wadatijack = None - locflag = 1 if input_dict and isinstance(input_dict, dict): if 'parameter' in input_dict: parameter = input_dict['parameter'] @@ -110,8 +109,6 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even eventid = input_dict['eventid'] if 'iplot' in input_dict: iplot = input_dict['iplot'] - if 'locflag' in input_dict: - locflag = input_dict['locflag'] if 'savexml' in input_dict: savexml = input_dict['savexml'] if 'obspyDMT_wfpath' in input_dict: @@ -153,7 +150,8 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even datastructure.setExpandFields(exf) # check if default location routine NLLoc is available - if real_None(parameter['nllocbin']) and locflag: + if real_None(parameter['nllocbin']): + locflag = 1 # get NLLoc-root path nllocroot = parameter.get('nllocroot') # get path to NLLoc executable @@ -178,7 +176,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even print(" !!! ") wfpath_extension = '' - if obspyDMT_wfpath not in [None, False, 'False']: + if obspyDMT_wfpath not in [None, False, 'False', '']: wfpath_extension = obspyDMT_wfpath print('Using obspyDMT structure. There will be no restitution, as pre-processed data are expected.') if wfpath_extension != 'processed': diff --git a/pylot/core/analysis/magnitude.py b/pylot/core/analysis/magnitude.py index 7f813172..08704f7b 100644 --- a/pylot/core/analysis/magnitude.py +++ b/pylot/core/analysis/magnitude.py @@ -122,7 +122,13 @@ class Magnitude(object): def net_magnitude(self, magscaling=None): if self: - if magscaling is not None and str(magscaling) is not '[0.0, 0.0]': + if magscaling == None: + scaling = False + elif magscaling[0] != 0 and magscaling[1] != 0: + scaling = False + else: + scaling = True + if scaling: # scaling necessary print("Scaling network magnitude ...") mag = ope.Magnitude( @@ -141,7 +147,6 @@ class Magnitude(object): station_count=len(self.magnitudes), azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap) return mag - return None class LocalMagnitude(Magnitude): diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index b94998eb..60f64939 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -3419,7 +3419,6 @@ class TuneAutopicker(QWidget): 'eventid': [self.get_current_event_fp()], 'iplot': 2, 'fig_dict': self.fig_dict, - 'locflag': 0, 'savexml': False, 'obspyDMT_wfpath': wfpath} for key in self.fig_dict.keys(): From f4201c4e2f6ca70c74d6f97d0754f5db563b5a42 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 28 Jun 2018 15:59:13 +0200 Subject: [PATCH 58/70] [bugfix] full path for ctrfile --- PyLoT.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PyLoT.py b/PyLoT.py index 379c2f85..a11b7374 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -2764,7 +2764,7 @@ class MainWindow(QMainWindow): self.PyLoTprefs() self.locate_event() - ctrfile = parameter['ctrfile'] + ctrfile = os.path.join(locroot, 'run', parameter['ctrfile']) ttt = parameter['ttpatter'] outfile = parameter['outpatter'] From 9b63c1bb241f3532cce138f8d6b349688d541ed1 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 29 Jun 2018 10:13:58 +0200 Subject: [PATCH 59/70] [bugfix] taupy phases lost on plot refresh --- pylot/core/util/widgets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 60f64939..1b78a456 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -1727,7 +1727,7 @@ class PickDlg(QDialog): self.arrivalsText.append(ax.text(time_rel, ylims[0], arrival.name, color='0.5')) def drawArrivalsText(self): - return self.drawArrivals(True) + return self.drawArrivals(textOnly=True) def refreshArrivalsText(self, event=None): self.removeArrivalsText() @@ -2682,6 +2682,7 @@ class PickDlg(QDialog): phase = 'S' filter = True self.plotWFData(phase=phase, filter=filter) + self.drawArrivals() def resetZoom(self): ax = self.multicompfig.axes[0] From 22e5de194e9c41dc8bc33a978c6f7062f21fa8cf Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 29 Jun 2018 13:55:42 +0200 Subject: [PATCH 60/70] [bugfix] array map only checking for manual picks --- pylot/core/util/array_map.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pylot/core/util/array_map.py b/pylot/core/util/array_map.py index 91dee54e..de9a3bf3 100644 --- a/pylot/core/util/array_map.py +++ b/pylot/core/util/array_map.py @@ -375,13 +375,13 @@ class Array_map(QtGui.QWidget): self.draw_everything() def draw_everything(self): - if self.picks_dict: + if self.picks_dict or self.autopicks_dict: self.init_picks() if len(self.picks) >= 3: self.init_picksgrid() self.draw_contour_filled() self.scatter_all_stations() - if self.picks_dict: + if self.picks_dict or self.autopicks_dict: self.scatter_picked_stations() self.cbar = self.add_cbar(label='Time relative to first onset ({}) [s]'.format(self._earliest_picktime)) self.comboBox_phase.setEnabled(True) From 2c07dd63b8c378d63962462f33831cc2072f3683 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 29 Jun 2018 14:19:09 +0200 Subject: [PATCH 61/70] [bugfix] save Event before tarting tuneAutopicker (else source information might not be accessible to autoPyLoT) --- pylot/core/util/widgets.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 1b78a456..e9b1a965 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -3422,6 +3422,8 @@ class TuneAutopicker(QWidget): 'fig_dict': self.fig_dict, 'savexml': False, 'obspyDMT_wfpath': wfpath} + event = self.get_current_event() + self.parent().saveData(event, event.path, '.xml') for key in self.fig_dict.keys(): if not key == 'plot_style': self.fig_dict[key].clear() From d2ba8888d1ba3e96762c3c6be2d7354e0e85508c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Fri, 29 Jun 2018 15:07:26 +0200 Subject: [PATCH 62/70] Reduced maximum number if iterations to two, some effort to avoid error for screen output if no magnitude scaling is applied. --- autoPyLoT.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/autoPyLoT.py b/autoPyLoT.py index a8eebabb..6b209f4f 100755 --- a/autoPyLoT.py +++ b/autoPyLoT.py @@ -167,7 +167,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even ttpat = parameter.get('ttpatter') # pattern of NLLoc-output file nllocoutpatter = parameter.get('outpatter') - maxnumit = 3 # maximum number of iterations for re-picking + maxnumit = 2 # maximum number of iterations for re-picking else: locflag = 0 print(" !!! ") @@ -439,8 +439,15 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even evt = local_mag.updated_event(magscaling) net_ml = local_mag.net_magnitude(magscaling) print("Network local magnitude: %4.1f" % net_ml.mag) - print("Network local magnitude scaled with:") - print("%f * Ml + %f" % (magscaling[0], magscaling[1])) + if magscaling == None: + scaling = False + elif magscaling[0] != 0 and magscaling[1] != 0: + scaling = False + else: + scaling = True + if scaling: + print("Network local magnitude scaled with:") + print("%f * Ml + %f" % (magscaling[0], magscaling[1])) else: print("autoPyLoT: No NLLoc-location file available! Stop iteration!") locflag = 9 From 4896c1e1d8f50a849d1645f9df0de55fe465668e Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 2 Jul 2018 13:34:30 +0200 Subject: [PATCH 63/70] [cleanup] removed redundancy --- pylot/core/pick/picker.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/pylot/core/pick/picker.py b/pylot/core/pick/picker.py index 5328ca90..bb35ec7a 100644 --- a/pylot/core/pick/picker.py +++ b/pylot/core/pick/picker.py @@ -221,7 +221,7 @@ class AICPicker(AutoPicker): # get noise window inoise = getnoisewin(self.Tcf, self.Pick, self.TSNR[0], self.TSNR[1]) # check, if these are counts or m/s, important for slope estimation! - # this is quick and dirty, better solution? + # this is quick and dirty, better solution? #Todo wtf if max(self.Data[0].data < 1e-3) and max(self.Data[0].data >= 1e-6): self.Data[0].data = self.Data[0].data * 1000000. elif max(self.Data[0].data < 1e-6): @@ -351,18 +351,14 @@ class AICPicker(AutoPicker): ax2.set_ylabel('Counts') ax2.set_yticks([]) ax2.legend(loc=1) - if plt_flag == 1: - fig.show() - try: input() - except SyntaxError: pass - plt.close(fig) else: ax1.set_title(self.Data[0].stats.station) - if plt_flag == 1: - fig.show() - try: input() - except SyntaxError: pass - plt.close(fig) + + if plt_flag == 1: + fig.show() + try: input() + except SyntaxError: pass + plt.close(fig) if self.Pick == None: print('AICPicker: Could not find minimum, picking window too short?') From 854f5b8c7ee8c93f45bef8a4c1130867dcc906a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Tue, 3 Jul 2018 10:34:43 +0200 Subject: [PATCH 64/70] [Bugfix] No network magnitude available for screen output while tuning --- autoPyLoT.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/autoPyLoT.py b/autoPyLoT.py index 6b209f4f..5db95399 100755 --- a/autoPyLoT.py +++ b/autoPyLoT.py @@ -346,7 +346,8 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even picks[stats]['P'].update(props) evt = moment_mag.updated_event() net_mw = moment_mag.net_magnitude() - print("Network moment magnitude: %4.1f" % net_mw.mag) + if net_mw is not None: + print("Network moment magnitude: %4.1f" % net_mw.mag) # calculate local (Richter) magntiude WAscaling = parameter.get('WAscaling') magscaling = parameter.get('magscaling') @@ -363,8 +364,15 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even evt = local_mag.updated_event(magscaling) net_ml = local_mag.net_magnitude(magscaling) print("Network local magnitude: %4.1f" % net_ml.mag) - print("Network local magnitude scaled with:") - print("%f * Ml + %f" % (magscaling[0], magscaling[1])) + if magscaling == None: + scaling = False + elif magscaling[0] != 0 and magscaling[1] != 0: + scaling = False + else: + scaling = True + if scaling: + print("Network local magnitude scaled with:") + print("%f * Ml + %f" % (magscaling[0], magscaling[1])) else: print("autoPyLoT: No NLLoc-location file available!") print("No source parameter estimation possible!") @@ -421,7 +429,8 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even picks[stats]['P'].update(props) evt = moment_mag.updated_event() net_mw = moment_mag.net_magnitude() - print("Network moment magnitude: %4.1f" % net_mw.mag) + if net_mw is not None: + print("Network moment magnitude: %4.1f" % net_mw.mag) # calculate local (Richter) magntiude WAscaling = parameter.get('WAscaling') magscaling = parameter.get('magscaling') From 46d4ad7ea54a6054fd2e901f24164c17ed35526b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Tue, 3 Jul 2018 10:35:09 +0200 Subject: [PATCH 65/70] Some new parameter settings. --- inputs/pylot_local.in | 66 +++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/inputs/pylot_local.in b/inputs/pylot_local.in index fe019440..ccfeddd4 100644 --- a/inputs/pylot_local.in +++ b/inputs/pylot_local.in @@ -4,19 +4,19 @@ %Parameters are optimized for %extent data sets! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #main settings# - #rootpath# %project path - #datapath# %data path - #database# %name of data base - #eventID# %event ID for single event processing (* for all events found in database) - #invdir# %full path to inventory or dataless-seed file +/DATA/Insheim #rootpath# %project path +EVENT_DATA/LOCAL #datapath# %data path +2018.02_Insheim #database# %name of data base +e0006.038.18 #eventID# %event ID for single event processing (* for all events found in database) +/DATA/Insheim/STAT_INFO #invdir# %full path to inventory or dataless-seed file PILOT #datastructure# %choose data structure True #apverbose# %choose 'True' or 'False' for terminal output %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #NLLoc settings# -None #nllocbin# %path to NLLoc executable -None #nllocroot# %root of NLLoc-processing directory -None #phasefile# %name of autoPyLoT-output phase file for NLLoc -None #ctrfile# %name of autoPyLoT-output control file for NLLoc +/home/ludger/NLLOC #nllocbin# %path to NLLoc executable +/home/ludger/NLLOC/Insheim #nllocroot# %root of NLLoc-processing directory +AUTOPHASES.obs #phasefile# %name of autoPyLoT-output phase file for NLLoc +Insheim_min1d032016_auto.in #ctrfile# %name of autoPyLoT-output control file for NLLoc ttime #ttpatter# %pattern of NLLoc ttimes from grid AUTOLOC_nlloc #outpatter# %pattern of NLLoc-output file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -27,31 +27,31 @@ AUTOLOC_nlloc #outpatter# %pattern of %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #settings local magnitude# 1.11 0.0009 -2.0 #WAscaling# %Scaling relation (log(Ao)+Alog(r)+Br+C) of Wood-Anderson amplitude Ao [nm] If zeros are set, original Richter magnitude is calculated! -1.0382 -0.447 #magscaling# %Scaling relation for derived local magnitude [a*Ml+b]. If zeros are set, no scaling of network magnitude is applied! +0.0 0.0 #magscaling# %Scaling relation for derived local magnitude [a*Ml+b]. If zeros are set, no scaling of network magnitude is applied! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #filter settings# -1.0 1.0 #minfreq# %Lower filter frequency [P, S] -10.0 10.0 #maxfreq# %Upper filter frequency [P, S] -2 2 #filter_order# %filter order [P, S] +2.0 2.0 #minfreq# %Lower filter frequency [P, S] +30.0 15.0 #maxfreq# %Upper filter frequency [P, S] +3 3 #filter_order# %filter order [P, S] bandpass bandpass #filter_type# %filter type (bandpass, bandstop, lowpass, highpass) [P, S] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #common settings picker# local #extent# %extent of array ("local", "regional" or "global") -15.0 #pstart# %start time [s] for calculating CF for P-picking -60.0 #pstop# %end time [s] for calculating CF for P-picking --1.0 #sstart# %start time [s] relative to P-onset for calculating CF for S-picking +7.0 #pstart# %start time [s] for calculating CF for P-picking +16.0 #pstop# %end time [s] for calculating CF for P-picking +-0.5 #sstart# %start time [s] relative to P-onset for calculating CF for S-picking 10.0 #sstop# %end time [s] after P-onset for calculating CF for S-picking -True #use_taup# %use estimated traveltimes from TauPy for calculating windows for CF +False #use_taup# %use estimated traveltimes from TauPy for calculating windows for CF iasp91 #taup_model# %define TauPy model for traveltime estimation -2.0 10.0 #bpz1# %lower/upper corner freq. of first band pass filter Z-comp. [Hz] -2.0 12.0 #bpz2# %lower/upper corner freq. of second band pass filter Z-comp. [Hz] -2.0 8.0 #bph1# %lower/upper corner freq. of first band pass filter H-comp. [Hz] -2.0 10.0 #bph2# %lower/upper corner freq. of second band pass filter z-comp. [Hz] +2.0 20.0 #bpz1# %lower/upper corner freq. of first band pass filter Z-comp. [Hz] +2.0 30.0 #bpz2# %lower/upper corner freq. of second band pass filter Z-comp. [Hz] +2.0 10.0 #bph1# %lower/upper corner freq. of first band pass filter H-comp. [Hz] +2.0 15.0 #bph2# %lower/upper corner freq. of second band pass filter z-comp. [Hz] #special settings for calculating CF# %!!Edit the following only if you know what you are doing!!% #Z-component# HOS #algoP# %choose algorithm for P-onset determination (HOS, ARZ, or AR3) -7.0 #tlta# %for HOS-/AR-AIC-picker, length of LTA window [s] +4.0 #tlta# %for HOS-/AR-AIC-picker, length of LTA window [s] 4 #hosorder# %for HOS-picker, order of Higher Order Statistics 2 #Parorder# %for AR-picker, order of AR process of Z-component 1.2 #tdet1z# %for AR-picker, length of AR determination window [s] for Z-component, 1st pick @@ -59,12 +59,12 @@ HOS #algoP# %choose algo 0.6 #tdet2z# %for AR-picker, length of AR determination window [s] for Z-component, 2nd pick 0.2 #tpred2z# %for AR-picker, length of AR prediction window [s] for Z-component, 2nd pick 0.001 #addnoise# %add noise to seismogram for stable AR prediction -3.0 0.1 0.5 1.0 #tsnrz# %for HOS/AR, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s] +3.0 0.0 1.0 0.5 #tsnrz# %for HOS/AR, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s] 3.0 #pickwinP# %for initial AIC pick, length of P-pick window [s] 6.0 #Precalcwin# %for HOS/AR, window length [s] for recalculation of CF (relative to 1st pick) -0.2 #aictsmooth# %for HOS/AR, take average of samples for smoothing of AIC-function [s] +0.4 #aictsmooth# %for HOS/AR, take average of samples for smoothing of AIC-function [s] 0.1 #tsmoothP# %for HOS/AR, take average of samples for smoothing CF [s] -0.001 #ausP# %for HOS/AR, artificial uplift of samples (aus) of CF (P) +0.4 #ausP# %for HOS/AR, artificial uplift of samples (aus) of CF (P) 1.3 #nfacP# %for HOS/AR, noise factor for noise level determination (P) #H-components# ARH #algoS# %choose algorithm for S-onset determination (ARH or AR3) @@ -75,7 +75,7 @@ ARH #algoS# %choose algo 4 #Sarorder# %for AR-picker, order of AR process of H-components 5.0 #Srecalcwin# %for AR-picker, window length [s] for recalculation of CF (2nd pick) (H) 4.0 #pickwinS# %for initial AIC pick, length of S-pick window [s] -2.0 0.3 1.5 1.0 #tsnrh# %for ARH/AR3, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s] +2.0 0.2 1.5 1.0 #tsnrh# %for ARH/AR3, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s] 1.0 #aictsmoothS# %for AIC-picker, take average of samples for smoothing of AIC-function [s] 0.7 #tsmoothS# %for AR-picker, take average of samples for smoothing CF [s] (S) 0.9 #ausS# %for HOS/AR, artificial uplift of samples (aus) of CF (S) @@ -85,16 +85,16 @@ ARH #algoS# %choose algo 2.0 #minFMSNR# %miniumum required SNR for first-motion determination 0.2 #fmpickwin# %pick window around P onset for calculating zero crossings #quality assessment# -0.02 0.04 0.08 0.16 #timeerrorsP# %discrete time errors [s] corresponding to picking weights [0 1 2 3] for P -0.04 0.08 0.16 0.32 #timeerrorsS# %discrete time errors [s] corresponding to picking weights [0 1 2 3] for S +0.04 0.08 0.16 0.32 #timeerrorsP# %discrete time errors [s] corresponding to picking weights [0 1 2 3] for P +0.05 0.10 0.20 0.40 #timeerrorsS# %discrete time errors [s] corresponding to picking weights [0 1 2 3] for S 0.8 #minAICPslope# %below this slope [counts/s] the initial P pick is rejected 1.1 #minAICPSNR# %below this SNR the initial P pick is rejected 1.0 #minAICSslope# %below this slope [counts/s] the initial S pick is rejected 1.5 #minAICSSNR# %below this SNR the initial S pick is rejected 1.0 #minsiglength# %length of signal part for which amplitudes must exceed noiselevel [s] -1.0 #noisefactor# %noiselevel*noisefactor=threshold -10.0 #minpercent# %required percentage of amplitudes exceeding threshold -1.5 #zfac# %P-amplitude must exceed at least zfac times RMS-S amplitude -6.0 #mdttolerance# %maximum allowed deviation of P picks from median [s] +1.1 #noisefactor# %noiselevel*noisefactor=threshold +50.0 #minpercent# %required percentage of amplitudes exceeding threshold +1.1 #zfac# %P-amplitude must exceed at least zfac times RMS-S amplitude +5.0 #mdttolerance# %maximum allowed deviation of P picks from median [s] 1.0 #wdttolerance# %maximum allowed deviation from Wadati-diagram -5.0 #jackfactor# %pick is removed if the variance of the subgroup with the pick removed is larger than the mean variance of all subgroups times safety factor +2.0 #jackfactor# %pick is removed if the variance of the subgroup with the pick removed is larger than the mean variance of all subgroups times safety factor From b6c682315de670e971afbeb43c446def533137ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20K=C3=BCperkoch?= Date: Tue, 3 Jul 2018 11:34:32 +0200 Subject: [PATCH 66/70] Allow negative saftey gap for slope determination, use only mean of noise window for SNR determination --- pylot/core/pick/picker.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pylot/core/pick/picker.py b/pylot/core/pick/picker.py index 5328ca90..e999648e 100644 --- a/pylot/core/pick/picker.py +++ b/pylot/core/pick/picker.py @@ -240,12 +240,17 @@ class AICPicker(AutoPicker): return # calculate SNR from CF self.SNR = max(abs(self.Data[0].data[isignal])) / \ - max(abs(self.Data[0].data[inoise] - np.mean(self.Data[0].data[inoise]))) + abs(np.mean(self.Data[0].data[inoise])) # calculate slope from CF after initial pick # get slope window tslope = self.TSNR[3] # slope determination window - islope = np.where((self.Tcf <= min([self.Pick + tslope, self.Tcf[-1]])) \ - & (self.Tcf >= self.Pick)) # TODO: put this in a seperate function like getsignalwin + tsafety = self.TSNR[1] # safety gap, AIC is usually a little bit too late + if tsafety >= 0: + islope = np.where((self.Tcf <= min([self.Pick + tslope + tsafety, self.Tcf[-1]])) \ + & (self.Tcf >= self.Pick)) # TODO: put this in a seperate function like getsignalwin + else: + islope = np.where((self.Tcf <= min([self.Pick + tslope, self.Tcf[-1]])) \ + & (self.Tcf >= self.Pick + tsafety)) # TODO: put this in a seperate function like getsignalwin # find maximum within slope determination window # 'cause slope should be calculated up to first local minimum only! try: From 2379dee142c861543da3aaa8edb192f4066ade3b Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 4 Jul 2018 10:56:18 +0200 Subject: [PATCH 67/70] [hotfix] metadata could not be read (improve this) --- PyLoT.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/PyLoT.py b/PyLoT.py index a11b7374..76238428 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -3128,20 +3128,18 @@ class MainWindow(QMainWindow): settings.setValue("inventoryFile", self.project.inv_path) fninv = settings.value("inventoryFile", None) - if fninv and ask_default: + if (fninv and ask_default) and not new: ans = QMessageBox.question(self, self.tr("Use default metadata..."), self.tr( "Do you want to use the default value for metadata?\n({})".format(fninv)), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) - if ans == QMessageBox.No: - if not set_inv(settings): - return None - elif ans == QMessageBox.Yes: + if ans == QMessageBox.Yes: self.read_metadata_thread(fninv) - if fninv and not ask_default: - self.read_metadata_thread(fninv) + return + set_inv(settings) + def calc_magnitude(self, type='ML'): self.init_metadata() if not self.metadata: From e05909b188b4bcdef83372a06c5296d9f10cff20 Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 4 Jul 2018 16:48:14 +0200 Subject: [PATCH 68/70] [minor] textobjects split into single lines before adding to log for convenience --- PyLoT.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/PyLoT.py b/PyLoT.py index 76238428..f8c99424 100755 --- a/PyLoT.py +++ b/PyLoT.py @@ -2339,7 +2339,9 @@ class MainWindow(QMainWindow): self.nextStation = bool(signal) def addListItem(self, text): - self.listWidget.addItem(text) + textlist = text.split('\n') + for text in textlist: + self.listWidget.addItem(text) self.listWidget.scrollToBottom() def init_fig_dict(self): From b0ad99eced4907675b7e7a240949a68c06b9cdf3 Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 4 Jul 2018 17:25:11 +0200 Subject: [PATCH 69/70] [minor] improved text output if wf data cannot be read --- pylot/core/io/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylot/core/io/data.py b/pylot/core/io/data.py index e84badea..5e6db468 100644 --- a/pylot/core/io/data.py +++ b/pylot/core/io/data.py @@ -445,7 +445,7 @@ class Data(object): except SacIOError as se: warnmsg += '{0}\n{1}\n'.format(fname, se) if warnmsg: - warnmsg = 'WARNING: unable to read\n' + warnmsg + warnmsg = 'WARNING in appendWFData: unable to read waveform data\n' + warnmsg print(warnmsg) def getWFData(self): From df0f059ff396f2855287cfd41c29dc02d7729587 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 5 Jul 2018 14:37:32 +0200 Subject: [PATCH 70/70] [bugfix] parameters tpred2z and tdet2z were unused --- pylot/core/pick/autopick.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pylot/core/pick/autopick.py b/pylot/core/pick/autopick.py index baa450e1..76985aed 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -179,6 +179,8 @@ def autopickstation(wfstream, pickparam, verbose=False, nfacP = pickparam.get('nfacP') tpred1z = pickparam.get('tpred1z') tdet1z = pickparam.get('tdet1z') + tpred2z = pickparam.get('tpred2z') + tdet2z = pickparam.get('tdet2z') Parorder = pickparam.get('Parorder') addnoise = pickparam.get('addnoise') Precalcwin = pickparam.get('Precalcwin') @@ -489,7 +491,7 @@ def autopickstation(wfstream, pickparam, verbose=False, elif algoP == 'ARZ': # calculate ARZ-CF using subclass ARZcf of class # CharcteristicFunction - cf2 = ARZcf(z_copy, cuttimes2, tpred1z, Parorder, tdet1z, + cf2 = ARZcf(z_copy, cuttimes2, tpred2z, Parorder, tdet2z, addnoise) # instance of ARZcf ############################################################## # get refined onset time from CF2 using class Picker