From f21fc7bb37d3235fc695b18e202ba0622850e240 Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 30 Aug 2017 10:51:20 +0200 Subject: [PATCH 1/8] [fixes #244] parameters passed to pickDlg explicit --- QtPyLoT.py | 5 ++++- pylot/core/util/widgets.py | 24 +++++++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 624e8983..cb55c317 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -1799,11 +1799,14 @@ class MainWindow(QMainWindow): return self.update_status('picking on station {0}'.format(station)) data = self.get_data().getWFData() + event = self.get_current_event() 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')) + autopicks=self.getPicksOnStation(station, 'auto'), + metadata=self.metadata, event=event, + filteroptions=self.filteroptions) pickDlg.nextStation.setChecked(nextStation) if pickDlg.exec_(): if pickDlg._dirty: diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index e79f4cce..bb1adf23 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -822,7 +822,8 @@ class PickDlg(QDialog): update_picks = QtCore.Signal(dict) def __init__(self, parent=None, data=None, station=None, network=None, picks=None, - autopicks=None, rotate=False, parameter=None, embedded=False, model='iasp91'): + autopicks=None, rotate=False, parameter=None, embedded=False, metadata=None, + event=None, filteroptions=None, model='iasp91'): super(PickDlg, self).__init__(parent) # initialize attributes @@ -831,6 +832,8 @@ class PickDlg(QDialog): self.station = station self.network = network self.rotate = rotate + self.metadata = metadata + self.pylot_event = event self.components = 'ZNE' self.currentPhase = None self.phaseText = [] @@ -853,8 +856,8 @@ class PickDlg(QDialog): else: self.autopicks = {} self._init_autopicks = {} - if hasattr(self.parent(), 'filteroptions'): - self.filteroptions = self.parent().filteroptions + if filteroptions: + self.filteroptions = filteroptions else: self.filteroptions = FILTERDEFAULTS self.pick_block = False @@ -915,7 +918,7 @@ class PickDlg(QDialog): # init expected picks using obspy Taup try: - if self.parent().metadata: + if self.metadata: self.model = TauPyModel(model) self.get_arrivals() self.drawArrivals() @@ -1080,13 +1083,16 @@ class PickDlg(QDialog): self._dirty = bool def get_arrivals(self, plot=False): + if not self.metadata: + print('get_arrivals: No metadata given. Return!') + return func = {True: self.model.get_ray_paths_geo, False: self.model.get_travel_times_geo} phases = self.prepare_phases() station_id = self.data.traces[0].get_id() - parser = self.parent().metadata[1] + parser = self.metadata[1] station_coords = parser.get_coordinates(station_id) - origins = self.parent().get_current_event().origins + origins = self.pylot_event.origins if origins: source_origin = origins[0] else: @@ -1117,7 +1123,7 @@ class PickDlg(QDialog): else: ylims = self.getPlotWidget().getYLims() stime = self.getStartTime() - source_origin = self.parent().get_current_event().origins[0] + source_origin = self.pylot_event.origins[0] source_time = source_origin.time for arrival in self.arrivals: arrival_time_abs = source_time + arrival.time @@ -2335,10 +2341,14 @@ class TuneAutopicker(QWidget): return station = self.get_current_station() data = self.data.getWFData() + metadata = self.parent.metadata + event = self.get_current_event() + filteroptions = self.parent.filteroptions pickDlg = PickDlg(self, data=data.select(station=station), station=station, parameter=self.parameter, picks=self.get_current_event_picks(station), autopicks=self.get_current_event_autopicks(station), + metadata=metadata, event=event, filteroptions=filteroptions, embedded=True) pickDlg.update_picks.connect(self.picks_from_pickdlg) pickDlg.update_picks.connect(self.fill_eventbox) From aea58b3c11c171daef660be5989aa0a7acadc0ca Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 30 Aug 2017 14:44:39 +0200 Subject: [PATCH 2/8] [update] made autopickwidget concept more flexible --- pylot/core/util/widgets.py | 73 +++++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index bb1adf23..addf4121 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -2031,20 +2031,77 @@ class CanvasWidget(QWidget): self.main_layout.addWidget(canvas) -class AutoPickWidget(QWidget): +class MultiEventWidget(QWidget): start = Signal() ''' + + ''' + def __init__(self, pickoptions=None, parent=None, windowflag=1): + QtGui.QWidget.__init__(self, parent, windowflag) + + self.pickoptions = pickoptions + # self.pickoptions =[('current event', None), + # ('tune events', None), + # ('test events', None), + # ('all (picked)', None), + # ('all events', None)] + + self.setupUi() + # set initial size + self.resize(1280, 720) + + def setupUi(self): + # init main layout + self.main_layout = QtGui.QVBoxLayout() + self.setLayout(self.main_layout) + # init main splitter + self.main_splitter = QtGui.QSplitter() + self.main_splitter.setChildrenCollapsible(False) + + self.init_checkboxes() + + self.eventbox = QtGui.QComboBox() + self.button_clear = QtGui.QPushButton('Clear') + + self.main_layout.insertWidget(1, self.main_splitter) + + self.main_layout.setStretch(0, 0) + self.main_layout.setStretch(1, 1) + self.main_splitter.setStretchFactor(0, 1) + self.main_splitter.setStretchFactor(1, 2) + + def init_checkboxes(self): + self.rb_layout = QtGui.QHBoxLayout() + + self.rb_dict = {} + + self.start_button = QtGui.QPushButton('Start') + + for index, (key, func) in enumerate(self.pickoptions): + rb = QtGui.QRadioButton(key) + if index == 0: + rb.setChecked(True) + self.rb_dict[key] = rb + self.rb_layout.insertWidget(index, rb) + self.rb_layout.setStretch(index, 0) + + self.rb_layout.addWidget(self.start_button) + + self.rb_layout.addWidget(QtGui.QWidget()) + self.rb_layout.setStretch(len(self.pickoptions)+1, 1) + + self.main_layout.insertLayout(0, self.rb_layout) + + +class AutoPickWidget(MultiEventWidget): + ''' ''' def __init__(self, parent, pickoptions): - QtGui.QWidget.__init__(self, parent, 1) - self.pickoptions = pickoptions - self.setupUi() + MultiEventWidget.__init__(self, pickoptions, parent, 1) self.connect_buttons() self.reinitEvents2plot() self.setWindowTitle('Autopick events interactively') - # set initial size - self.resize(1280, 720) def setupUi(self): # init main layout @@ -2069,7 +2126,7 @@ class AutoPickWidget(QWidget): self.main_splitter.setStretchFactor(1, 2) def connect_buttons(self): - self.start_button.clicked.connect(self.start_picker) + self.start_button.clicked.connect(self.run) self.button_clear.clicked.connect(self.reinitEvents2plot) def init_checkboxes(self): @@ -2169,7 +2226,7 @@ class AutoPickWidget(QWidget): tooltip = 'No events for this selection' self.rb_dict[key].setToolTip(tooltip) - def start_picker(self): + def run(self): self.refresh_plot_tabs() self.start.emit() From ca5167cb04f3a1c5ebffd26c8fc0ee6799707c7b Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 30 Aug 2017 14:45:20 +0200 Subject: [PATCH 3/8] [bugfix] check type(picks) in dict/Attribdict --- pylot/core/util/utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pylot/core/util/utils.py b/pylot/core/util/utils.py index 46a66eda..28dad3bb 100644 --- a/pylot/core/util/utils.py +++ b/pylot/core/util/utils.py @@ -9,6 +9,7 @@ import subprocess import numpy as np from obspy import UTCDateTime, read +from obspy.core import AttribDict from obspy.signal.rotate import rotate2zne from obspy.io.xseed.utils import SEEDParserException @@ -95,6 +96,8 @@ def excludeQualityClasses(picks, qClasses, timeerrorsP, timeerrorsS): for station, phases in picks.items(): for phase, pick in phases.items(): + if not type(pick) in [AttribDict, dict]: + continue pickerror = phaseError[identifyPhaseID(phase)] quality = getQualityFromUncertainty(pick['spe'], pickerror) if not quality in qClasses: From 9e1af65af7876960d7549a11475fc9bfd01e8360 Mon Sep 17 00:00:00 2001 From: Darius Arnold Date: Thu, 31 Aug 2017 00:07:38 +0200 Subject: [PATCH 4/8] [bugfix] AIC-CF was smoothed using wrong parameter aictsmooth was unused in pylot, instead the tsmoothP parameter was used two times. aictsmooth should smooth the AIC-CF during the determination of the preliminary onset. tsmoothP is used to smooth the HOS-CF during pragmatic picking. --- 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 5b8c4d96..6932f620 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -131,6 +131,7 @@ def autopickstation(wfstream, pickparam, verbose=False, bpz1 = pickparam.get('bpz1') bpz2 = pickparam.get('bpz2') pickwinP = pickparam.get('pickwinP') + aictsmoothP = pickparam.get('aictsmooth') tsmoothP = pickparam.get('tsmoothP') ausP = pickparam.get('ausP') nfacP = pickparam.get('nfacP') @@ -323,7 +324,7 @@ def autopickstation(wfstream, pickparam, verbose=False, fig = fig_dict[key] else: fig = None - aicpick = AICPicker(aiccf, tsnrz, pickwinP, iplot, None, tsmoothP, fig=fig) + aicpick = AICPicker(aiccf, tsnrz, pickwinP, iplot, None, aictsmoothP, fig=fig) # add pstart and pstop to aic plot if fig: for ax in fig.axes: From ba001fb53d504b62af31c59b838eb7a079e86165 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 31 Aug 2017 09:49:09 +0200 Subject: [PATCH 5/8] [change] restructured comparison widget --- QtPyLoT.py | 15 ++-- pylot/core/util/widgets.py | 153 +++++++++++++++++++++++++------------ 2 files changed, 112 insertions(+), 56 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index cb55c317..fec61ca5 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -1231,12 +1231,15 @@ class MainWindow(QMainWindow): def comparePicks(self): if self.check4Comparison(): - autopicks = excludeQualityClasses(self.getPicks('auto'), [4], - self._inputs['timeerrorsP'], self._inputs['timeerrorsS']) - manupicks = excludeQualityClasses(self.getPicks('manual'), [4], - self._inputs['timeerrorsP'], self._inputs['timeerrorsS']) - co = Comparison(auto=autopicks, manu=manupicks) - compare_dlg = ComparisonWidget(co, self) + comparisons = {} + for event in self.project.eventlist: + autopicks = excludeQualityClasses(event.getAutopicks(), [4], + self._inputs['timeerrorsP'], self._inputs['timeerrorsS']) + manupicks = excludeQualityClasses(event.getPicks(), [4], + self._inputs['timeerrorsP'], self._inputs['timeerrorsS']) + co = Comparison(auto=autopicks, manu=manupicks) + comparisons[event.pylot_id] = co + compare_dlg = ComparisonWidget(comparisons[self.get_current_event_name()], self) compare_dlg.show() def getPlotWidget(self): diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index addf4121..e157c8d5 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -2092,6 +2092,13 @@ class MultiEventWidget(QWidget): self.main_layout.insertLayout(0, self.rb_layout) + def enable(self, bool): + for rb in self.rb_dict.values(): + rb.setEnabled(bool) + self.start_button.setEnabled(bool) + self.eventbox.setEnabled(bool) + self.button_clear.setEnabled(bool) + class AutoPickWidget(MultiEventWidget): ''' @@ -2100,57 +2107,15 @@ class AutoPickWidget(MultiEventWidget): def __init__(self, parent, pickoptions): MultiEventWidget.__init__(self, pickoptions, parent, 1) self.connect_buttons() + self.init_plot_layout() + self.init_log_layout() self.reinitEvents2plot() self.setWindowTitle('Autopick events interactively') - def setupUi(self): - # init main layout - self.main_layout = QtGui.QVBoxLayout() - self.setLayout(self.main_layout) - # init main splitter - self.main_splitter = QtGui.QSplitter() - self.main_splitter.setChildrenCollapsible(False) - - self.init_checkboxes() - self.init_log_layout() - self.init_plot_layout() - - self.eventbox = QtGui.QComboBox() - self.button_clear = QtGui.QPushButton('Clear') - - self.main_layout.insertWidget(1, self.main_splitter) - - self.main_layout.setStretch(0, 0) - self.main_layout.setStretch(1, 1) - self.main_splitter.setStretchFactor(0, 1) - self.main_splitter.setStretchFactor(1, 2) - def connect_buttons(self): self.start_button.clicked.connect(self.run) self.button_clear.clicked.connect(self.reinitEvents2plot) - def init_checkboxes(self): - self.rb_layout = QtGui.QHBoxLayout() - - self.rb_dict = {} - - self.start_button = QtGui.QPushButton('Start') - - for index, (key, func) in enumerate(self.pickoptions): - rb = QtGui.QRadioButton(key) - if index == 0: - rb.setChecked(True) - self.rb_dict[key] = rb - self.rb_layout.insertWidget(index, rb) - self.rb_layout.setStretch(index, 0) - - self.rb_layout.addWidget(self.start_button) - - self.rb_layout.addWidget(QtGui.QWidget()) - self.rb_layout.setStretch(len(self.pickoptions)+1, 1) - - self.main_layout.insertLayout(0, self.rb_layout) - def init_plot_layout(self): # init tab widget self.tab_plots = QtGui.QTabWidget() @@ -2230,12 +2195,100 @@ class AutoPickWidget(MultiEventWidget): self.refresh_plot_tabs() self.start.emit() - def enable(self, bool): - for rb in self.rb_dict.values(): - rb.setEnabled(bool) - self.start_button.setEnabled(bool) - self.eventbox.setEnabled(bool) - self.button_clear.setEnabled(bool) +class CompareEventsWidget(MultiEventWidget): + ''' + ''' + + def __init__(self, parent, pickoptions): + MultiEventWidget.__init__(self, pickoptions, parent, 1) + self.connect_buttons() + self.init_plot_layout() + self.init_log_layout() + self.reinitEvents2plot() + self.setWindowTitle('Autopick events interactively') + + def connect_buttons(self): + self.start_button.clicked.connect(self.run) + self.button_clear.clicked.connect(self.reinitEvents2plot) + + def init_plot_layout(self): + # init tab widget + self.tab_plots = QtGui.QTabWidget() + self.gb_plots = QtGui.QGroupBox('Plots') + self.gb_plots.setMinimumSize(100, 100) + self.main_splitter.insertWidget(1, self.gb_plots) + self.plot_layout = QtGui.QVBoxLayout() + self.plot_layout.insertWidget(1, self.tab_plots) + self.gb_plots.setLayout(self.plot_layout) + + def init_log_layout(self): + self.gb_log = QtGui.QGroupBox('Log') + self.gb_log.setMinimumSize(100, 100) + self.main_splitter.insertWidget(0, self.gb_log) + + def insert_log_widget(self, widget): + vl = QtGui.QVBoxLayout() + vl.addWidget(widget) + self.gb_log.setLayout(vl) + + def add_plot_widget(self, widget, key, eventID): + eventID += ' [picked: {}]'.format(time.strftime('%X %x %z')) + if not eventID in self.events2plot.keys(): + self.events2plot[eventID] = {} + self.events2plot[eventID][key] = widget + + def generate_combobox(self): + self.eventbox.clear() + for eventID, widgets in self.events2plot.items(): + self.eventbox.addItem(str(eventID), widgets) + self.eventbox.currentIndexChanged.connect(self.draw_plots) + self.draw_plots() + + def draw_plots(self, index=0): + self.refresh_plot_tabs() + widgets = self.eventbox.itemData(index) + if not widgets: + return + for key, widget in widgets.items(): + self.tab_plots.addTab(widget, str(key)) + + def update_plots(self): + self.refresh_plot_tabs() + if len(self.events2plot) > 0: + self.eventbox_layout = QtGui.QHBoxLayout() + self.generate_combobox() + self.eventbox_layout.addWidget(self.eventbox) + self.eventbox_layout.addWidget(self.button_clear) + self.eventbox_layout.setStretch(0, 1) + self.plot_layout.insertLayout(0, self.eventbox_layout) + + def reinitEvents2plot(self): + self.events2plot = {} + self.eventbox.clear() + self.refresh_plot_tabs() + + def refresh_plot_tabs(self): + self.tab_plots.clear() + + def refresh_tooltips(self): + for key, func in self.pickoptions: + eventlist = func() + if not type(eventlist) == list: + eventlist = [eventlist] + tooltip='' + for index, event in enumerate(eventlist): + if not event: + continue + tooltip += '{}'.format(event.pylot_id) + if not index + 1 == len(eventlist): + tooltip += '\n' + if not tooltip: + tooltip = 'No events for this selection' + self.rb_dict[key].setToolTip(tooltip) + + def run(self): + self.refresh_plot_tabs() + self.start.emit() class TuneAutopicker(QWidget): From eaa7a993af48a56ea64a824a4fcad9d80f679887 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 31 Aug 2017 11:16:13 +0200 Subject: [PATCH 6/8] [add] compare widget for multiple events added --- QtPyLoT.py | 105 ++++++++++++++++---------- pylot/core/util/widgets.py | 149 ++++++++++++++----------------------- 2 files changed, 122 insertions(+), 132 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index fec61ca5..632d746d 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -79,7 +79,8 @@ from pylot.core.util.event import Event from pylot.core.io.location import create_creation_info, create_event from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \ WaveformWidget, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \ - getDataType, ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget + getDataType, ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \ + CompareEventsWidget from pylot.core.util.map_projection import map_projection from pylot.core.util.structure import DATASTRUCTURE from pylot.core.util.thread import Thread, Worker @@ -201,6 +202,14 @@ class MainWindow(QMainWindow): s_filter['order'])} self.loc = False + # init event selection options for compare/autopick + self.pickoptions =[('current event', self.get_current_event), + ('tune events', self.get_ref_events), + ('test events', self.get_test_events), + ('all (picked) events', self.get_manu_picked_events), + ('all events', self.get_all_events)] + + def setupUi(self): try: self.startTime = min( @@ -1230,17 +1239,27 @@ class MainWindow(QMainWindow): return None def comparePicks(self): - if self.check4Comparison(): - comparisons = {} - for event in self.project.eventlist: - autopicks = excludeQualityClasses(event.getAutopicks(), [4], - self._inputs['timeerrorsP'], self._inputs['timeerrorsS']) - manupicks = excludeQualityClasses(event.getPicks(), [4], - self._inputs['timeerrorsP'], self._inputs['timeerrorsS']) - co = Comparison(auto=autopicks, manu=manupicks) - comparisons[event.pylot_id] = co - compare_dlg = ComparisonWidget(comparisons[self.get_current_event_name()], self) - compare_dlg.show() + comparisons = {} + eventdict = {} + for event in self.project.eventlist: + if not self.comparable[event.pylot_id]: + continue + autopicks = excludeQualityClasses(event.getAutopicks(), [4], + self._inputs['timeerrorsP'], self._inputs['timeerrorsS']) + manupicks = excludeQualityClasses(event.getPicks(), [4], + self._inputs['timeerrorsP'], self._inputs['timeerrorsS']) + co = Comparison(auto=autopicks, manu=manupicks) + comparisons[event.pylot_id] = co + eventdict[event.pylot_id] = event + if len(eventdict) < 1: + return + pickoptions = self.pickoptions.copy() + pickoptions.pop(-1) + pickoptions.pop(0) + compare_multi = CompareEventsWidget(self, pickoptions, eventdict, comparisons) + compare_multi.show() + #compare_dlg = ComparisonWidget(comparisons[self.get_current_event_name()], self) + #compare_dlg.show() def getPlotWidget(self): return self.dataPlot @@ -1491,6 +1510,7 @@ class MainWindow(QMainWindow): self.dataPlot.plotWidget.showAxis('bottom') def finishWaveformDataPlot(self): + self.comparable = self.checkEvents4comparison() if self.pg: self.finish_pg_plot() else: @@ -1524,15 +1544,31 @@ class MainWindow(QMainWindow): self.locateEvent.setEnabled(True) if event.pylot_autopicks: self.drawPicks(picktype='auto') - if event.pylot_picks and event.pylot_autopicks: - for key in event.pylot_picks: - for akey in event.pylot_autopicks: - if (akey == key) and (event.pylot_autopicks[akey]['P']['spe'] is not None \ - or event.pylot_autopicks[akey]['S']['spe'] is not None): - self.compare_action.setEnabled(True) - break + if True in self.comparable.values(): + self.compare_action.setEnabled(True) self.draw() + def checkEvent4comparison(self, event): + if event.pylot_picks and event.pylot_autopicks: + for station in event.pylot_picks: + if station in event.pylot_autopicks: + autopick_p = event.pylot_autopicks[station]['P']['spe'] + manupick_p = event.pylot_picks[station]['P']['spe'] + autopick_s = event.pylot_autopicks[station]['S']['spe'] + manupick_s = event.pylot_picks[station]['S']['spe'] + if autopick_p and manupick_p: + return True + elif autopick_s and manupick_s: + return True + return False + + def checkEvents4comparison(self): + # init dict to keep track whether event can be compared + comparable = {} + for event in self.project.eventlist: + comparable[event.pylot_id] = self.checkEvent4comparison(event) + return comparable + def clearWaveformDataPlot(self): self.disconnectWFplotEvents() if self.pg: @@ -1919,12 +1955,6 @@ class MainWindow(QMainWindow): "No autoPyLoT output declared!") return - self.pickoptions =[('current event', self.get_current_event), - ('tune events', self.get_ref_events), - ('test events', self.get_test_events), - ('all (picked) events', self.get_manu_picked_events), - ('all events', self.get_all_events)] - self.listWidget = QListWidget() self.setDirty(True) self.apw = AutoPickWidget(self, self.pickoptions) @@ -2096,7 +2126,6 @@ class MainWindow(QMainWindow): #event.picks.update(picks) MP MP idea elif type == 'auto': event.addAutopicks(picksdict['auto']) - self.check4Comparison() def drawPicks(self, station=None, picktype=None): # if picktype not specified, draw both @@ -2636,18 +2665,18 @@ class MainWindow(QMainWindow): def check4Loc(self): return self.picksNum() >= 4 - def check4Comparison(self): - mpicks = self.getPicks() - apicks = self.getPicks('auto') - for station, phases in mpicks.items(): - try: - aphases = apicks[station] - for phase in phases.keys(): - if phase in aphases.keys(): - return True - except KeyError: - continue - return False + # def check4Comparison(self): + # mpicks = self.getPicks() + # apicks = self.getPicks('auto') + # for station, phases in mpicks.items(): + # try: + # aphases = apicks[station] + # for phase in phases.keys(): + # if phase in aphases.keys(): + # return True + # except KeyError: + # continue + # return False def picksNum(self, type='manual'): num = 0 diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index e157c8d5..ad606721 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -121,7 +121,7 @@ def createAction(parent, text, slot=None, shortcut=None, icon=None, class ComparisonWidget(QWidget): - def __init__(self, c, parent=None): + def __init__(self, c, parent=None, windowflag=1): self._data = c self._stats = c.stations self._canvas = PlotWidget(self) @@ -130,7 +130,7 @@ class ComparisonWidget(QWidget): histCheckBox=None) self._phases = 'PS' self._plotprops = dict(station=list(self.stations)[0], phase=list(self.phases)[0]) - super(ComparisonWidget, self).__init__(parent, 1) + super(ComparisonWidget, self).__init__(parent, windowflag) self.setupUI() self.resize(1280, 720) self.plotcomparison() @@ -2092,6 +2092,22 @@ class MultiEventWidget(QWidget): self.main_layout.insertLayout(0, self.rb_layout) + def refresh_tooltips(self): + for key, func in self.pickoptions: + eventlist = func() + if not type(eventlist) == list: + eventlist = [eventlist] + tooltip='' + for index, event in enumerate(eventlist): + if not event: + continue + tooltip += '{}'.format(event.pylot_id) + if not index + 1 == len(eventlist): + tooltip += '\n' + if not tooltip: + tooltip = 'No events for this selection' + self.rb_dict[key].setToolTip(tooltip) + def enable(self, bool): for rb in self.rb_dict.values(): rb.setEnabled(bool) @@ -2111,6 +2127,7 @@ class AutoPickWidget(MultiEventWidget): self.init_log_layout() self.reinitEvents2plot() self.setWindowTitle('Autopick events interactively') + self.set_main_stretch() def connect_buttons(self): self.start_button.clicked.connect(self.run) @@ -2167,6 +2184,10 @@ class AutoPickWidget(MultiEventWidget): self.eventbox_layout.setStretch(0, 1) self.plot_layout.insertLayout(0, self.eventbox_layout) + def set_main_stretch(self): + self.main_layout.setStretch(0, 0) + self.main_layout.setStretch(1, 1) + def reinitEvents2plot(self): self.events2plot = {} self.eventbox.clear() @@ -2175,119 +2196,59 @@ class AutoPickWidget(MultiEventWidget): def refresh_plot_tabs(self): self.tab_plots.clear() - def refresh_tooltips(self): - for key, func in self.pickoptions: - eventlist = func() - if not type(eventlist) == list: - eventlist = [eventlist] - tooltip='' - for index, event in enumerate(eventlist): - if not event: - continue - tooltip += '{}'.format(event.pylot_id) - if not index + 1 == len(eventlist): - tooltip += '\n' - if not tooltip: - tooltip = 'No events for this selection' - self.rb_dict[key].setToolTip(tooltip) - def run(self): self.refresh_plot_tabs() self.start.emit() + class CompareEventsWidget(MultiEventWidget): ''' ''' - def __init__(self, parent, pickoptions): + def __init__(self, parent, pickoptions, eventdict, comparisons): MultiEventWidget.__init__(self, pickoptions, parent, 1) + self.eventdict = eventdict + self.comparisons = comparisons + self.init_eventbox() self.connect_buttons() - self.init_plot_layout() - self.init_log_layout() - self.reinitEvents2plot() - self.setWindowTitle('Autopick events interactively') + self.setWindowTitle('Compare events') + self.set_main_stretch() def connect_buttons(self): self.start_button.clicked.connect(self.run) - self.button_clear.clicked.connect(self.reinitEvents2plot) - def init_plot_layout(self): - # init tab widget - self.tab_plots = QtGui.QTabWidget() - self.gb_plots = QtGui.QGroupBox('Plots') - self.gb_plots.setMinimumSize(100, 100) - self.main_splitter.insertWidget(1, self.gb_plots) - self.plot_layout = QtGui.QVBoxLayout() - self.plot_layout.insertWidget(1, self.tab_plots) - self.gb_plots.setLayout(self.plot_layout) + def init_eventbox(self): + self.eventbox_layout = QtGui.QHBoxLayout() + self.eventbox_layout.addWidget(self.eventbox) + self.main_layout.insertLayout(1, self.eventbox_layout) + self.fill_eventbox() + self.eventbox.currentIndexChanged.connect(self.update_comparison) - def init_log_layout(self): - self.gb_log = QtGui.QGroupBox('Log') - self.gb_log.setMinimumSize(100, 100) - self.main_splitter.insertWidget(0, self.gb_log) + def fill_eventbox(self): + event_ids = list(self.eventdict.keys()) + for event_id in sorted(event_ids): + self.eventbox.addItem(str(event_id)) + self.update_comparison() - def insert_log_widget(self, widget): - vl = QtGui.QVBoxLayout() - vl.addWidget(widget) - self.gb_log.setLayout(vl) - - def add_plot_widget(self, widget, key, eventID): - eventID += ' [picked: {}]'.format(time.strftime('%X %x %z')) - if not eventID in self.events2plot.keys(): - self.events2plot[eventID] = {} - self.events2plot[eventID][key] = widget - - def generate_combobox(self): + def update_eventbox(self): self.eventbox.clear() - for eventID, widgets in self.events2plot.items(): - self.eventbox.addItem(str(eventID), widgets) - self.eventbox.currentIndexChanged.connect(self.draw_plots) - self.draw_plots() + self.fill_eventbox() - def draw_plots(self, index=0): - self.refresh_plot_tabs() - widgets = self.eventbox.itemData(index) - if not widgets: - return - for key, widget in widgets.items(): - self.tab_plots.addTab(widget, str(key)) + def update_comparison(self, index=0): + if hasattr(self, 'compare_widget'): + self.compare_widget.setParent(None) + self.compare_widget = ComparisonWidget( + self.comparisons[self.eventbox.currentText()], self, 0) + self.main_layout.insertWidget(2, self.compare_widget) + self.set_main_stretch() - def update_plots(self): - self.refresh_plot_tabs() - if len(self.events2plot) > 0: - self.eventbox_layout = QtGui.QHBoxLayout() - self.generate_combobox() - self.eventbox_layout.addWidget(self.eventbox) - self.eventbox_layout.addWidget(self.button_clear) - self.eventbox_layout.setStretch(0, 1) - self.plot_layout.insertLayout(0, self.eventbox_layout) - - def reinitEvents2plot(self): - self.events2plot = {} - self.eventbox.clear() - self.refresh_plot_tabs() - - def refresh_plot_tabs(self): - self.tab_plots.clear() - - def refresh_tooltips(self): - for key, func in self.pickoptions: - eventlist = func() - if not type(eventlist) == list: - eventlist = [eventlist] - tooltip='' - for index, event in enumerate(eventlist): - if not event: - continue - tooltip += '{}'.format(event.pylot_id) - if not index + 1 == len(eventlist): - tooltip += '\n' - if not tooltip: - tooltip = 'No events for this selection' - self.rb_dict[key].setToolTip(tooltip) + def set_main_stretch(self): + self.main_layout.setStretch(0, 0) + self.main_layout.setStretch(1, 0) + self.main_layout.setStretch(2, 1) + self.main_layout.setStretch(3, 0) def run(self): - self.refresh_plot_tabs() self.start.emit() From 79cbaf3397a5fe09ddf670ff885e19a02359c624 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 31 Aug 2017 14:31:33 +0200 Subject: [PATCH 7/8] [update] working version to compare several events --- QtPyLoT.py | 54 +++++++++++++++++++++++++++----------- pylot/core/pick/compare.py | 44 ++++++++++++++++++++++++------- pylot/core/util/widgets.py | 54 +++++++++++++++++++++++++------------- 3 files changed, 110 insertions(+), 42 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 632d746d..720a651a 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -202,14 +202,6 @@ class MainWindow(QMainWindow): s_filter['order'])} self.loc = False - # init event selection options for compare/autopick - self.pickoptions =[('current event', self.get_current_event), - ('tune events', self.get_ref_events), - ('test events', self.get_test_events), - ('all (picked) events', self.get_manu_picked_events), - ('all events', self.get_all_events)] - - def setupUi(self): try: self.startTime = min( @@ -1038,6 +1030,8 @@ class MainWindow(QMainWindow): # if pick widget is open, refresh tooltips as well if hasattr(self, 'apw'): self.apw.refresh_tooltips() + if hasattr(self, 'cmpw'): + self.cmpw.refresh_tooltips() if not eventBox: eventBox = self.eventBox @@ -1253,13 +1247,36 @@ class MainWindow(QMainWindow): eventdict[event.pylot_id] = event if len(eventdict) < 1: return - pickoptions = self.pickoptions.copy() - pickoptions.pop(-1) - pickoptions.pop(0) - compare_multi = CompareEventsWidget(self, pickoptions, eventdict, comparisons) - compare_multi.show() - #compare_dlg = ComparisonWidget(comparisons[self.get_current_event_name()], self) - #compare_dlg.show() + + # init event selection options for autopick + self.compareoptions =[('tune events', self.get_ref_events), + ('test events', self.get_test_events), + ('all (picked) events', self.get_manu_picked_events)] + + self.cmpw = CompareEventsWidget(self, self.compareoptions, eventdict, comparisons) + self.cmpw.start.connect(self.compareMulti) + self.cmpw.refresh_tooltips() + self.cmpw.show() + + def compareMulti(self): + for key, func in self.compareoptions: + if self.cmpw.rb_dict[key].isChecked(): + # if radio button is checked break for loop and use func + break + eventlist = func() + # use only events comparable + eventlist_overlap = [event for event in eventlist if self.comparable[event.pylot_id]] + compare_widget = self.buildMultiCompareWidget(eventlist_overlap) + compare_widget.show() + + + def buildMultiCompareWidget(self, eventlist): + global_comparison = Comparison(eventlist=eventlist) + compare_widget = ComparisonWidget(global_comparison, self) + compare_widget.setWindowTitle('Histograms for all selected events') + compare_widget.hideToolbar() + compare_widget.setHistboxChecked(True) + return compare_widget def getPlotWidget(self): return self.dataPlot @@ -1955,6 +1972,13 @@ class MainWindow(QMainWindow): "No autoPyLoT output declared!") return + # init event selection options for autopick + self.pickoptions =[('current event', self.get_current_event), + ('tune events', self.get_ref_events), + ('test events', self.get_test_events), + ('all (picked) events', self.get_manu_picked_events), + ('all events', self.get_all_events)] + self.listWidget = QListWidget() self.setDirty(True) self.apw = AutoPickWidget(self, self.pickoptions) diff --git a/pylot/core/pick/compare.py b/pylot/core/pick/compare.py index 24caa92c..ee908a13 100644 --- a/pylot/core/pick/compare.py +++ b/pylot/core/pick/compare.py @@ -27,16 +27,8 @@ class Comparison(object): """ def __init__(self, **kwargs): - names = list() self._pdfs = dict() - for name, fn in kwargs.items(): - if isinstance(fn, PDFDictionary): - self._pdfs[name] = fn - elif isinstance(fn, dict) or isinstance(fn, AttribDict): - self._pdfs[name] = PDFDictionary(fn) - else: - self._pdfs[name] = PDFDictionary.from_quakeml(fn) - names.append(name) + names = self.iter_kwargs(kwargs) if len(names) > 2: raise ValueError('Comparison is only defined for two ' 'arguments!') @@ -48,6 +40,40 @@ class Comparison(object): return False return True + def iter_kwargs(self, kwargs): + names = list() + for name, fn in kwargs.items(): + if name == 'eventlist': + names = self.init_by_eventlist(fn) + break + if isinstance(fn, PDFDictionary): + self._pdfs[name] = fn + elif isinstance(fn, dict) or isinstance(fn, AttribDict): + self._pdfs[name] = PDFDictionary(fn) + else: + self._pdfs[name] = PDFDictionary.from_quakeml(fn) + names.append(name) + return names + + def init_by_eventlist(self, eventlist): + # create one dictionary containing all picks for all events (therefore modify station key) + global_picksdict = {} + for event in eventlist: + automanu = {'manu': event.pylot_picks, + 'auto': event.pylot_autopicks} + for method, picksdict in automanu.items(): + if not method in global_picksdict.keys(): + global_picksdict[method] = {} + for station, picks in picksdict.items(): + new_picksdict = global_picksdict[method] + # new id combining event and station in one dictionary for all events + id = '{}_{}'.format(event.pylot_id, station) + new_picksdict[id] = picks + for method, picksdict in global_picksdict.items(): + self._pdfs[method] = PDFDictionary(picksdict) + names = list(global_picksdict.keys()) + return names + def get(self, name): return self._pdfs[name] diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index ad606721..6e840fc8 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -154,19 +154,19 @@ class ComparisonWidget(QWidget): _phases_combobox.currentIndexChanged.connect(self.prepareplot) self.widgets = _phases_combobox - _hist_checkbox = QCheckBox('Show histograms', self) - _hist_checkbox.setObjectName('histCheckBox') - _hist_checkbox.stateChanged.connect(self.plothist) - self.widgets = _hist_checkbox + self._hist_checkbox = QCheckBox('Show histograms', self) + self._hist_checkbox.setObjectName('histCheckBox') + self._hist_checkbox.stateChanged.connect(self.plothist) + self.widgets = self._hist_checkbox - _toolbar = QToolBar(self) - _toolbar.addWidget(_stats_combobox) - _toolbar.addWidget(_phases_combobox) - _toolbar.addWidget(_hist_checkbox) + self._toolbar = QToolBar(self) + self._toolbar.addWidget(_stats_combobox) + self._toolbar.addWidget(_phases_combobox) + self._toolbar.addWidget(self._hist_checkbox) _innerlayout.addWidget(self.canvas) - _outerlayout.addWidget(_toolbar) + _outerlayout.addWidget(self._toolbar) _outerlayout.addLayout(_innerlayout) # finally layout the entire widget @@ -232,6 +232,15 @@ class ComparisonWidget(QWidget): if name in self.widgets.keys(): self._widgets[name] = widget + def showToolbar(self): + self._toolbar.show() + + def hideToolbar(self): + self._toolbar.hide() + + def setHistboxChecked(self, bool): + self._hist_checkbox.setChecked(bool) + def clf(self): self.canvas.figure.clf() @@ -2036,10 +2045,10 @@ class MultiEventWidget(QWidget): ''' ''' - def __init__(self, pickoptions=None, parent=None, windowflag=1): + def __init__(self, options=None, parent=None, windowflag=1): QtGui.QWidget.__init__(self, parent, windowflag) - self.pickoptions = pickoptions + self.options = options # self.pickoptions =[('current event', None), # ('tune events', None), # ('test events', None), @@ -2077,8 +2086,9 @@ class MultiEventWidget(QWidget): self.start_button = QtGui.QPushButton('Start') - for index, (key, func) in enumerate(self.pickoptions): + for index, (key, func) in enumerate(self.options): rb = QtGui.QRadioButton(key) + rb.toggled.connect(self.check_rb_selection) if index == 0: rb.setChecked(True) self.rb_dict[key] = rb @@ -2088,12 +2098,12 @@ class MultiEventWidget(QWidget): self.rb_layout.addWidget(self.start_button) self.rb_layout.addWidget(QtGui.QWidget()) - self.rb_layout.setStretch(len(self.pickoptions)+1, 1) + self.rb_layout.setStretch(len(self.options) + 1, 1) self.main_layout.insertLayout(0, self.rb_layout) def refresh_tooltips(self): - for key, func in self.pickoptions: + for key, func in self.options: eventlist = func() if not type(eventlist) == list: eventlist = [eventlist] @@ -2107,6 +2117,13 @@ class MultiEventWidget(QWidget): if not tooltip: tooltip = 'No events for this selection' self.rb_dict[key].setToolTip(tooltip) + self.check_rb_selection() + + def check_rb_selection(self): + for rb in self.rb_dict.values(): + if rb.isChecked(): + check_events = (rb.toolTip() == 'No events for this selection') + self.start_button.setEnabled(not(check_events)) def enable(self, bool): for rb in self.rb_dict.values(): @@ -2120,8 +2137,8 @@ class AutoPickWidget(MultiEventWidget): ''' ''' - def __init__(self, parent, pickoptions): - MultiEventWidget.__init__(self, pickoptions, parent, 1) + def __init__(self, parent, options): + MultiEventWidget.__init__(self, options, parent, 1) self.connect_buttons() self.init_plot_layout() self.init_log_layout() @@ -2205,8 +2222,8 @@ class CompareEventsWidget(MultiEventWidget): ''' ''' - def __init__(self, parent, pickoptions, eventdict, comparisons): - MultiEventWidget.__init__(self, pickoptions, parent, 1) + def __init__(self, parent, options, eventdict, comparisons): + MultiEventWidget.__init__(self, options, parent, 1) self.eventdict = eventdict self.comparisons = comparisons self.init_eventbox() @@ -2216,6 +2233,7 @@ class CompareEventsWidget(MultiEventWidget): def connect_buttons(self): self.start_button.clicked.connect(self.run) + self.start_button.setText('Show Histograms') def init_eventbox(self): self.eventbox_layout = QtGui.QHBoxLayout() From 33bc4e060f08c0dafb5e30594a49a6654e996508 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 31 Aug 2017 15:01:48 +0200 Subject: [PATCH 8/8] [minor] change layout and add groupbox --- pylot/core/util/widgets.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 6e840fc8..933cf9ab 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -2049,12 +2049,6 @@ class MultiEventWidget(QWidget): QtGui.QWidget.__init__(self, parent, windowflag) self.options = options - # self.pickoptions =[('current event', None), - # ('tune events', None), - # ('test events', None), - # ('all (picked)', None), - # ('all events', None)] - self.setupUi() # set initial size self.resize(1280, 720) @@ -2226,7 +2220,10 @@ class CompareEventsWidget(MultiEventWidget): MultiEventWidget.__init__(self, options, parent, 1) self.eventdict = eventdict self.comparisons = comparisons + self.compare_widget = QtGui.QWidget() self.init_eventbox() + self.init_event_area() + self.fill_eventbox() self.connect_buttons() self.setWindowTitle('Compare events') self.set_main_stretch() @@ -2235,11 +2232,16 @@ class CompareEventsWidget(MultiEventWidget): self.start_button.clicked.connect(self.run) self.start_button.setText('Show Histograms') + def init_event_area(self): + self.event_layout = QVBoxLayout() + self.event_layout.insertWidget(0, self.eventbox) + self.event_area = QGroupBox('Single Event') + self.event_area.setLayout(self.event_layout) + self.main_layout.insertWidget(1, self.event_area) + def init_eventbox(self): self.eventbox_layout = QtGui.QHBoxLayout() self.eventbox_layout.addWidget(self.eventbox) - self.main_layout.insertLayout(1, self.eventbox_layout) - self.fill_eventbox() self.eventbox.currentIndexChanged.connect(self.update_comparison) def fill_eventbox(self): @@ -2253,18 +2255,18 @@ class CompareEventsWidget(MultiEventWidget): self.fill_eventbox() def update_comparison(self, index=0): - if hasattr(self, 'compare_widget'): - self.compare_widget.setParent(None) + self.compare_widget.setParent(None) self.compare_widget = ComparisonWidget( self.comparisons[self.eventbox.currentText()], self, 0) - self.main_layout.insertWidget(2, self.compare_widget) + self.event_layout.insertWidget(1, self.compare_widget) self.set_main_stretch() def set_main_stretch(self): self.main_layout.setStretch(0, 0) - self.main_layout.setStretch(1, 0) - self.main_layout.setStretch(2, 1) - self.main_layout.setStretch(3, 0) + self.main_layout.setStretch(1, 1) + self.main_layout.setStretch(2, 0) + self.event_layout.setStretch(0, 0) + self.event_layout.setStretch(1, 1) def run(self): self.start.emit()