Compare commits
2 Commits
e1a0fde619
...
feature/da
| Author | SHA1 | Date | |
|---|---|---|---|
| 65dbaad446 | |||
| 5b97d51517 |
66
PyLoT.py
66
PyLoT.py
@@ -76,7 +76,7 @@ from pylot.core.util.utils import fnConstructor, getLogin, \
|
||||
full_range, readFilterInformation, pick_color_plt, \
|
||||
pick_linestyle_plt, identifyPhaseID, excludeQualityClasses, \
|
||||
transform_colors_mpl, transform_colors_mpl_str, getAutoFilteroptions, check_all_obspy, \
|
||||
check_all_pylot, get_bool, get_None, get_pylot_eventfile_with_extension
|
||||
check_all_pylot, get_bool, get_None
|
||||
from pylot.core.util.gui import make_pen
|
||||
from pylot.core.util.event import Event
|
||||
from pylot.core.io.location import create_creation_info, create_event
|
||||
@@ -84,7 +84,7 @@ from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \
|
||||
PylotCanvas, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \
|
||||
ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \
|
||||
CompareEventsWidget, ProgressBarWidget, AddMetadataWidget, SingleTextLineDialog, LogWidget, PickQualitiesFromXml, \
|
||||
SourceSpecWindow, ChooseWaveFormWindow, SpectrogramTab, SearchFileByExtensionDialog
|
||||
SourceSpecWindow, ChooseWaveFormWindow, SpectrogramTab
|
||||
from pylot.core.util.array_map import Array_map
|
||||
from pylot.core.util.structure import DATASTRUCTURE
|
||||
from pylot.core.util.thread import Thread, Worker
|
||||
@@ -181,6 +181,7 @@ class MainWindow(QMainWindow):
|
||||
self.autodata = Data(self)
|
||||
|
||||
self.fnames = None
|
||||
self.fnames_comp = None
|
||||
self._stime = None
|
||||
|
||||
# track deleted picks for logging
|
||||
@@ -1006,15 +1007,16 @@ class MainWindow(QMainWindow):
|
||||
return
|
||||
refresh = False
|
||||
events = self.project.eventlist
|
||||
sld = SearchFileByExtensionDialog(label='Specify file extension: ', default_text='.xml',
|
||||
events=events)
|
||||
sld = SingleTextLineDialog(label='Specify file extension: ', default_text='.xml')
|
||||
if not sld.exec_():
|
||||
return
|
||||
fext = sld.lineEdit.text()
|
||||
# fext = '.xml'
|
||||
for event in events:
|
||||
filename = get_pylot_eventfile_with_extension(event, fext)
|
||||
if filename:
|
||||
path = event.path
|
||||
eventname = path.split('/')[-1] # or event.pylot_id
|
||||
filename = os.path.join(path, 'PyLoT_' + eventname + fext)
|
||||
if os.path.isfile(filename):
|
||||
self.load_data(filename, draw=False, event=event, overwrite=True)
|
||||
refresh = True
|
||||
if not refresh:
|
||||
@@ -1129,16 +1131,19 @@ class MainWindow(QMainWindow):
|
||||
else:
|
||||
return
|
||||
|
||||
def getWFFnames_from_eventbox(self, eventbox=None):
|
||||
def getWFFnames_from_eventbox(self, eventbox: str = None, subpath: str = None) -> list:
|
||||
'''
|
||||
Return waveform filenames from event in eventbox.
|
||||
'''
|
||||
# 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]
|
||||
if subpath:
|
||||
eventpath = os.path.join(eventpath, subpath)
|
||||
if not os.path.isdir(eventpath):
|
||||
return []
|
||||
if self.dataStructure:
|
||||
if not eventpath:
|
||||
return
|
||||
return []
|
||||
fnames = [os.path.join(eventpath, f) for f in os.listdir(eventpath)]
|
||||
else:
|
||||
raise DatastructureError('not specified')
|
||||
@@ -1886,7 +1891,6 @@ class MainWindow(QMainWindow):
|
||||
# which will read in data input twice. Therefore current tab is changed to 0
|
||||
# in loadProject before calling this function.
|
||||
self.fill_eventbox()
|
||||
#print(f'{self.get_current_event()=}')
|
||||
plotted = False
|
||||
if self.tabs.currentIndex() == 2:
|
||||
self.init_event_table()
|
||||
@@ -1921,6 +1925,7 @@ class MainWindow(QMainWindow):
|
||||
self.spectro_layout.addWidget(newSpectroWidget)
|
||||
self.spectroWidget = newSpectroWidget
|
||||
|
||||
|
||||
def newWF(self, event=None, plot=True):
|
||||
'''
|
||||
Load new data and plot if necessary.
|
||||
@@ -1950,13 +1955,20 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def prepareLoadWaveformData(self):
|
||||
self.fnames = self.getWFFnames_from_eventbox()
|
||||
self.fnames_syn = []
|
||||
self.fnames_comp = []
|
||||
fnames_comp = self.getWFFnames_from_eventbox(subpath='compare')
|
||||
self.dataPlot.activateCompareOptions(bool(fnames_comp))
|
||||
if fnames_comp:
|
||||
if self.dataPlot.comp_checkbox.isChecked():
|
||||
self.fnames_comp = fnames_comp
|
||||
|
||||
eventpath = self.get_current_event_path()
|
||||
basepath = eventpath.split(os.path.basename(eventpath))[0]
|
||||
self.obspy_dmt = check_obspydmt_structure(basepath)
|
||||
self.dataPlot.activateObspyDMToptions(self.obspy_dmt)
|
||||
if self.obspy_dmt:
|
||||
self.prepareObspyDMT_data(eventpath)
|
||||
self.dataPlot.activateCompareOptions(True)
|
||||
|
||||
def loadWaveformData(self):
|
||||
'''
|
||||
@@ -1971,8 +1983,6 @@ class MainWindow(QMainWindow):
|
||||
# ans = False
|
||||
|
||||
settings = QSettings()
|
||||
# process application events to wait for event items to appear in event box
|
||||
QApplication.processEvents()
|
||||
curr_event = self.get_current_event()
|
||||
if not curr_event:
|
||||
print('Could not find current event. Try reload?')
|
||||
@@ -1989,7 +1999,7 @@ class MainWindow(QMainWindow):
|
||||
tstop = None
|
||||
|
||||
self.data.setWFData(self.fnames,
|
||||
self.fnames_syn,
|
||||
self.fnames_comp,
|
||||
checkRotated=True,
|
||||
metadata=self.metadata,
|
||||
tstart=tstart,
|
||||
@@ -1997,7 +2007,7 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def prepareObspyDMT_data(self, eventpath):
|
||||
qcbox_processed = self.dataPlot.qcombo_processed
|
||||
qcheckb_syn = self.dataPlot.syn_checkbox
|
||||
qcheckb_syn = self.dataPlot.comp_checkbox
|
||||
qcbox_processed.setEnabled(False)
|
||||
qcheckb_syn.setEnabled(False)
|
||||
for fpath in os.listdir(eventpath):
|
||||
@@ -2005,8 +2015,8 @@ class MainWindow(QMainWindow):
|
||||
if 'syngine' in fpath:
|
||||
eventpath_syn = os.path.join(eventpath, fpath)
|
||||
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 self.dataPlot.comp_checkbox.isChecked():
|
||||
self.fnames_comp = [os.path.join(eventpath_syn, filename) for filename in os.listdir(eventpath_syn)]
|
||||
if 'processed' in fpath:
|
||||
qcbox_processed.setEnabled(True)
|
||||
if qcbox_processed.isEnabled():
|
||||
@@ -2128,7 +2138,7 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def finish_pg_plot(self):
|
||||
self.getPlotWidget().updateWidget()
|
||||
plots = self.wfp_thread.data
|
||||
plots, gaps = self.wfp_thread.data
|
||||
# do not show plot if no data are given
|
||||
self.wf_scroll_area.setVisible(len(plots) > 0)
|
||||
self.no_data_label.setVisible(not len(plots) > 0)
|
||||
@@ -2287,7 +2297,7 @@ class MainWindow(QMainWindow):
|
||||
comp = self.getComponent()
|
||||
title = 'section: {0} components'.format(zne_text[comp])
|
||||
wfst = self.get_data().getWFData()
|
||||
wfsyn = self.get_data().getSynWFData()
|
||||
wfsyn = self.get_data().getAltWFdata()
|
||||
if self.filterActionP.isChecked() and filter:
|
||||
self.filterWaveformData(plot=False, phase='P')
|
||||
elif self.filterActionS.isChecked() and filter:
|
||||
@@ -2302,8 +2312,8 @@ class MainWindow(QMainWindow):
|
||||
self.plot_method = 'normal'
|
||||
rval = plotWidget.plotWFData(wfdata=wfst, wfsyn=wfsyn, title=title, mapping=False, component=comp,
|
||||
nth_sample=int(nth_sample), method=self.plot_method, gain=self.gain)
|
||||
plots = rval if rval else []
|
||||
return plots
|
||||
plots, gaps = rval if rval else ([], [])
|
||||
return plots, gaps
|
||||
|
||||
def adjustPlotHeight(self):
|
||||
if self.pg:
|
||||
@@ -2599,18 +2609,21 @@ class MainWindow(QMainWindow):
|
||||
print("Warning! No network, station, and location info available!")
|
||||
return
|
||||
self.update_status('picking on station {0}'.format(station))
|
||||
data = self.get_data().getOriginalWFData().copy()
|
||||
wfdata = self.get_data().getOriginalWFData().copy()
|
||||
wfdata_comp = self.get_data().getAltWFdata().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),
|
||||
data=wfdata.select(station=station),
|
||||
data_compare=wfdata_comp.select(station=station),
|
||||
station=station, network=network,
|
||||
location=location,
|
||||
picks=self.getPicksOnStation(station, 'manual'),
|
||||
autopicks=self.getPicksOnStation(station, 'auto'),
|
||||
metadata=self.metadata, event=event,
|
||||
model=self.inputs.get('taup_model'),
|
||||
filteroptions=self.filteroptions, wftype=wftype)
|
||||
filteroptions=self.filteroptions, wftype=wftype,
|
||||
show_comp_data=self.dataPlot.comp_checkbox.isChecked())
|
||||
if self.filterActionP.isChecked():
|
||||
pickDlg.currentPhase = "P"
|
||||
pickDlg.filterWFData()
|
||||
@@ -3634,7 +3647,7 @@ class MainWindow(QMainWindow):
|
||||
return True
|
||||
return False
|
||||
|
||||
def update_status(self, message, duration=10000):
|
||||
def update_status(self, message, duration=5000):
|
||||
self.statusBar().showMessage(message, duration)
|
||||
if self.get_data() is not None:
|
||||
if not self.get_current_event() or not self.project.location:
|
||||
@@ -3808,8 +3821,7 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def closeEvent(self, event):
|
||||
if self.okToContinue():
|
||||
if hasattr(self, 'logwidget'):
|
||||
self.logwidget.close()
|
||||
self.logwidget.close()
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
|
||||
conda activate pylot_38
|
||||
|
||||
python ./autoPyLoT.py -i /home/marcel/.pylot/pylot_adriaarray.in -c 20 -dmt processed
|
||||
python ./autoPyLoT.py -i /home/marcel/.pylot/pylot_janis_noisy.in -c $NSLOTS
|
||||
|
||||
@@ -19,7 +19,7 @@ from pylot.core.util.errors import FormatError, OverwriteError
|
||||
from pylot.core.util.event import Event
|
||||
from pylot.core.util.obspyDMT_interface import qml_from_obspyDMT
|
||||
from pylot.core.util.utils import fnConstructor, full_range, check4rotated, \
|
||||
check_for_gaps_and_merge, trim_station_components, check_for_nan
|
||||
check4gapsAndMerge, trim_station_components
|
||||
|
||||
|
||||
class Data(object):
|
||||
@@ -64,7 +64,7 @@ class Data(object):
|
||||
elif 'LOC' in evtdata:
|
||||
raise NotImplementedError('PILOT location information '
|
||||
'read support not yet '
|
||||
'implemented.')
|
||||
'implemeted.')
|
||||
elif 'event.pkl' in evtdata:
|
||||
evtdata = qml_from_obspyDMT(evtdata)
|
||||
else:
|
||||
@@ -451,27 +451,25 @@ class Data(object):
|
||||
data.filter(**kwargs)
|
||||
self.dirty = True
|
||||
|
||||
def setWFData(self, fnames, fnames_syn=None, checkRotated=False, metadata=None, tstart=0, tstop=0):
|
||||
def setWFData(self, fnames, fnames_alt=None, checkRotated=False, metadata=None, tstart=0, tstop=0):
|
||||
"""
|
||||
Clear current waveform data and set given waveform data
|
||||
:param fnames: waveform data names to append
|
||||
:param fnames_alt: alternative data to show (e.g. synthetic/processed)
|
||||
:type fnames: list
|
||||
"""
|
||||
def check_fname_exists(filenames: list) -> list:
|
||||
if filenames:
|
||||
filenames = [fn for fn in filenames if os.path.isfile(fn)]
|
||||
return filenames
|
||||
|
||||
self.wfdata = Stream()
|
||||
self.wforiginal = None
|
||||
self.wfsyn = Stream()
|
||||
self.wf_alt = Stream()
|
||||
if tstart == tstop:
|
||||
tstart = tstop = None
|
||||
self.tstart = tstart
|
||||
self.tstop = tstop
|
||||
|
||||
fnames = check_fname_exists(fnames)
|
||||
fnames_syn = check_fname_exists(fnames_syn)
|
||||
# remove directories
|
||||
fnames = [fname for fname in fnames if not os.path.isdir(fname)]
|
||||
fnames_alt = [fname for fname in fnames_alt if not os.path.isdir(fname)]
|
||||
|
||||
# if obspy_dmt:
|
||||
# wfdir = 'raw'
|
||||
# self.processed = False
|
||||
@@ -489,8 +487,8 @@ class Data(object):
|
||||
# wffnames = fnames
|
||||
if fnames is not None:
|
||||
self.appendWFData(fnames)
|
||||
if fnames_syn is not None:
|
||||
self.appendWFData(fnames_syn, synthetic=True)
|
||||
if fnames_alt is not None:
|
||||
self.appendWFData(fnames_alt, alternative=True)
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -498,9 +496,7 @@ class Data(object):
|
||||
# remove possible underscores in station names
|
||||
# self.wfdata = remove_underscores(self.wfdata)
|
||||
# check for gaps and merge
|
||||
self.wfdata, _ = check_for_gaps_and_merge(self.wfdata)
|
||||
# check for nans
|
||||
check_for_nan(self.wfdata)
|
||||
self.wfdata = check4gapsAndMerge(self.wfdata)
|
||||
# check for stations with rotated components
|
||||
if checkRotated and metadata is not None:
|
||||
self.wfdata = check4rotated(self.wfdata, metadata, verbosity=0)
|
||||
@@ -512,7 +508,7 @@ class Data(object):
|
||||
self.dirty = False
|
||||
return True
|
||||
|
||||
def appendWFData(self, fnames, synthetic=False):
|
||||
def appendWFData(self, fnames, alternative=False):
|
||||
"""
|
||||
Read waveform data from fnames and append it to current wf data
|
||||
:param fnames: waveform data to append
|
||||
@@ -525,20 +521,20 @@ class Data(object):
|
||||
if self.dirty:
|
||||
self.resetWFData()
|
||||
|
||||
real_or_syn_data = {True: self.wfsyn,
|
||||
False: self.wfdata}
|
||||
orig_or_alternative_data = {True: self.wf_alt,
|
||||
False: self.wfdata}
|
||||
|
||||
warnmsg = ''
|
||||
for fname in set(fnames):
|
||||
try:
|
||||
real_or_syn_data[synthetic] += read(fname, starttime=self.tstart, endtime=self.tstop)
|
||||
orig_or_alternative_data[alternative] += read(fname, starttime=self.tstart, endtime=self.tstop)
|
||||
except TypeError:
|
||||
try:
|
||||
real_or_syn_data[synthetic] += read(fname, format='GSE2', starttime=self.tstart, endtime=self.tstop)
|
||||
orig_or_alternative_data[alternative] += read(fname, format='GSE2', starttime=self.tstart, endtime=self.tstop)
|
||||
except Exception as e:
|
||||
try:
|
||||
real_or_syn_data[synthetic] += read(fname, format='SEGY', starttime=self.tstart,
|
||||
endtime=self.tstop)
|
||||
orig_or_alternative_data[alternative] += read(fname, format='SEGY', starttime=self.tstart,
|
||||
endtime=self.tstop)
|
||||
except Exception as e:
|
||||
warnmsg += '{0}\n{1}\n'.format(fname, e)
|
||||
except SacIOError as se:
|
||||
@@ -553,8 +549,8 @@ class Data(object):
|
||||
def getOriginalWFData(self):
|
||||
return self.wforiginal
|
||||
|
||||
def getSynWFData(self):
|
||||
return self.wfsyn
|
||||
def getAltWFdata(self):
|
||||
return self.wf_alt
|
||||
|
||||
def resetWFData(self):
|
||||
"""
|
||||
|
||||
@@ -660,7 +660,7 @@ class AutopickStation(object):
|
||||
ax1.set_ylim([-1.5, 1.5])
|
||||
ax1.set_ylabel('Normalized Counts')
|
||||
|
||||
if self.horizontal_traces_exist():# and self.s_data.Sflag == 1:
|
||||
if self.horizontal_traces_exist() and self.s_data.Sflag == 1:
|
||||
# plot E trace
|
||||
ax2 = fig.add_subplot(3, 1, 2, sharex=ax1)
|
||||
th1data = np.linspace(0, self.etrace.stats.endtime - self.etrace.stats.starttime,
|
||||
|
||||
@@ -1332,6 +1332,22 @@ def get_quality_class(uncertainty, weight_classes):
|
||||
return quality
|
||||
|
||||
|
||||
def set_NaNs_to(data, nan_value):
|
||||
"""
|
||||
Replace all NaNs in data with nan_value
|
||||
:param data: array holding data
|
||||
:type data: `~numpy.ndarray`
|
||||
:param nan_value: value which all NaNs are set to
|
||||
:type nan_value: float, int
|
||||
:return: data array with all NaNs replaced with nan_value
|
||||
:rtype: `~numpy.ndarray`
|
||||
"""
|
||||
nn = np.isnan(data)
|
||||
if np.any(nn):
|
||||
data[nn] = nan_value
|
||||
return data
|
||||
|
||||
|
||||
def taper_cf(cf):
|
||||
"""
|
||||
Taper cf data to get rid off of side maximas
|
||||
|
||||
@@ -13,7 +13,6 @@ import obspy
|
||||
from PySide2 import QtWidgets
|
||||
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
||||
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
|
||||
from pylot.core.util.utils import identifyPhaseID
|
||||
from scipy.interpolate import griddata
|
||||
|
||||
from pylot.core.pick.utils import get_quality_class
|
||||
@@ -280,12 +279,9 @@ class Array_map(QtWidgets.QWidget):
|
||||
self.canvas.axes.figure.canvas.draw_idle()
|
||||
|
||||
def onpick(self, event):
|
||||
btn_msg = {1: ' in selection. Aborted', 2: ' to delete a pick on. Aborted', 3: ' to display info.'}
|
||||
ind = event.ind
|
||||
button = event.mouseevent.button
|
||||
msg_reason = None
|
||||
if len(ind) > 1:
|
||||
self._parent.update_status(f'Found more than one station {btn_msg.get(button)}')
|
||||
if ind == []:
|
||||
return
|
||||
if button == 1:
|
||||
self.openPickDlg(ind)
|
||||
@@ -388,14 +384,7 @@ class Array_map(QtWidgets.QWidget):
|
||||
try:
|
||||
station_name = st_id.split('.')[-1]
|
||||
# current_picks_dict: auto or manual
|
||||
station_picks = self.current_picks_dict().get(station_name)
|
||||
if not station_picks:
|
||||
continue
|
||||
for phase_hint, pick in station_picks.items():
|
||||
if identifyPhaseID(phase_hint) == phase:
|
||||
break
|
||||
else:
|
||||
continue
|
||||
pick = self.current_picks_dict()[station_name][phase]
|
||||
if pick['picker'] == 'auto':
|
||||
if not pick['spe']:
|
||||
continue
|
||||
@@ -474,17 +463,19 @@ class Array_map(QtWidgets.QWidget):
|
||||
transform=ccrs.PlateCarree(), label='deleted'))
|
||||
|
||||
def openPickDlg(self, ind):
|
||||
data = self._parent.get_data().getWFData()
|
||||
wfdata = self._parent.get_data().getWFData()
|
||||
wfdata_comp = self._parent.get_data().getWFDataComp()
|
||||
for index in ind:
|
||||
network, station = self._station_onpick_ids[index].split('.')[:2]
|
||||
pyl_mw = self._parent
|
||||
try:
|
||||
data = data.select(station=station)
|
||||
if not data:
|
||||
wfdata = wfdata.select(station=station)
|
||||
wfdata_comp = wfdata_comp.select(station=station)
|
||||
if not wfdata:
|
||||
self._warn('No data for station {}'.format(station))
|
||||
return
|
||||
pickDlg = PickDlg(self._parent, parameter=self.parameter,
|
||||
data=data, network=network, station=station,
|
||||
data=wfdata.copy(), data_compare=wfdata_comp.copy(), network=network, station=station,
|
||||
picks=self._parent.get_current_event().getPick(station),
|
||||
autopicks=self._parent.get_current_event().getAutopick(station),
|
||||
filteroptions=self._parent.filteroptions, metadata=self.metadata,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import glob
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
@@ -190,11 +189,7 @@ class Metadata(object):
|
||||
metadata = self.get_metadata(seed_id, time)
|
||||
if not metadata:
|
||||
return
|
||||
try:
|
||||
return metadata['data'].get_coordinates(seed_id, time)
|
||||
# no specific exception defined in obspy inventory
|
||||
except Exception as e:
|
||||
logging.warning(f'Could not get metadata for {seed_id}')
|
||||
return metadata['data'].get_coordinates(seed_id, time)
|
||||
|
||||
def get_all_coordinates(self):
|
||||
def stat_info_from_parser(parser):
|
||||
|
||||
@@ -42,7 +42,7 @@ def main(project_file_path, manual=False, auto=True, file_format='png', f_ext=''
|
||||
for item in input_list:
|
||||
array_map_worker(item)
|
||||
else:
|
||||
pool = multiprocessing.Pool(ncores, maxtasksperchild=1000)
|
||||
pool = multiprocessing.Pool(ncores)
|
||||
pool.map(array_map_worker, input_list)
|
||||
pool.close()
|
||||
pool.join()
|
||||
|
||||
@@ -160,7 +160,7 @@ class MultiThread(QThread):
|
||||
try:
|
||||
if not self.ncores:
|
||||
self.ncores = multiprocessing.cpu_count()
|
||||
pool = multiprocessing.Pool(self.ncores, maxtasksperchild=1000)
|
||||
pool = multiprocessing.Pool(self.ncores)
|
||||
self.data = pool.map_async(self.func, self.args, callback=self.emitDone)
|
||||
# self.data = pool.apply_async(self.func, self.shotlist, callback=self.emitDone) #emit each time returned
|
||||
pool.close()
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
@@ -120,7 +119,7 @@ def gen_Pool(ncores=0):
|
||||
|
||||
print('gen_Pool: Generated multiprocessing Pool with {} cores\n'.format(ncores))
|
||||
|
||||
pool = multiprocessing.Pool(ncores, maxtasksperchild=100)
|
||||
pool = multiprocessing.Pool(ncores)
|
||||
return pool
|
||||
|
||||
|
||||
@@ -819,6 +818,19 @@ def trim_station_components(data, trim_start=True, trim_end=True):
|
||||
return data
|
||||
|
||||
|
||||
def merge_stream(stream):
|
||||
gaps = stream.get_gaps()
|
||||
if gaps:
|
||||
# list of merged stations (seed_ids)
|
||||
merged = ['{}.{}.{}.{}'.format(*gap[:4]) for gap in gaps]
|
||||
stream.merge(method=1)
|
||||
print('Merged the following stations because of gaps:')
|
||||
for merged_station in merged:
|
||||
print(merged_station)
|
||||
|
||||
return stream, gaps
|
||||
|
||||
|
||||
def check4gapsAndRemove(data):
|
||||
"""
|
||||
check for gaps in Stream and remove them
|
||||
@@ -839,12 +851,12 @@ def check4gapsAndRemove(data):
|
||||
return data
|
||||
|
||||
|
||||
def check_for_gaps_and_merge(data):
|
||||
def check4gapsAndMerge(data):
|
||||
"""
|
||||
check for gaps in Stream and merge if gaps are found
|
||||
:param data: stream of seismic data
|
||||
:type data: `~obspy.core.stream.Stream`
|
||||
:return: data stream, gaps returned from obspy get_gaps
|
||||
:return: data stream
|
||||
:rtype: `~obspy.core.stream.Stream`
|
||||
"""
|
||||
gaps = data.get_gaps()
|
||||
@@ -855,7 +867,7 @@ def check_for_gaps_and_merge(data):
|
||||
for merged_station in merged:
|
||||
print(merged_station)
|
||||
|
||||
return data, gaps
|
||||
return data
|
||||
|
||||
|
||||
def check4doubled(data):
|
||||
@@ -885,33 +897,6 @@ def check4doubled(data):
|
||||
return data
|
||||
|
||||
|
||||
def check_for_nan(data, nan_value=0.):
|
||||
"""
|
||||
Replace all NaNs in data with nan_value (in place)
|
||||
:param data: stream of seismic data
|
||||
:type data: `~obspy.core.stream.Stream`
|
||||
:param nan_value: value which all NaNs are set to
|
||||
:type nan_value: float, int
|
||||
:return: None
|
||||
"""
|
||||
if not data:
|
||||
return
|
||||
for trace in data:
|
||||
np.nan_to_num(trace.data, copy=False, nan=nan_value)
|
||||
|
||||
|
||||
def get_pylot_eventfile_with_extension(event, fext):
|
||||
if hasattr(event, 'path'):
|
||||
eventpath = event.path
|
||||
else:
|
||||
logging.warning('No attribute path found for event.')
|
||||
return
|
||||
eventname = eventpath.split('/')[-1] # or event.pylot_id
|
||||
filename = os.path.join(eventpath, 'PyLoT_' + eventname + fext)
|
||||
if os.path.isfile(filename):
|
||||
return filename
|
||||
|
||||
|
||||
def get_stations(data):
|
||||
"""
|
||||
Get list of all station names in data stream
|
||||
|
||||
@@ -36,7 +36,7 @@ from PySide2.QtWidgets import QAction, QApplication, QCheckBox, QComboBox, \
|
||||
QGridLayout, QLabel, QLineEdit, QMessageBox, \
|
||||
QTabWidget, QToolBar, QVBoxLayout, QHBoxLayout, QWidget, \
|
||||
QPushButton, QFileDialog, QInputDialog
|
||||
from PySide2.QtCore import QSettings, Qt, QUrl, Signal, QTimer
|
||||
from PySide2.QtCore import QSettings, Qt, QUrl, Signal
|
||||
from PySide2.QtWebEngineWidgets import QWebEngineView as QWebView
|
||||
from obspy import Stream, Trace, UTCDateTime
|
||||
from obspy.core.util import AttribDict
|
||||
@@ -51,10 +51,10 @@ from pylot.core.pick.autopick import fmpicker
|
||||
from pylot.core.util.defaults import OUTPUTFORMATS, FILTERDEFAULTS
|
||||
from pylot.core.util.utils import prepTimeAxis, full_range, demeanTrace, isSorted, findComboBoxIndex, clims, \
|
||||
pick_linestyle_plt, pick_color_plt, \
|
||||
check4rotated, check4doubled, check_for_gaps_and_merge, check_for_nan, identifyPhase, \
|
||||
check4rotated, check4doubled, merge_stream, identifyPhase, \
|
||||
loopIdentifyPhase, trim_station_components, transformFilteroptions2String, \
|
||||
identifyPhaseID, get_bool, get_None, pick_color, getAutoFilteroptions, SetChannelComponents, \
|
||||
station_id_remove_channel, get_pylot_eventfile_with_extension
|
||||
station_id_remove_channel
|
||||
from autoPyLoT import autoPyLoT
|
||||
from pylot.core.util.thread import Thread
|
||||
from pylot.core.util.dataprocessing import Metadata
|
||||
@@ -793,7 +793,7 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
|
||||
def connect_signals(self):
|
||||
self.qcombo_processed.activated.connect(self.parent().newWF)
|
||||
self.syn_checkbox.clicked.connect(self.parent().newWF)
|
||||
self.comp_checkbox.clicked.connect(self.parent().newWF)
|
||||
|
||||
def init_labels(self):
|
||||
self.label_layout.addWidget(self.status_label)
|
||||
@@ -804,13 +804,13 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
# use widgets as placeholder, so that child widgets keep position when others are hidden
|
||||
mid_layout = QHBoxLayout()
|
||||
right_layout = QHBoxLayout()
|
||||
mid_layout.addWidget(self.syn_checkbox)
|
||||
mid_layout.addWidget(self.comp_checkbox)
|
||||
right_layout.addWidget(self.qcombo_processed)
|
||||
mid_widget.setLayout(mid_layout)
|
||||
right_widget.setLayout(right_layout)
|
||||
self.label_layout.addWidget(mid_widget)
|
||||
self.label_layout.addWidget(right_widget)
|
||||
self.syn_checkbox.setLayoutDirection(Qt.RightToLeft)
|
||||
self.comp_checkbox.setLayoutDirection(Qt.RightToLeft)
|
||||
self.label_layout.setStretch(0, 4)
|
||||
self.label_layout.setStretch(1, 0)
|
||||
self.label_layout.setStretch(2, 0)
|
||||
@@ -825,7 +825,7 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
label = QtWidgets.QLabel()
|
||||
self.perm_labels.append(label)
|
||||
self.qcombo_processed = QtWidgets.QComboBox()
|
||||
self.syn_checkbox = QtWidgets.QCheckBox('synthetics')
|
||||
self.comp_checkbox = QtWidgets.QCheckBox('Load comparison data')
|
||||
self.addQCboxItem('processed', 'green')
|
||||
self.addQCboxItem('raw', 'black')
|
||||
# self.perm_qcbox_right.setAlignment(2)
|
||||
@@ -834,9 +834,11 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
def getPlotDict(self):
|
||||
return self.plotdict
|
||||
|
||||
def activateObspyDMToptions(self, activate):
|
||||
self.syn_checkbox.setVisible(activate)
|
||||
self.qcombo_processed.setVisible(activate)
|
||||
def activateObspyDMToptions(self, activate: bool) -> None:
|
||||
self.qcombo_processed.setEnabled(activate)
|
||||
|
||||
def activateCompareOptions(self, activate: bool) -> None:
|
||||
self.comp_checkbox.setEnabled(activate)
|
||||
|
||||
def setPermText(self, number, text=None, color='black'):
|
||||
if not 0 <= number < len(self.perm_labels):
|
||||
@@ -862,24 +864,9 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
|
||||
def plotWFData(self, wfdata, wfsyn=None, title=None, scaleddata=False, mapping=True,
|
||||
component='*', nth_sample=1, verbosity=0, method='normal', gain=1., shift_syn=0.2):
|
||||
def station_sort(nslc):
|
||||
"""Try to sort after station integer in case of a line array (e.g. active seismics)"""
|
||||
try:
|
||||
rval = sorted(nslc, key=lambda x: int(x.split('.')[1]))
|
||||
return rval
|
||||
except ValueError as e:
|
||||
# this is the standard case for seismological stations
|
||||
pass
|
||||
except Exception as e:
|
||||
print(f'Sorting by station integer failed with unknown exception: {e}')
|
||||
|
||||
# fallback to default sorting
|
||||
return sorted(nslc)
|
||||
|
||||
if not wfdata:
|
||||
print('Nothing to plot.')
|
||||
return
|
||||
|
||||
self.title = title
|
||||
self.clearPlotDict()
|
||||
self.wfstart, self.wfend = full_range(wfdata)
|
||||
@@ -897,14 +884,14 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
else:
|
||||
st_select = wfdata
|
||||
|
||||
# st_select, gaps = check_for_gaps_and_merge(st_select) #MP MP commented because probably done twice
|
||||
st_select, gaps = merge_stream(st_select)
|
||||
|
||||
# list containing tuples of network, station, channel (for sorting)
|
||||
nslc = []
|
||||
for trace in st_select:
|
||||
nslc.append(
|
||||
trace.get_id()) # (trace.stats.network, trace.stats.station, trace.stats.location trace.stats.channel))
|
||||
nslc = station_sort(nslc)
|
||||
nslc.sort()
|
||||
nslc.reverse()
|
||||
plots = []
|
||||
|
||||
@@ -959,7 +946,7 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
[time for index, time in enumerate(time_ax_syn) if not index % nth_sample] if st_syn else [])
|
||||
trace.data = np.array(
|
||||
[datum * gain + n for index, datum in enumerate(trace.data) if not index % nth_sample])
|
||||
trace_syn.data = np.array([datum + n for index, datum in enumerate(trace_syn.data)
|
||||
trace_syn.data = np.array([datum + n + shift_syn 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_syn.data))
|
||||
@@ -968,7 +955,7 @@ class WaveformWidgetPG(QtWidgets.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):
|
||||
'''
|
||||
@@ -990,7 +977,7 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
min_ = data.min(axis=1)
|
||||
max_ = data.max(axis=1)
|
||||
if remaining_samples:
|
||||
extreme_values = np.empty((npixel + 1, 2), dtype=float)
|
||||
extreme_values = np.empty((npixel + 1, 2), dtype=np.float)
|
||||
extreme_values[:-1, 0] = min_
|
||||
extreme_values[:-1, 1] = max_
|
||||
extreme_values[-1, 0] = \
|
||||
@@ -998,7 +985,7 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
extreme_values[-1, 1] = \
|
||||
trace.data[-remaining_samples:].max()
|
||||
else:
|
||||
extreme_values = np.empty((npixel, 2), dtype=float)
|
||||
extreme_values = np.empty((npixel, 2), dtype=np.float)
|
||||
extreme_values[:, 0] = min_
|
||||
extreme_values[:, 1] = max_
|
||||
data = extreme_values.flatten()
|
||||
@@ -1148,12 +1135,12 @@ class PylotCanvas(FigureCanvas):
|
||||
ax.set_xlim(self.cur_xlim)
|
||||
ax.set_ylim(self.cur_ylim)
|
||||
self.refreshPickDlgText()
|
||||
ax.figure.canvas.draw()
|
||||
ax.figure.canvas.draw_idle()
|
||||
|
||||
def panRelease(self, gui_event):
|
||||
self.press = None
|
||||
self.press_rel = None
|
||||
self.figure.canvas.draw()
|
||||
self.figure.canvas.draw_idle()
|
||||
|
||||
def panZoom(self, gui_event, threshold=2., factor=1.1):
|
||||
if not gui_event.x and not gui_event.y:
|
||||
@@ -1371,11 +1358,15 @@ class PylotCanvas(FigureCanvas):
|
||||
plot_positions[channel] = plot_pos
|
||||
return plot_positions
|
||||
|
||||
def plotWFData(self, wfdata, title=None, zoomx=None, zoomy=None,
|
||||
def plotWFData(self, wfdata, wfdata_compare=None, title=None, zoomx=None, zoomy=None,
|
||||
noiselevel=None, scaleddata=False, mapping=True,
|
||||
component='*', nth_sample=1, iniPick=None, verbosity=0,
|
||||
plot_additional=False, additional_channel=None, scaleToChannel=None,
|
||||
snr=None):
|
||||
def get_wf_dict(data: Stream = Stream(), linecolor = 'k', offset: float = 0., **plot_kwargs):
|
||||
return dict(data=data, linecolor=linecolor, offset=offset, plot_kwargs=plot_kwargs)
|
||||
|
||||
|
||||
ax = self.axes[0]
|
||||
ax.cla()
|
||||
|
||||
@@ -1386,21 +1377,33 @@ class PylotCanvas(FigureCanvas):
|
||||
settings = QSettings()
|
||||
compclass = SetChannelComponents.from_qsettings(settings)
|
||||
|
||||
linecolor = (0., 0., 0., 1.) if not self.style else self.style['linecolor']['rgba_mpl']
|
||||
|
||||
plot_streams = dict(wfdata=get_wf_dict(linecolor=linecolor, linewidth=0.7),
|
||||
wfdata_comp=get_wf_dict(offset=0.1, linecolor='b', alpha=0.7, linewidth=0.5))
|
||||
|
||||
if not component == '*':
|
||||
alter_comp = compclass.getCompPosition(component)
|
||||
# alter_comp = str(alter_comp[0])
|
||||
|
||||
st_select = wfdata.select(component=component)
|
||||
st_select += wfdata.select(component=alter_comp)
|
||||
plot_streams['wfdata']['data'] = wfdata.select(component=component)
|
||||
plot_streams['wfdata']['data'] += wfdata.select(component=alter_comp)
|
||||
if wfdata_compare:
|
||||
plot_streams['wfdata_comp']['data'] = wfdata_compare.select(component=component)
|
||||
plot_streams['wfdata_comp']['data'] += wfdata_compare.select(component=alter_comp)
|
||||
else:
|
||||
st_select = wfdata
|
||||
plot_streams['wfdata']['data'] = wfdata
|
||||
if wfdata_compare:
|
||||
plot_streams['wfdata_comp']['data'] = wfdata_compare
|
||||
|
||||
st_main = plot_streams['wfdata']['data']
|
||||
|
||||
if mapping:
|
||||
plot_positions = self.calcPlotPositions(st_select, compclass)
|
||||
plot_positions = self.calcPlotPositions(st_main, compclass)
|
||||
|
||||
# list containing tuples of network, station, channel and plot position (for sorting)
|
||||
nslc = []
|
||||
for plot_pos, trace in enumerate(st_select):
|
||||
for plot_pos, trace in enumerate(st_main):
|
||||
if not trace.stats.channel[-1] in ['Z', 'N', 'E', '1', '2', '3']:
|
||||
print('Warning: Unrecognized channel {}'.format(trace.stats.channel))
|
||||
continue
|
||||
@@ -1408,44 +1411,48 @@ class PylotCanvas(FigureCanvas):
|
||||
nslc.sort()
|
||||
nslc.reverse()
|
||||
|
||||
linecolor = (0., 0., 0., 1.) if not self.style else self.style['linecolor']['rgba_mpl']
|
||||
|
||||
for n, seed_id in enumerate(nslc):
|
||||
network, station, location, channel = seed_id.split('.')
|
||||
st = st_select.select(id=seed_id)
|
||||
trace = st[0].copy()
|
||||
if mapping:
|
||||
n = plot_positions[trace.stats.channel]
|
||||
if n > nmax:
|
||||
nmax = n
|
||||
if verbosity:
|
||||
msg = 'plotting %s channel of station %s' % (channel, station)
|
||||
print(msg)
|
||||
stime = trace.stats.starttime - wfstart
|
||||
time_ax = prepTimeAxis(stime, trace)
|
||||
if time_ax is not None:
|
||||
if scaleToChannel:
|
||||
st_scale = wfdata.select(channel=scaleToChannel)
|
||||
if st_scale:
|
||||
tr = st_scale[0]
|
||||
for wf_name, wf_dict in plot_streams.items():
|
||||
st_select = wf_dict.get('data')
|
||||
if not st_select:
|
||||
continue
|
||||
st = st_select.select(id=seed_id)
|
||||
trace = st[0].copy()
|
||||
if mapping:
|
||||
n = plot_positions[trace.stats.channel]
|
||||
if n > nmax:
|
||||
nmax = n
|
||||
if verbosity:
|
||||
msg = 'plotting %s channel of station %s' % (channel, station)
|
||||
print(msg)
|
||||
stime = trace.stats.starttime - wfstart
|
||||
time_ax = prepTimeAxis(stime, trace)
|
||||
if time_ax is not None:
|
||||
if scaleToChannel:
|
||||
st_scale = wfdata.select(channel=scaleToChannel)
|
||||
if st_scale:
|
||||
tr = st_scale[0]
|
||||
trace.detrend('constant')
|
||||
trace.normalize(np.max(np.abs(tr.data)) * 2)
|
||||
scaleddata = True
|
||||
if not scaleddata:
|
||||
trace.detrend('constant')
|
||||
trace.normalize(np.max(np.abs(tr.data)) * 2)
|
||||
scaleddata = True
|
||||
if not scaleddata:
|
||||
trace.detrend('constant')
|
||||
trace.normalize(np.max(np.abs(trace.data)) * 2)
|
||||
trace.normalize(np.max(np.abs(trace.data)) * 2)
|
||||
|
||||
times = [time for index, time in enumerate(time_ax) if not index % nth_sample]
|
||||
data = [datum + n for index, datum in enumerate(trace.data) if not index % nth_sample]
|
||||
ax.axhline(n, color="0.5", lw=0.5)
|
||||
ax.plot(times, data, color=linecolor, linewidth=0.7)
|
||||
if noiselevel is not None:
|
||||
for level in [-noiselevel[channel], noiselevel[channel]]:
|
||||
ax.plot([time_ax[0], time_ax[-1]],
|
||||
[n + level, n + level],
|
||||
color=linecolor,
|
||||
linestyle='dashed')
|
||||
self.setPlotDict(n, seed_id)
|
||||
offset = wf_dict.get('offset')
|
||||
|
||||
times = [time for index, time in enumerate(time_ax) if not index % nth_sample]
|
||||
data = [datum + n + offset for index, datum in enumerate(trace.data) if not index % nth_sample]
|
||||
ax.axhline(n, color="0.5", lw=0.5)
|
||||
ax.plot(times, data, color=wf_dict.get('linecolor'), **wf_dict.get('plot_kwargs'))
|
||||
if noiselevel is not None:
|
||||
for level in [-noiselevel[channel], noiselevel[channel]]:
|
||||
ax.plot([time_ax[0], time_ax[-1]],
|
||||
[n + level, n + level],
|
||||
color=wf_dict.get('linecolor'),
|
||||
linestyle='dashed')
|
||||
self.setPlotDict(n, seed_id)
|
||||
if plot_additional and additional_channel:
|
||||
compare_stream = wfdata.select(channel=additional_channel)
|
||||
if compare_stream:
|
||||
@@ -1568,96 +1575,6 @@ class PylotCanvas(FigureCanvas):
|
||||
self.draw()
|
||||
|
||||
|
||||
class SearchFileByExtensionDialog(QtWidgets.QDialog):
|
||||
def __init__(self, parent=None, label='Text: ', default_text='.xml', events=None):
|
||||
super(SearchFileByExtensionDialog, self).__init__(parent)
|
||||
self.events = events
|
||||
self.filepaths = []
|
||||
self.default_text = default_text
|
||||
self.label = label
|
||||
self.setButtons()
|
||||
self.setupUi()
|
||||
self.connectSignals()
|
||||
self.showPaths()
|
||||
self.refresh_timer = QTimer(self)
|
||||
self.refresh_timer.timeout.connect(self.showPaths)
|
||||
self.refresh_timer.start(10000)
|
||||
|
||||
self.resize(800, 450)
|
||||
|
||||
|
||||
def setupUi(self):
|
||||
self.main_layout = QtWidgets.QVBoxLayout()
|
||||
self.header_layout = QtWidgets.QHBoxLayout()
|
||||
#
|
||||
self.setLayout(self.main_layout)
|
||||
|
||||
# widgets inside the dialog
|
||||
self.textLabel = QtWidgets.QLabel(self.label)
|
||||
self.lineEdit = QtWidgets.QLineEdit(self.default_text)
|
||||
|
||||
# optional search button, currently disabled. List refreshed when text changes
|
||||
self.searchButton = QtWidgets.QPushButton('Search')
|
||||
self.searchButton.setVisible(False)
|
||||
|
||||
self.tableWidget = QtWidgets.QTableWidget()
|
||||
tableWidget = self.tableWidget
|
||||
tableWidget.setColumnCount(2)
|
||||
tableWidget.setRowCount(len(self.events))
|
||||
tableWidget.setHorizontalHeaderLabels(('Filename', 'Last modified'))
|
||||
tableWidget.setEditTriggers(tableWidget.NoEditTriggers)
|
||||
tableWidget.setSortingEnabled(True)
|
||||
header = tableWidget.horizontalHeader()
|
||||
header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
|
||||
header.setStretchLastSection(True)
|
||||
|
||||
self.statusText = QtWidgets.QLabel()
|
||||
|
||||
self.header_layout.addWidget(self.textLabel)
|
||||
self.header_layout.addWidget(self.lineEdit)
|
||||
self.header_layout.addWidget(self.searchButton)
|
||||
|
||||
self.main_layout.addLayout(self.header_layout)
|
||||
self.main_layout.addWidget(self.tableWidget)
|
||||
self.main_layout.addWidget(self.statusText)
|
||||
self.main_layout.addWidget(self._buttonbox)
|
||||
|
||||
def showPaths(self):
|
||||
self.filepaths = []
|
||||
fext = self.lineEdit.text()
|
||||
self.tableWidget.clearContents()
|
||||
for index, event in enumerate(self.events):
|
||||
filename = get_pylot_eventfile_with_extension(event, fext)
|
||||
if filename:
|
||||
self.filepaths.append(filename)
|
||||
ts = int(os.path.getmtime(filename))
|
||||
|
||||
# create QTableWidgetItems of filepath and last modification time
|
||||
fname_item = QtWidgets.QTableWidgetItem(f'{filename}')
|
||||
ts_item = QtWidgets.QTableWidgetItem(f'{datetime.datetime.fromtimestamp(ts)}')
|
||||
self.tableWidget.setItem(index, 0, fname_item)
|
||||
self.tableWidget.setItem(index, 1, ts_item)
|
||||
|
||||
# TODO: Idea -> only refresh if table contents changed. Use selection to load only a subset of files
|
||||
if len(self.filepaths) > 0:
|
||||
status_text = f'Found {len(self.filepaths)} eventfiles. Do you want to load them?'
|
||||
else:
|
||||
status_text = 'Did not find any files for specified file mask.'
|
||||
self.statusText.setText(status_text)
|
||||
|
||||
|
||||
def setButtons(self):
|
||||
self._buttonbox = QDialogButtonBox(QDialogButtonBox.Ok |
|
||||
QDialogButtonBox.Cancel)
|
||||
|
||||
def connectSignals(self):
|
||||
self._buttonbox.accepted.connect(self.accept)
|
||||
self._buttonbox.rejected.connect(self.reject)
|
||||
self.lineEdit.textChanged.connect(self.showPaths)
|
||||
self.searchButton.clicked.connect(self.showPaths)
|
||||
|
||||
|
||||
|
||||
class SingleTextLineDialog(QtWidgets.QDialog):
|
||||
def __init__(self, parent=None, label='Text: ', default_text='.xml'):
|
||||
super(SingleTextLineDialog, self).__init__(parent)
|
||||
@@ -1762,8 +1679,8 @@ class PhaseDefaults(QtWidgets.QDialog):
|
||||
class PickDlg(QDialog):
|
||||
update_picks = QtCore.Signal(dict)
|
||||
|
||||
def __init__(self, parent=None, data=None, station=None, network=None, location=None, picks=None,
|
||||
autopicks=None, rotate=False, parameter=None, embedded=False, metadata=None,
|
||||
def __init__(self, parent=None, data=None, data_compare=None, station=None, network=None, location=None, picks=None,
|
||||
autopicks=None, rotate=False, parameter=None, embedded=False, metadata=None, show_comp_data=False,
|
||||
event=None, filteroptions=None, model=None, wftype=None):
|
||||
super(PickDlg, self).__init__(parent, Qt.Window)
|
||||
self.orig_parent = parent
|
||||
@@ -1772,6 +1689,7 @@ class PickDlg(QDialog):
|
||||
# initialize attributes
|
||||
self.parameter = parameter
|
||||
self._embedded = embedded
|
||||
self.showCompData = show_comp_data
|
||||
self.station = station
|
||||
self.network = network
|
||||
self.location = location
|
||||
@@ -1810,22 +1728,6 @@ class PickDlg(QDialog):
|
||||
else:
|
||||
self.filteroptions = FILTERDEFAULTS
|
||||
self.pick_block = False
|
||||
self.nextStation = QtWidgets.QCheckBox('Continue with next station ')
|
||||
|
||||
# comparison channel
|
||||
self.compareChannel = QtWidgets.QComboBox()
|
||||
self.compareChannel.activated.connect(self.resetPlot)
|
||||
|
||||
# scale channel
|
||||
self.scaleChannel = QtWidgets.QComboBox()
|
||||
self.scaleChannel.activated.connect(self.resetPlot)
|
||||
|
||||
# initialize panning attributes
|
||||
self.press = None
|
||||
self.xpress = None
|
||||
self.ypress = None
|
||||
self.cur_xlim = None
|
||||
self.cur_ylim = None
|
||||
|
||||
# set attribute holding data
|
||||
if data is None or not data:
|
||||
@@ -1838,6 +1740,31 @@ class PickDlg(QDialog):
|
||||
raise Exception(errmsg)
|
||||
else:
|
||||
self.data = data
|
||||
self.data_compare = data_compare
|
||||
|
||||
self.nextStation = QtWidgets.QCheckBox('Continue with next station ')
|
||||
|
||||
# comparison channel
|
||||
self.referenceChannel = QtWidgets.QComboBox()
|
||||
self.referenceChannel.activated.connect(self.resetPlot)
|
||||
|
||||
# comparison channel
|
||||
self.compareCB = QtWidgets.QCheckBox()
|
||||
self.compareCB.setChecked(self.showCompData)
|
||||
self.compareCB.clicked.connect(self.switchCompData)
|
||||
self.compareCB.clicked.connect(self.resetPlot)
|
||||
self.compareCB.setVisible(bool(self.data_compare))
|
||||
|
||||
# scale channel
|
||||
self.scaleChannel = QtWidgets.QComboBox()
|
||||
self.scaleChannel.activated.connect(self.resetPlot)
|
||||
|
||||
# initialize panning attributes
|
||||
self.press = None
|
||||
self.xpress = None
|
||||
self.ypress = None
|
||||
self.cur_xlim = None
|
||||
self.cur_ylim = None
|
||||
|
||||
self.stime, self.etime = full_range(self.getWFData())
|
||||
|
||||
@@ -1850,12 +1777,12 @@ class PickDlg(QDialog):
|
||||
self.setupUi()
|
||||
|
||||
# fill compare and scale channels
|
||||
self.compareChannel.addItem('-', None)
|
||||
self.referenceChannel.addItem('-', None)
|
||||
self.scaleChannel.addItem('individual', None)
|
||||
|
||||
for trace in self.getWFData():
|
||||
channel = trace.stats.channel
|
||||
self.compareChannel.addItem(channel, trace)
|
||||
self.referenceChannel.addItem(channel, trace)
|
||||
if not channel[-1] in ['Z', 'N', 'E', '1', '2', '3']:
|
||||
print('Skipping unknown channel for scaling: {}'.format(channel))
|
||||
continue
|
||||
@@ -1872,7 +1799,7 @@ class PickDlg(QDialog):
|
||||
if self.wftype is not None:
|
||||
title += ' | ({})'.format(self.wftype)
|
||||
|
||||
self.multicompfig.plotWFData(wfdata=self.getWFData(),
|
||||
self.multicompfig.plotWFData(wfdata=self.getWFData(), wfdata_compare=self.getWFDataComp(),
|
||||
title=title)
|
||||
|
||||
self.multicompfig.setZoomBorders2content()
|
||||
@@ -2048,8 +1975,11 @@ class PickDlg(QDialog):
|
||||
_dialtoolbar.addWidget(est_label)
|
||||
_dialtoolbar.addWidget(self.plot_arrivals_button)
|
||||
_dialtoolbar.addSeparator()
|
||||
_dialtoolbar.addWidget(QtWidgets.QLabel('Compare to channel: '))
|
||||
_dialtoolbar.addWidget(self.compareChannel)
|
||||
_dialtoolbar.addWidget(QtWidgets.QLabel('Plot reference channel: '))
|
||||
_dialtoolbar.addWidget(self.referenceChannel)
|
||||
_dialtoolbar.addSeparator()
|
||||
_dialtoolbar.addWidget(QtWidgets.QLabel('Compare: '))
|
||||
_dialtoolbar.addWidget(self.compareCB)
|
||||
_dialtoolbar.addSeparator()
|
||||
_dialtoolbar.addWidget(QtWidgets.QLabel('Scaling: '))
|
||||
_dialtoolbar.addWidget(self.scaleChannel)
|
||||
@@ -2384,7 +2314,7 @@ class PickDlg(QDialog):
|
||||
def activatePicking(self):
|
||||
self.leave_rename_phase()
|
||||
self.renamePhaseAction.setEnabled(False)
|
||||
self.compareChannel.setEnabled(False)
|
||||
self.referenceChannel.setEnabled(False)
|
||||
self.scaleChannel.setEnabled(False)
|
||||
phase = self.currentPhase
|
||||
phaseID = self.getPhaseID(phase)
|
||||
@@ -2416,7 +2346,7 @@ class PickDlg(QDialog):
|
||||
self.disconnectPressEvent()
|
||||
self.multicompfig.connectEvents()
|
||||
self.renamePhaseAction.setEnabled(True)
|
||||
self.compareChannel.setEnabled(True)
|
||||
self.referenceChannel.setEnabled(True)
|
||||
self.scaleChannel.setEnabled(True)
|
||||
self.connect_pick_delete()
|
||||
self.draw()
|
||||
@@ -2489,6 +2419,12 @@ class PickDlg(QDialog):
|
||||
def getWFData(self):
|
||||
return self.data
|
||||
|
||||
def getWFDataComp(self):
|
||||
if self.showCompData:
|
||||
return self.data_compare
|
||||
else:
|
||||
return Stream()
|
||||
|
||||
def selectWFData(self, channel):
|
||||
component = channel[-1].upper()
|
||||
wfdata = Stream()
|
||||
@@ -2610,11 +2546,16 @@ class PickDlg(QDialog):
|
||||
|
||||
stime = self.getStartTime()
|
||||
|
||||
# copy data for plotting
|
||||
data = self.getWFData().copy()
|
||||
data = self.getPickPhases(data, phase)
|
||||
data.normalize()
|
||||
if not data:
|
||||
# copy wfdata for plotting
|
||||
wfdata = self.getWFData().copy()
|
||||
wfdata_comp = self.getWFDataComp().copy()
|
||||
wfdata = self.getPickPhases(wfdata, phase)
|
||||
wfdata_comp = self.getPickPhases(wfdata_comp, phase)
|
||||
for wfd in [wfdata, wfdata_comp]:
|
||||
if wfd:
|
||||
wfd.normalize()
|
||||
|
||||
if not wfdata:
|
||||
QtWidgets.QMessageBox.warning(self, 'No channel to plot',
|
||||
'No channel to plot for phase: {}. '
|
||||
'Make sure to select the correct channels for P and S '
|
||||
@@ -2622,14 +2563,16 @@ class PickDlg(QDialog):
|
||||
self.leave_picking_mode()
|
||||
return
|
||||
|
||||
# filter data and trace on which is picked prior to determination of SNR
|
||||
# filter wfdata and trace on which is picked prior to determination of SNR
|
||||
filterphase = self.currentFilterPhase()
|
||||
if filterphase:
|
||||
filteroptions = self.getFilterOptions(filterphase).parseFilterOptions()
|
||||
try:
|
||||
data.detrend('linear')
|
||||
data.filter(**filteroptions)
|
||||
# wfdata.filter(**filteroptions)# MP MP removed filtering of original data
|
||||
for wfd in [wfdata, wfdata_comp]:
|
||||
if wfd:
|
||||
wfd.detrend('linear')
|
||||
wfd.filter(**filteroptions)
|
||||
# wfdata.filter(**filteroptions)# MP MP removed filtering of original wfdata
|
||||
except ValueError as e:
|
||||
self.qmb = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Icon.Information,
|
||||
'Denied',
|
||||
@@ -2639,8 +2582,8 @@ class PickDlg(QDialog):
|
||||
snr = []
|
||||
noiselevels = {}
|
||||
# determine SNR and noiselevel
|
||||
for trace in data.traces:
|
||||
st = data.select(channel=trace.stats.channel)
|
||||
for trace in wfdata.traces:
|
||||
st = wfdata.select(channel=trace.stats.channel)
|
||||
stime_diff = trace.stats.starttime - stime
|
||||
result = getSNR(st, (noise_win, gap_win, signal_win), ini_pick - stime_diff)
|
||||
snr.append(result[0])
|
||||
@@ -2651,23 +2594,25 @@ class PickDlg(QDialog):
|
||||
noiselevel = nfac
|
||||
noiselevels[trace.stats.channel] = noiselevel
|
||||
|
||||
# prepare plotting of data
|
||||
for trace in data:
|
||||
t = prepTimeAxis(trace.stats.starttime - stime, trace)
|
||||
inoise = getnoisewin(t, ini_pick, noise_win, gap_win)
|
||||
trace = demeanTrace(trace, inoise)
|
||||
# upscale trace data in a way that each trace is vertically zoomed to noiselevel*factor
|
||||
channel = trace.stats.channel
|
||||
noiselevel = noiselevels[channel]
|
||||
noiseScaleFactor = self.calcNoiseScaleFactor(noiselevel, zoomfactor=5.)
|
||||
trace.data *= noiseScaleFactor
|
||||
noiselevels[channel] *= noiseScaleFactor
|
||||
# prepare plotting of wfdata
|
||||
for wfd in [wfdata, wfdata_comp]:
|
||||
if wfd:
|
||||
for trace in wfd:
|
||||
t = prepTimeAxis(trace.stats.starttime - stime, trace)
|
||||
inoise = getnoisewin(t, ini_pick, noise_win, gap_win)
|
||||
trace = demeanTrace(trace, inoise)
|
||||
# upscale trace wfdata in a way that each trace is vertically zoomed to noiselevel*factor
|
||||
channel = trace.stats.channel
|
||||
noiselevel = noiselevels[channel]
|
||||
noiseScaleFactor = self.calcNoiseScaleFactor(noiselevel, zoomfactor=5.)
|
||||
trace.data *= noiseScaleFactor
|
||||
noiselevels[channel] *= noiseScaleFactor
|
||||
|
||||
mean_snr = np.mean(snr)
|
||||
x_res = getResolutionWindow(mean_snr, parameter.get('extent'))
|
||||
|
||||
xlims = [ini_pick - x_res, ini_pick + x_res]
|
||||
ylims = list(np.array([-.5, .5]) + [0, len(data) - 1])
|
||||
ylims = list(np.array([-.5, .5]) + [0, len(wfdata) - 1])
|
||||
|
||||
title = self.getStation() + ' picking mode'
|
||||
title += ' | SNR: {}'.format(mean_snr)
|
||||
@@ -2675,9 +2620,10 @@ class PickDlg(QDialog):
|
||||
filtops_str = transformFilteroptions2String(filteroptions)
|
||||
title += ' | Filteroptions: {}'.format(filtops_str)
|
||||
|
||||
plot_additional = bool(self.compareChannel.currentText())
|
||||
additional_channel = self.compareChannel.currentText()
|
||||
self.multicompfig.plotWFData(wfdata=data,
|
||||
plot_additional = bool(self.referenceChannel.currentText())
|
||||
additional_channel = self.referenceChannel.currentText()
|
||||
self.multicompfig.plotWFData(wfdata=wfdata,
|
||||
wfdata_compare=wfdata_comp,
|
||||
title=title,
|
||||
zoomx=xlims,
|
||||
zoomy=ylims,
|
||||
@@ -3068,7 +3014,8 @@ class PickDlg(QDialog):
|
||||
self.cur_xlim = self.multicompfig.axes[0].get_xlim()
|
||||
self.cur_ylim = self.multicompfig.axes[0].get_ylim()
|
||||
# self.multicompfig.updateCurrentLimits()
|
||||
data = self.getWFData().copy()
|
||||
wfdata = self.getWFData().copy()
|
||||
wfdata_comp = self.getWFDataComp().copy()
|
||||
title = self.getStation()
|
||||
if filter:
|
||||
filtoptions = None
|
||||
@@ -3076,19 +3023,22 @@ class PickDlg(QDialog):
|
||||
filtoptions = self.getFilterOptions(self.getPhaseID(phase), gui_filter=True).parseFilterOptions()
|
||||
|
||||
if filtoptions is not None:
|
||||
data.detrend('linear')
|
||||
data.taper(0.02, type='cosine')
|
||||
data.filter(**filtoptions)
|
||||
for wfd in [wfdata, wfdata_comp]:
|
||||
if wfd:
|
||||
wfd.detrend('linear')
|
||||
wfd.taper(0.02, type='cosine')
|
||||
wfd.filter(**filtoptions)
|
||||
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()
|
||||
plot_additional = bool(self.referenceChannel.currentText())
|
||||
additional_channel = self.referenceChannel.currentText()
|
||||
scale_channel = self.scaleChannel.currentText()
|
||||
self.multicompfig.plotWFData(wfdata=data, title=title,
|
||||
self.multicompfig.plotWFData(wfdata=wfdata, wfdata_compare=wfdata_comp,
|
||||
title=title,
|
||||
zoomx=self.getXLims(),
|
||||
zoomy=self.getYLims(),
|
||||
plot_additional=plot_additional,
|
||||
@@ -3161,6 +3111,9 @@ class PickDlg(QDialog):
|
||||
self.resetZoom()
|
||||
self.refreshPlot()
|
||||
|
||||
def switchCompData(self):
|
||||
self.showCompData = self.compareCB.isChecked()
|
||||
|
||||
def refreshPlot(self):
|
||||
if self.autoFilterAction.isChecked():
|
||||
self.filterActionP.setChecked(False)
|
||||
@@ -3671,9 +3624,8 @@ class TuneAutopicker(QWidget):
|
||||
# wfdat = remove_underscores(wfdat)
|
||||
# rotate misaligned stations to ZNE
|
||||
# check for gaps and doubled channels
|
||||
wfdat, _ = check_for_gaps_and_merge(wfdat)
|
||||
# check for nans
|
||||
check_for_nan(wfdat)
|
||||
wfdat, gaps = merge_stream(wfdat)
|
||||
# check4gaps(wfdat)
|
||||
check4doubled(wfdat)
|
||||
wfdat = check4rotated(wfdat, self.parent().metadata, verbosity=0)
|
||||
# trim station components to same start value
|
||||
@@ -3772,11 +3724,13 @@ class TuneAutopicker(QWidget):
|
||||
location = None
|
||||
|
||||
wfdata = self.data.getWFData()
|
||||
wfdata_comp = self.data.getWFDataComp()
|
||||
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(),
|
||||
data_comp=wfdata_comp.select(station=station).copy(),
|
||||
station=station, network=network,
|
||||
location=location, parameter=self.parameter,
|
||||
picks=self.get_current_event_picks(station),
|
||||
@@ -3828,7 +3782,6 @@ class TuneAutopicker(QWidget):
|
||||
st = self.data.getWFData()
|
||||
tr = st.select(station=self.get_current_station())[0]
|
||||
starttime = tr.stats.starttime
|
||||
# create two lists with figure names and subindices (for subplots) to get the correct axes
|
||||
p_axes = [
|
||||
('mainFig', 0),
|
||||
('aicFig', 0),
|
||||
@@ -3861,7 +3814,7 @@ class TuneAutopicker(QWidget):
|
||||
self.plot_manual_pick_to_ax(ax=ax, picks=picks, phase='S',
|
||||
starttime=starttime, quality=qualitySpick)
|
||||
for canvas in self.parent().canvas_dict.values():
|
||||
canvas.draw()
|
||||
canvas.draw_idle()
|
||||
|
||||
def plot_manual_pick_to_ax(self, ax, picks, phase, starttime, quality):
|
||||
mpp = picks[phase]['mpp'] - starttime
|
||||
|
||||
Reference in New Issue
Block a user