Compare commits

...

1 Commits

Author SHA1 Message Date
053b1ce397 [initial] first implementation of residual plotting (WIP) 2024-09-16 16:29:14 +02:00
4 changed files with 95 additions and 16 deletions

View File

@ -1537,8 +1537,8 @@ class MainWindow(QMainWindow):
return True return True
return not bool(os.listdir(wf_path)) return not bool(os.listdir(wf_path))
def filename_from_action(self, action): def filename_from_action(self, action=None):
if action.data() is None: if not action or action.data() is None:
filt = "Supported file formats" \ filt = "Supported file formats" \
" (*.mat *.qml *.xml *.kor *.evt)" " (*.mat *.qml *.xml *.kor *.evt)"
caption = "Open an event file" caption = "Open an event file"

View File

@ -218,12 +218,14 @@ def picksdict_from_obs(fn):
return picks return picks
def picksdict_from_picks(evt, parameter=None): def picksdict_from_picks(evt, parameter=None, nwst_id: bool = False):
""" """
Takes an Event object and return the pick dictionary commonly used within Takes an Event object and return the pick dictionary commonly used within
PyLoT PyLoT
:param evt: Event object contain all available information :param evt: Event object contain all available information
:type evt: `~obspy.core.event.Event` :type evt: `~obspy.core.event.Event`
:param nwst_id: determines if network and station id are used or only station id
:type nwst_id: bool
:return: pick dictionary (auto and manual) :return: pick dictionary (auto and manual)
""" """
picksdict = { picksdict = {
@ -233,7 +235,10 @@ def picksdict_from_picks(evt, parameter=None):
for pick in evt.picks: for pick in evt.picks:
errors = None errors = None
phase = {} phase = {}
station = pick.waveform_id.station_code if not nwst_id:
station_or_nwst = pick.waveform_id.station_code
else:
station_or_nwst = f'{pick.waveform_id.station_code}.{pick.waveform_id.network_code}'
if pick.waveform_id.channel_code is None: if pick.waveform_id.channel_code is None:
channel = '' channel = ''
else: else:
@ -254,7 +259,7 @@ def picksdict_from_picks(evt, parameter=None):
if pick_method == 'None': if pick_method == 'None':
pick_method = 'manual' pick_method = 'manual'
try: try:
onsets = picksdict[pick_method][station] onsets = picksdict[pick_method][station_or_nwst]
except KeyError as e: except KeyError as e:
# print(e) # print(e)
onsets = {} onsets = {}
@ -301,7 +306,7 @@ def picksdict_from_picks(evt, parameter=None):
phase['filter_id'] = filter_id if filter_id is not None else '' phase['filter_id'] = filter_id if filter_id is not None else ''
onsets[pick.phase_hint] = phase.copy() onsets[pick.phase_hint] = phase.copy()
picksdict[pick_method][station] = onsets.copy() picksdict[pick_method][station_or_nwst] = onsets.copy()
return picksdict return picksdict

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import copy
import traceback import traceback
import cartopy.crs as ccrs import cartopy.crs as ccrs
@ -16,6 +16,8 @@ from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from mpl_toolkits.axes_grid1.inset_locator import inset_axes from mpl_toolkits.axes_grid1.inset_locator import inset_axes
from obspy import UTCDateTime from obspy import UTCDateTime
from pylot.core.io.data import Data
from pylot.core.io.phases import picksdict_from_picks
from pylot.core.util.utils import identifyPhaseID from pylot.core.util.utils import identifyPhaseID
from scipy.interpolate import griddata from scipy.interpolate import griddata
@ -41,6 +43,7 @@ class MplCanvas(FigureCanvas):
class Array_map(QtWidgets.QWidget): class Array_map(QtWidgets.QWidget):
def __init__(self, parent, metadata, parameter=None, axes=None, annotate=True, pointsize=25., def __init__(self, parent, metadata, parameter=None, axes=None, annotate=True, pointsize=25.,
linewidth=1.5, width=5e6, height=2e6): linewidth=1.5, width=5e6, height=2e6):
QtWidgets.QWidget.__init__(self, parent=parent) QtWidgets.QWidget.__init__(self, parent=parent)
assert (parameter is not None or parent is not None), 'either parent or parameter has to be set' assert (parameter is not None or parent is not None), 'either parent or parameter has to be set'
@ -58,6 +61,8 @@ class Array_map(QtWidgets.QWidget):
self.uncertainties = None self.uncertainties = None
self.autopicks_dict = None self.autopicks_dict = None
self.hybrids_dict = None self.hybrids_dict = None
self.picks_dict_ref = None
self.autopicks_dict_ref = None
self.eventLoc = None self.eventLoc = None
self.parameter = parameter if parameter else parent._inputs self.parameter = parameter if parameter else parent._inputs
@ -108,8 +113,10 @@ class Array_map(QtWidgets.QWidget):
self.status_label = QtWidgets.QLabel() self.status_label = QtWidgets.QLabel()
self.map_reset_button = QtWidgets.QPushButton('Reset Map View') self.map_reset_button = QtWidgets.QPushButton('Reset Map View')
self.save_map_button = QtWidgets.QPushButton('Save Map') self.save_map_button = QtWidgets.QPushButton('Save Map')
self.load_reference_picks_button = QtWidgets.QPushButton('Load reference picks.')
self.go2eq_button = QtWidgets.QPushButton('Go to Event Location') self.go2eq_button = QtWidgets.QPushButton('Go to Event Location')
self.subtract_mean_cb = QtWidgets.QCheckBox('Subtract mean') self.subtract_mean_cb = QtWidgets.QCheckBox('Subtract mean')
self.subtract_ref_cb = QtWidgets.QCheckBox('Subtract reference onsets')
self.main_box = QtWidgets.QVBoxLayout() self.main_box = QtWidgets.QVBoxLayout()
self.setLayout(self.main_box) self.setLayout(self.main_box)
@ -156,7 +163,9 @@ class Array_map(QtWidgets.QWidget):
self.bot_row.addWidget(self.map_reset_button, 2) self.bot_row.addWidget(self.map_reset_button, 2)
self.bot_row.addWidget(self.go2eq_button, 2) self.bot_row.addWidget(self.go2eq_button, 2)
self.bot_row.addWidget(self.save_map_button, 2) self.bot_row.addWidget(self.save_map_button, 2)
self.bot_row.addWidget(self.load_reference_picks_button, 2)
self.bot_row.addWidget(self.subtract_mean_cb, 0) self.bot_row.addWidget(self.subtract_mean_cb, 0)
self.bot_row.addWidget(self.subtract_ref_cb, 0)
self.bot_row.addWidget(self.status_label, 5) self.bot_row.addWidget(self.status_label, 5)
def init_colormap(self): def init_colormap(self):
@ -217,7 +226,9 @@ class Array_map(QtWidgets.QWidget):
self.map_reset_button.clicked.connect(self.org_map_view) self.map_reset_button.clicked.connect(self.org_map_view)
self.go2eq_button.clicked.connect(self.go2eq) self.go2eq_button.clicked.connect(self.go2eq)
self.save_map_button.clicked.connect(self.saveFigure) self.save_map_button.clicked.connect(self.saveFigure)
self.load_reference_picks_button.clicked.connect(self.load_reference_picks)
self.subtract_mean_cb.stateChanged.connect(self.toggle_subtract_mean) self.subtract_mean_cb.stateChanged.connect(self.toggle_subtract_mean)
self.subtract_ref_cb.stateChanged.connect(self.toggle_subtract_ref)
self.plotWidget.mpl_connect('motion_notify_event', self.mouse_moved) self.plotWidget.mpl_connect('motion_notify_event', self.mouse_moved)
self.plotWidget.mpl_connect('scroll_event', self.mouse_scroll) self.plotWidget.mpl_connect('scroll_event', self.mouse_scroll)
@ -374,8 +385,11 @@ class Array_map(QtWidgets.QWidget):
def get_max_from_stations(self, key): def get_max_from_stations(self, key):
return self._from_dict(max, key) return self._from_dict(max, key)
def get_selected_pick_type(self):
return self.comboBox_am.currentText().split(' ')[0]
def current_picks_dict(self): def current_picks_dict(self):
picktype = self.comboBox_am.currentText().split(' ')[0] picktype = self.get_selected_pick_type()
auto_manu = {'auto': self.autopicks_dict, auto_manu = {'auto': self.autopicks_dict,
'manual': self.picks_dict, 'manual': self.picks_dict,
'hybrid': self.hybrids_dict} 'hybrid': self.hybrids_dict}
@ -447,6 +461,9 @@ class Array_map(QtWidgets.QWidget):
self.cmaps_box.setCurrentIndex(self.cmaps_box.findText(cmap)) self.cmaps_box.setCurrentIndex(self.cmaps_box.findText(cmap))
self._refresh_drawings() self._refresh_drawings()
def toggle_subtract_ref(self):
self._refresh_drawings()
def init_lat_lon_dimensions(self): def init_lat_lon_dimensions(self):
# init minimum and maximum lon and lat dimensions # init minimum and maximum lon and lat dimensions
self.londim = self.lonmax - self.lonmin self.londim = self.lonmax - self.lonmin
@ -459,7 +476,10 @@ class Array_map(QtWidgets.QWidget):
self.longrid, self.latgrid = np.meshgrid(lonaxis, lataxis) self.longrid, self.latgrid = np.meshgrid(lonaxis, lataxis)
def init_picksgrid(self): def init_picksgrid(self):
picks, uncertainties, lats, lons = self.get_picks_lat_lon() rval = self.get_picks_lat_lon()
if not rval:
return
picks, uncertainties, lats, lons = rval
try: try:
self.picksgrid_active = griddata((lats, lons), picks, (self.latgrid, self.longrid), method='linear') self.picksgrid_active = griddata((lats, lons), picks, (self.latgrid, self.longrid), method='linear')
except Exception as e: except Exception as e:
@ -477,15 +497,20 @@ class Array_map(QtWidgets.QWidget):
def get_picks_lat_lon(self): def get_picks_lat_lon(self):
picks_rel = self.picks_rel_mean_corrected if self.subtract_mean_cb.isChecked() else self.picks_rel picks_rel = self.picks_rel_mean_corrected if self.subtract_mean_cb.isChecked() else self.picks_rel
picks_rel = self.picks_rel_ref_corrected if self.subtract_ref_cb.isChecked() else picks_rel
if not picks_rel:
return
picks = [] picks = []
uncertainties = [] uncertainties = []
latitudes = [] latitudes = []
longitudes = [] longitudes = []
for st_id, pick in picks_rel.items(): for nwst_id, pick in picks_rel.items():
if nwst_id not in self.uncertainties or nwst_id not in self.stations_dict:
continue
picks.append(pick) picks.append(pick)
uncertainties.append(self.uncertainties.get(st_id)) uncertainties.append(self.uncertainties.get(nwst_id))
latitudes.append(self.stations_dict[st_id]['latitude']) latitudes.append(self.stations_dict[nwst_id]['latitude'])
longitudes.append(self.stations_dict[st_id]['longitude']) longitudes.append(self.stations_dict[nwst_id]['longitude'])
return picks, uncertainties, latitudes, longitudes return picks, uncertainties, latitudes, longitudes
# plotting ----------------------------------------------------- # plotting -----------------------------------------------------
@ -582,7 +607,10 @@ class Array_map(QtWidgets.QWidget):
transform=ccrs.PlateCarree()) transform=ccrs.PlateCarree())
def scatter_picked_stations(self): def scatter_picked_stations(self):
picks, uncertainties, lats, lons = self.get_picks_lat_lon() rval = self.get_picks_lat_lon()
if not rval:
return
picks, uncertainties, lats, lons = rval
if len(lons) < 1 and len(lats) < 1: if len(lons) < 1 and len(lats) < 1:
return return
@ -737,6 +765,52 @@ class Array_map(QtWidgets.QWidget):
fname += '.png' fname += '.png'
self.canvas.fig.savefig(fname) self.canvas.fig.savefig(fname)
def load_reference_picks(self):
fname = self._parent.filename_from_action()
data_ref = Data(parent=self._parent, evtdata=str(fname))
evt_ref = data_ref.get_evt_data()
if not evt_ref:
return
picks_ref = evt_ref.picks
if not picks_ref:
return
picksdict_ref = picksdict_from_picks(evt_ref, nwst_id=False)
self.autopicks_dict = picksdict_ref['manual']
self.autopicks_dict_ref = picksdict_ref['auto']
return True
@property
def picks_rel_ref_corrected(self):
picktype = self.get_selected_pick_type()
if picktype in ['auto', 'hybrid']:
picks_dict = self.autopicks_dict_ref
elif picktype == 'manual':
picks_dict = self.autopicks_dict
else:
return
if picks_dict:
return self.subtract_picks(picks_dict)
else:
if self.load_reference_picks():
return self.picks_rel_ref_corrected
def subtract_picks(self, picks_dict):
current_picks = self.current_picks_dict()
subtracted_picks = {}
for station, ps_dict in current_picks.items():
for phase, pick in ps_dict.items():
pick_ref_ps = picks_dict.get(station)
if not pick_ref_ps:
continue
pick_ref = pick_ref_ps.get(phase)
if not pick_ref:
continue
mpp = pick['mpp'] - pick_ref['mpp']
nwst_id = f'{pick["network"]}.{station}'
subtracted_picks[nwst_id] = mpp
return subtracted_picks
def _warn(self, message): def _warn(self, message):
self.qmb = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Icon.Warning, 'Warning', message) self.qmb = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Icon.Warning, 'Warning', message)
self.qmb.show() self.qmb.show()

View File

@ -25,7 +25,7 @@ class HidePrints:
if self.hide: if self.hide:
self._original_stdout = sys.stdout self._original_stdout = sys.stdout
devnull = open(os.devnull, "w") devnull = open(os.devnull, "w")
sys.stdout = devnull #sys.stdout = devnull
def __exit__(self, exc_type, exc_val, exc_tb): def __exit__(self, exc_type, exc_val, exc_tb):
if self.hide: if self.hide:
@ -271,7 +271,7 @@ class TestAutopickStation(unittest.TestCase):
'fm': 'N', 'channel': None}} 'fm': 'N', 'channel': None}}
with HidePrints(): with HidePrints():
result, station = autopickstation(wfstream=wfstream, pickparam=self.pickparam_taupy_disabled, result, station = autopickstation(wfstream=wfstream, pickparam=self.pickparam_taupy_disabled,
metadata=(None, None)) metadata=(None, None), iplot=2)
compare_dicts(expected=expected['P'], result=result['P'], hint='P-') compare_dicts(expected=expected['P'], result=result['P'], hint='P-')
compare_dicts(expected=expected['S'], result=result['S'], hint='S-') compare_dicts(expected=expected['S'], result=result['S'], hint='S-')
self.assertEqual('GRA1', station) self.assertEqual('GRA1', station)