Merge branch 'develop' into feature/additional_channel_display
This commit is contained in:
commit
975bd64266
108
PyLoT.py
108
PyLoT.py
@ -274,6 +274,10 @@ class MainWindow(QMainWindow):
|
||||
print_icon.addPixmap(QPixmap(':/icons/printer.png'))
|
||||
self.filter_icon = QIcon()
|
||||
self.filter_icon.addPixmap(QPixmap(':/icons/filter.png'))
|
||||
self.filter_icon_p = QIcon()
|
||||
self.filter_icon_p.addPixmap(QPixmap(':/icons/filter_p.png'))
|
||||
self.filter_icon_s = QIcon()
|
||||
self.filter_icon_s.addPixmap(QPixmap(':/icons/filter_s.png'))
|
||||
z_icon = QIcon()
|
||||
z_icon.addPixmap(QPixmap(':/icons/key_Z.png'))
|
||||
n_icon = QIcon()
|
||||
@ -368,15 +372,23 @@ class MainWindow(QMainWindow):
|
||||
self.setParameter,
|
||||
None, paraIcon,
|
||||
"Modify Parameter")
|
||||
self.filterAction = self.createAction(self, "&Filter ...",
|
||||
self.filterWaveformData,
|
||||
"Ctrl+F", self.filter_icon,
|
||||
"""Toggle un-/filtered waveforms
|
||||
to be displayed, according to the
|
||||
desired seismic phase.""", True)
|
||||
self.filterActionP = createAction(parent=self, text='Apply P Filter',
|
||||
slot=self.filterP,
|
||||
icon=self.filter_icon_p,
|
||||
tip='Toggle filtered/original'
|
||||
' waveforms',
|
||||
checkable=True,
|
||||
shortcut='P')
|
||||
self.filterActionS = createAction(parent=self, text='Apply S Filter',
|
||||
slot=self.filterS,
|
||||
icon=self.filter_icon_s,
|
||||
tip='Toggle filtered/original'
|
||||
' waveforms',
|
||||
checkable=True,
|
||||
shortcut='S')
|
||||
filterEditAction = self.createAction(self, "&Filter parameter ...",
|
||||
self.adjustFilterOptions,
|
||||
"Alt+F", self.filter_icon,
|
||||
"Ctrl+F", self.filter_icon,
|
||||
"""Adjust filter parameters.""")
|
||||
self.inventoryAction = self.createAction(self, "Select &Inventory ...",
|
||||
self.get_new_metadata,
|
||||
@ -502,8 +514,8 @@ class MainWindow(QMainWindow):
|
||||
self.updateFileMenu()
|
||||
|
||||
self.editMenu = self.menuBar().addMenu('&Edit')
|
||||
editActions = (self.filterAction, filterEditAction, None,
|
||||
self.selectPAction, self.selectSAction, None,
|
||||
editActions = (self.filterActionP, self.filterActionS, filterEditAction, None,
|
||||
#self.selectPAction, self.selectSAction, None,
|
||||
self.inventoryAction, self.initMapAction, None,
|
||||
prefsEventAction)
|
||||
#printAction) #TODO: print event?
|
||||
@ -1415,7 +1427,8 @@ class MainWindow(QMainWindow):
|
||||
return None
|
||||
|
||||
def getStime(self):
|
||||
return self._stime
|
||||
if self.get_data():
|
||||
return full_range(self.get_data().getWFData())[0]
|
||||
|
||||
def addActions(self, target, actions):
|
||||
for action in actions:
|
||||
@ -1589,18 +1602,9 @@ class MainWindow(QMainWindow):
|
||||
# else:
|
||||
# ans = False
|
||||
self.fnames = self.getWFFnames_from_eventbox()
|
||||
self.data.setWFData(self.fnames)
|
||||
wfdat = self.data.getWFData() # all available streams
|
||||
# remove possible underscores in station names
|
||||
wfdat = remove_underscores(wfdat)
|
||||
# check for gaps and doubled channels
|
||||
check4gaps(wfdat)
|
||||
check4doubled(wfdat)
|
||||
# check for stations with rotated components
|
||||
wfdat = check4rotated(wfdat, self.metadata, verbosity=0)
|
||||
# trim station components to same start value
|
||||
trim_station_components(wfdat, trim_start=True, trim_end=False)
|
||||
self._stime = full_range(self.get_data().getWFData())[0]
|
||||
self.data.setWFData(self.fnames,
|
||||
checkRotated=True,
|
||||
metadata=self.metadata)
|
||||
|
||||
def connectWFplotEvents(self):
|
||||
'''
|
||||
@ -1759,18 +1763,19 @@ class MainWindow(QMainWindow):
|
||||
self.disableSaveEventAction()
|
||||
self.draw()
|
||||
|
||||
def plotWaveformDataThread(self):
|
||||
def plotWaveformDataThread(self, filter=True):
|
||||
'''
|
||||
Open a modal thread to plot current waveform data.
|
||||
'''
|
||||
self.clearWaveformDataPlot()
|
||||
self.wfp_thread = Thread(self, self.plotWaveformData,
|
||||
arg=filter,
|
||||
progressText='Plotting waveform data...',
|
||||
pb_widget=self.mainProgressBarWidget)
|
||||
self.wfp_thread.finished.connect(self.finishWaveformDataPlot)
|
||||
self.wfp_thread.start()
|
||||
|
||||
def plotWaveformData(self):
|
||||
def plotWaveformData(self, filter=True):
|
||||
'''
|
||||
Plot waveform data to current plotWidget.
|
||||
'''
|
||||
@ -1782,8 +1787,10 @@ class MainWindow(QMainWindow):
|
||||
comp = self.getComponent()
|
||||
title = 'section: {0} components'.format(zne_text[comp])
|
||||
wfst = self.get_data().getWFData()
|
||||
if self.filterAction.isChecked():
|
||||
self.filterWaveformData(plot=False)
|
||||
if self.filterActionP.isChecked() and filter:
|
||||
self.filterWaveformData(plot=False, phase='P')
|
||||
elif self.filterActionS.isChecked() and filter:
|
||||
self.filterWaveformData(plot=False, phase='S')
|
||||
# wfst = self.get_data().getWFData().select(component=comp)
|
||||
# wfst += self.get_data().getWFData().select(component=alter_comp)
|
||||
plotWidget = self.getPlotWidget()
|
||||
@ -1823,19 +1830,48 @@ class MainWindow(QMainWindow):
|
||||
def pushFilterWF(self, param_args):
|
||||
self.get_data().filterWFData(param_args)
|
||||
|
||||
def filterWaveformData(self, plot=True):
|
||||
def filterP(self):
|
||||
self.filterActionS.setChecked(False)
|
||||
if self.filterActionP.isChecked():
|
||||
self.filterWaveformData(phase='P')
|
||||
else:
|
||||
self.resetWFData()
|
||||
|
||||
def filterS(self):
|
||||
self.filterActionP.setChecked(False)
|
||||
if self.filterActionS.isChecked():
|
||||
self.filterWaveformData(phase='S')
|
||||
else:
|
||||
self.resetWFData()
|
||||
|
||||
def resetWFData(self):
|
||||
self.get_data().resetWFData()
|
||||
self.plotWaveformDataThread()
|
||||
|
||||
def filterWaveformData(self, plot=True, phase=None):
|
||||
if not self.get_current_event():
|
||||
return
|
||||
|
||||
if self.get_data():
|
||||
if self.getFilterOptions() and self.filterAction.isChecked():
|
||||
kwargs = self.getFilterOptions()[self.getSeismicPhase()].parseFilterOptions()
|
||||
if not phase:
|
||||
if self.filterActionP.isChecked():
|
||||
phase = 'P'
|
||||
elif self.filterActionS.isChecked():
|
||||
phase = 'S'
|
||||
if self.getFilterOptions():
|
||||
if (phase == 'P' and self.filterActionP.isChecked()) or (phase == 'S' and self.filterActionS.isChecked()):
|
||||
kwargs = self.getFilterOptions()[phase].parseFilterOptions()
|
||||
self.pushFilterWF(kwargs)
|
||||
elif self.filterAction.isChecked():
|
||||
else:
|
||||
self.get_data().resetWFData()
|
||||
elif self.filterActionP.isChecked() or self.filterActionS.isChecked():
|
||||
self.adjustFilterOptions()
|
||||
else:
|
||||
self.get_data().resetWFData()
|
||||
if plot:
|
||||
self.plotWaveformDataThread()
|
||||
self.drawPicks()
|
||||
self.draw()
|
||||
self.plotWaveformDataThread(filter=False)
|
||||
#self.drawPicks()
|
||||
#self.draw()
|
||||
|
||||
def adjustFilterOptions(self):
|
||||
fstring = "Filter Options"
|
||||
@ -1844,7 +1880,7 @@ class MainWindow(QMainWindow):
|
||||
if self.filterDlg.exec_():
|
||||
filteroptions = self.filterDlg.getFilterOptions()
|
||||
self.setFilterOptions(filteroptions)
|
||||
if self.filterAction.isChecked():
|
||||
if self.filterActionP.isChecked() or self.filterActionS.isChecked():
|
||||
kwargs = self.getFilterOptions()[self.getSeismicPhase()].parseFilterOptions()
|
||||
self.pushFilterWF(kwargs)
|
||||
self.plotWaveformDataThread()
|
||||
@ -1925,7 +1961,7 @@ class MainWindow(QMainWindow):
|
||||
# '[{0}: {1} Hz]'.format(
|
||||
# self.getFilterOptions().getFilterType(),
|
||||
# self.getFilterOptions().getFreq()))
|
||||
# if self.filterAction.isChecked():
|
||||
# if self.filterActionP.isChecked() or self.filterActionS.isChecked():
|
||||
# self.filterWaveformData()
|
||||
|
||||
def getSeismicPhase(self):
|
||||
@ -2018,7 +2054,7 @@ class MainWindow(QMainWindow):
|
||||
autopicks=self.getPicksOnStation(station, 'auto'),
|
||||
metadata=self.metadata, event=event,
|
||||
filteroptions=self.filteroptions)
|
||||
if self.filterAction.isChecked():
|
||||
if self.filterActionP.isChecked() or self.filterActionS.isChecked():
|
||||
pickDlg.currentPhase = self.getSeismicPhase()
|
||||
pickDlg.filterWFData()
|
||||
pickDlg.nextStation.setChecked(nextStation)
|
||||
|
@ -1 +1 @@
|
||||
0ebc-dirty
|
||||
f483-dirty
|
||||
|
@ -12,7 +12,8 @@ from pylot.core.io.phases import readPILOTEvent, picks_from_picksdict, \
|
||||
picksdict_from_pilot, merge_picks
|
||||
from pylot.core.util.errors import FormatError, OverwriteError
|
||||
from pylot.core.util.event import Event
|
||||
from pylot.core.util.utils import fnConstructor, full_range
|
||||
from pylot.core.util.utils import fnConstructor, full_range, remove_underscores, check4gaps, check4doubled, \
|
||||
check4rotated, trim_station_components
|
||||
import pylot.core.loc.velest as velest
|
||||
|
||||
|
||||
@ -367,7 +368,7 @@ class Data(object):
|
||||
data.filter(**kwargs)
|
||||
self.dirty = True
|
||||
|
||||
def setWFData(self, fnames):
|
||||
def setWFData(self, fnames, checkRotated=False, metadata=None):
|
||||
"""
|
||||
Clear current waveform data and set given waveform data
|
||||
:param fnames: waveform data names to append
|
||||
@ -379,10 +380,26 @@ class Data(object):
|
||||
self.appendWFData(fnames)
|
||||
else:
|
||||
return False
|
||||
|
||||
# various pre-processing steps:
|
||||
# remove possible underscores in station names
|
||||
self.wfdata = remove_underscores(self.wfdata)
|
||||
# check for gaps and doubled channels
|
||||
check4gaps(self.wfdata)
|
||||
check4doubled(self.wfdata)
|
||||
# check for stations with rotated components
|
||||
if checkRotated and metadata is not None:
|
||||
self.wfdata = check4rotated(self.wfdata, metadata, verbosity=0)
|
||||
# trim station components to same start value
|
||||
trim_station_components(self.wfdata, trim_start=True, trim_end=False)
|
||||
|
||||
# make a copy of original data
|
||||
self.wforiginal = self.getWFData().copy()
|
||||
self.dirty = False
|
||||
return True
|
||||
|
||||
|
||||
|
||||
def appendWFData(self, fnames):
|
||||
"""
|
||||
Read waveform data from fnames and append it to current wf data
|
||||
|
@ -16,7 +16,8 @@ from pylot.core.io.inputs import PylotParameter
|
||||
from pylot.core.io.location import create_event, \
|
||||
create_magnitude
|
||||
from pylot.core.pick.utils import select_for_phase
|
||||
from pylot.core.util.utils import getOwner, full_range, four_digits
|
||||
from pylot.core.util.utils import getOwner, full_range, four_digits, transformFilteroptions2String, \
|
||||
transformFilterString4Export, backtransformFilterString
|
||||
|
||||
|
||||
def add_amplitudes(event, amplitudes):
|
||||
@ -235,6 +236,10 @@ def picksdict_from_picks(evt):
|
||||
network = pick.waveform_id.network_code
|
||||
mpp = pick.time
|
||||
spe = pick.time_errors.uncertainty
|
||||
if pick.filter_id:
|
||||
filter_id = backtransformFilterString(str(pick.filter_id.id))
|
||||
else:
|
||||
filter_id = None
|
||||
try:
|
||||
picker = str(pick.method_id)
|
||||
if picker.startswith('smi:local/'):
|
||||
@ -261,6 +266,7 @@ def picksdict_from_picks(evt):
|
||||
phase['channel'] = channel
|
||||
phase['network'] = network
|
||||
phase['picker'] = picker
|
||||
phase['filter_id'] = filter_id if filter_id is not None else ''
|
||||
|
||||
onsets[pick.phase_hint] = phase.copy()
|
||||
picksdict[picker][station] = onsets.copy()
|
||||
@ -312,6 +318,13 @@ def picks_from_picksdict(picks, creation_info=None):
|
||||
pick.waveform_id = ope.WaveformStreamID(station_code=station,
|
||||
channel_code=ccode,
|
||||
network_code=ncode)
|
||||
try:
|
||||
filter_id = phase['filteroptions']
|
||||
filter_id = transformFilterString4Export(filter_id)
|
||||
except KeyError as e:
|
||||
warnings.warn(e.message, RuntimeWarning)
|
||||
filter_id = ''
|
||||
pick.filter_id = filter_id
|
||||
try:
|
||||
polarity = phase['fm']
|
||||
if polarity == 'U' or '+':
|
||||
@ -328,7 +341,6 @@ def picks_from_picksdict(picks, creation_info=None):
|
||||
picks_list.append(pick)
|
||||
return picks_list
|
||||
|
||||
|
||||
def reassess_pilot_db(root_dir, db_dir, out_dir=None, fn_param=None, verbosity=0):
|
||||
import glob
|
||||
|
||||
|
@ -24,7 +24,7 @@ class Thread(QThread):
|
||||
if self.redirect_stdout:
|
||||
sys.stdout = self
|
||||
try:
|
||||
if self.arg:
|
||||
if self.arg is not None:
|
||||
self.data = self.func(self.arg)
|
||||
else:
|
||||
self.data = self.func()
|
||||
|
@ -391,6 +391,38 @@ def full_range(stream):
|
||||
return min_start, max_end
|
||||
|
||||
|
||||
def transformFilteroptions2String(filtopts):
|
||||
st = ''
|
||||
if not filtopts:
|
||||
return st
|
||||
if 'type' in filtopts.keys():
|
||||
st += '{}'.format(filtopts['type'])
|
||||
if 'freq' in filtopts.keys():
|
||||
st += ' | freq: {}'.format(filtopts['freq'])
|
||||
elif 'freqmin' in filtopts.keys() and 'freqmax' in filtopts.keys():
|
||||
st += ' | freqmin: {} | freqmax: {}'.format(filtopts['freqmin'], filtopts['freqmax'])
|
||||
for key, value in filtopts.items():
|
||||
if key in ['type', 'freq', 'freqmin', 'freqmax']:
|
||||
continue
|
||||
st += ' | {}: {}'.format(key, value)
|
||||
return st
|
||||
|
||||
|
||||
def transformFilterString4Export(st):
|
||||
st = st.replace('|', '//')
|
||||
st = st.replace(':', '/')
|
||||
st = st.replace(' ', '')
|
||||
return st
|
||||
|
||||
|
||||
def backtransformFilterString(st):
|
||||
st = st.split('smi:local/')
|
||||
st = st[1] if len(st) > 1 else st[0]
|
||||
st = st.replace('//', ' | ')
|
||||
st = st.replace('/', ': ')
|
||||
return st
|
||||
|
||||
|
||||
def getHash(time):
|
||||
"""
|
||||
takes a time object and returns the corresponding SHA1 hash of the formatted date string
|
||||
@ -1137,6 +1169,8 @@ def identifyPhase(phase):
|
||||
# common phase suffix for P and S
|
||||
common_P = ['P', 'p', 'R']
|
||||
common_S = ['S', 's']
|
||||
if phase is None:
|
||||
return False
|
||||
if phase[-1] in common_P:
|
||||
return 'P'
|
||||
if phase[-1] in common_S:
|
||||
|
@ -17,8 +17,6 @@ import time
|
||||
import numpy as np
|
||||
|
||||
from matplotlib.figure import Figure
|
||||
from pylot.core.util.utils import find_horizontals, identifyPhase, loopIdentifyPhase, trim_station_components, \
|
||||
identifyPhaseID, check4rotated, real_Bool, pick_color
|
||||
|
||||
try:
|
||||
from matplotlib.backends.backend_qt4agg import FigureCanvas
|
||||
@ -49,7 +47,9 @@ from pylot.core.util.defaults import OUTPUTFORMATS, FILTERDEFAULTS, \
|
||||
SetChannelComponents
|
||||
from pylot.core.util.utils import prepTimeAxis, full_range, scaleWFData, \
|
||||
demeanTrace, isSorted, findComboBoxIndex, clims, pick_linestyle_plt, pick_color_plt, \
|
||||
check4rotated, check4doubled, check4gaps, remove_underscores
|
||||
check4rotated, check4doubled, check4gaps, remove_underscores, find_horizontals, identifyPhase, \
|
||||
loopIdentifyPhase, trim_station_components, transformFilteroptions2String, \
|
||||
identifyPhaseID, real_Bool, pick_color
|
||||
from autoPyLoT import autoPyLoT
|
||||
from pylot.core.util.thread import Thread
|
||||
|
||||
@ -375,8 +375,8 @@ class ComparisonWidget(QWidget):
|
||||
ax = axes_dict[phase]['exp']
|
||||
xlims = ax.get_xlim()
|
||||
ylims = ax.get_ylim()
|
||||
ax.fill_between([xlims[0], 0], ylims[0], ylims[1], color=(0.9, 1.0, 0.9, 0.5), label='earlier than manual')
|
||||
ax.fill_between([0, xlims[1]], ylims[0], ylims[1], color=(1.0, 0.9, 0.9, 0.5), label='later than manual')
|
||||
#ax.fill_between([xlims[0], 0], ylims[0], ylims[1], color=(0.9, 1.0, 0.9, 0.5), label='earlier than manual')
|
||||
#ax.fill_between([0, xlims[1]], ylims[0], ylims[1], color=(1.0, 0.9, 0.9, 0.5), label='later than manual')
|
||||
legend = ax.legend()
|
||||
legend.draggable()
|
||||
|
||||
@ -1152,9 +1152,11 @@ class PickDlg(QDialog):
|
||||
self.components = 'ZNE'
|
||||
self.currentPhase = None
|
||||
self.phaseText = []
|
||||
self.phaseLines = []
|
||||
self.arrivals = []
|
||||
self.arrivalsText = []
|
||||
self.cidpick = []
|
||||
self.cidpress = None
|
||||
settings = QSettings()
|
||||
pylot_user = getpass.getuser()
|
||||
self._user = settings.value('user/Login', pylot_user)
|
||||
@ -1242,6 +1244,7 @@ class PickDlg(QDialog):
|
||||
|
||||
# init pick delete (with right click)
|
||||
self.connect_pick_delete()
|
||||
self.connect_mouse_motion()
|
||||
self.setWindowTitle('Pickwindow on station: {}'.format(self.getStation()))
|
||||
self.setWindowState(QtCore.Qt.WindowMaximized)
|
||||
|
||||
@ -1270,6 +1273,8 @@ class PickDlg(QDialog):
|
||||
home_icon.addPixmap(QPixmap(':/icons/zoom_0.png'))
|
||||
del_icon = QIcon()
|
||||
del_icon.addPixmap(QPixmap(':/icons/delete.png'))
|
||||
sync_icon = QIcon()
|
||||
sync_icon.addPixmap(QPixmap(':/icons/sync.png'))
|
||||
|
||||
# create actions
|
||||
self.filterActionP = createAction(parent=self, text='Apply P Filter',
|
||||
@ -1278,14 +1283,14 @@ class PickDlg(QDialog):
|
||||
tip='Toggle filtered/original'
|
||||
' waveforms',
|
||||
checkable=True,
|
||||
shortcut='Ctrl+F')
|
||||
shortcut='P')
|
||||
self.filterActionS = createAction(parent=self, text='Apply S Filter',
|
||||
slot=self.filterS,
|
||||
icon=filter_icon_s,
|
||||
tip='Toggle filtered/original'
|
||||
' waveforms',
|
||||
checkable=True,
|
||||
shortcut='Shift+F')
|
||||
shortcut='S')
|
||||
self.autoFilterAction = createAction(parent=self, text='Automatic Filtering',
|
||||
slot=self.toggleAutoFilter,
|
||||
icon=key_a_icon,
|
||||
@ -1302,6 +1307,10 @@ class PickDlg(QDialog):
|
||||
self.resetPicksAction = createAction(parent=self, text='Delete Picks',
|
||||
slot=self.delPicks, icon=del_icon,
|
||||
tip='Delete current picks.')
|
||||
self.renamePhaseAction = createAction(parent=self, text='Rename Phase',
|
||||
slot=self.initRenamePhase, icon=sync_icon,
|
||||
tip='Rename a Phase.', checkable=True,
|
||||
shortcut='R')
|
||||
|
||||
self.addPickPhases(menuBar)
|
||||
|
||||
@ -1330,6 +1339,8 @@ class PickDlg(QDialog):
|
||||
self.reject_button = QPushButton('&Reject')
|
||||
self.disable_ar_buttons()
|
||||
|
||||
self.statusbar = QtGui.QStatusBar(self)
|
||||
|
||||
# add hotkeys
|
||||
self._shortcut_space = QtGui.QShortcut(QtGui.QKeySequence(' '), self)
|
||||
self._shortcut_space.activated.connect(self.accept_button.clicked)
|
||||
@ -1352,6 +1363,7 @@ class PickDlg(QDialog):
|
||||
_dialtoolbar.addAction(self.resetZoomAction)
|
||||
_dialtoolbar.addSeparator()
|
||||
_dialtoolbar.addAction(self.resetPicksAction)
|
||||
_dialtoolbar.addAction(self.renamePhaseAction)
|
||||
_dialtoolbar.addSeparator()
|
||||
if self._embedded:
|
||||
manu_label = QLabel('Manual Onsets:')
|
||||
@ -1375,9 +1387,12 @@ class PickDlg(QDialog):
|
||||
# layout the innermost widget
|
||||
_innerlayout = QVBoxLayout()
|
||||
_innerinnerlayout = QtGui.QHBoxLayout()
|
||||
_lowerlayout = QHBoxLayout()
|
||||
_innerinnerlayout.addWidget(self.multicompfig)
|
||||
_innerinnerlayout.addWidget(self.phaseplot)
|
||||
_innerlayout.addLayout(_innerinnerlayout)
|
||||
_innerlayout.addLayout(_lowerlayout)
|
||||
_lowerlayout.addWidget(self.statusbar)
|
||||
|
||||
# add button box to the dialog
|
||||
_buttonbox = QDialogButtonBox(QDialogButtonBox.Ok |
|
||||
@ -1385,13 +1400,17 @@ class PickDlg(QDialog):
|
||||
|
||||
# merge widgets and layouts to establish the dialog
|
||||
if not self._embedded:
|
||||
_innerlayout.addWidget(_buttonbox)
|
||||
_lowerlayout.addWidget(_buttonbox)
|
||||
_outerlayout.addWidget(menuBar)
|
||||
_outerlayout.addWidget(_dialtoolbar)
|
||||
_outerlayout.addLayout(_innerlayout)
|
||||
_outerlayout.setStretch(0, 0)
|
||||
_outerlayout.setStretch(1, 0)
|
||||
_outerlayout.setStretch(2, 1)
|
||||
_lowerlayout.setStretch(0, 5)
|
||||
_lowerlayout.setStretch(1, 1)
|
||||
_innerlayout.setStretch(0, 1)
|
||||
_innerlayout.setStretch(1, 0)
|
||||
|
||||
# connect widget element signals with slots (methods to the dialog
|
||||
# object
|
||||
@ -1555,7 +1574,7 @@ class PickDlg(QDialog):
|
||||
|
||||
filterOptionsAction = createAction(parent=self, text="&Filter parameter ...",
|
||||
slot=self.filterOptions,
|
||||
shortcut='Alt+F',
|
||||
shortcut='Ctrl+F',
|
||||
icon=self.orig_parent.filter_icon)
|
||||
filterMenu = menuBar.addMenu('Filter')
|
||||
filterMenu.addAction(self.filterActionP)
|
||||
@ -1675,8 +1694,15 @@ class PickDlg(QDialog):
|
||||
self.deactivatePicking()
|
||||
|
||||
def activatePicking(self):
|
||||
self.leave_rename_phase()
|
||||
self.renamePhaseAction.setEnabled(False)
|
||||
phase = self.currentPhase
|
||||
color = pick_color_plt('manual', self.getPhaseID(phase))
|
||||
phaseID = self.getPhaseID(phase)
|
||||
if not phaseID:
|
||||
self.warn_unknown_phase(phase)
|
||||
self.leave_picking_mode()
|
||||
return
|
||||
color = pick_color_plt('manual', phaseID)
|
||||
self.multicompfig.set_frame_color(color)
|
||||
self.multicompfig.set_frame_linewidth(1.5)
|
||||
if self.zoomAction.isChecked():
|
||||
@ -1700,6 +1726,7 @@ class PickDlg(QDialog):
|
||||
|
||||
self.disconnectPressEvent()
|
||||
self.multicompfig.connectEvents()
|
||||
self.renamePhaseAction.setEnabled(True)
|
||||
self.connect_pick_delete()
|
||||
self.draw()
|
||||
|
||||
@ -1799,6 +1826,17 @@ class PickDlg(QDialog):
|
||||
self.resetPicks()
|
||||
self.refreshPlot()
|
||||
|
||||
def initRenamePhase(self):
|
||||
if self.renamePhaseAction.isChecked():
|
||||
self.multicompfig.disconnectEvents()
|
||||
self.multicompfig.set_frame_color('orange')
|
||||
self.draw()
|
||||
self.statusbar.showMessage('Click on a phase you want to rename.')
|
||||
else:
|
||||
self.multicompfig.set_frame_color()
|
||||
self.multicompfig.connectEvents()
|
||||
self.draw()
|
||||
|
||||
def setIniPick(self, gui_event):
|
||||
self.multicompfig.set_frame_color('green')
|
||||
trace_number = round(gui_event.ydata)
|
||||
@ -2006,41 +2044,30 @@ class PickDlg(QDialog):
|
||||
# save pick times for actual phase
|
||||
phasepicks = dict(epp=epp, lpp=lpp, mpp=mpp, spe=spe,
|
||||
picker='manual', channel=channel,
|
||||
network=wfdata[0].stats.network)
|
||||
network=wfdata[0].stats.network,
|
||||
filteroptions=transformFilteroptions2String(filteroptions))
|
||||
|
||||
try:
|
||||
oldphasepick = self.picks[phase]
|
||||
except KeyError:
|
||||
self.picks[phase] = phasepicks
|
||||
else:
|
||||
self.picks[phase] = phasepicks
|
||||
oepp = oldphasepick['epp']
|
||||
ompp = oldphasepick['mpp']
|
||||
olpp = oldphasepick['lpp']
|
||||
msg = """Warning old phase information for phase {phase} has been
|
||||
altered.\n
|
||||
New phase times:\n
|
||||
earliest possible pick: {epp}\n
|
||||
most probable pick: {mpp}\n
|
||||
latest possible pick: {lpp}\n
|
||||
\n
|
||||
Old phase times (overwritten):\n
|
||||
earliest possible pick: {oepp}\n
|
||||
most probable pick: {ompp}\n
|
||||
latest possible pick: {olpp}\n""".format(phase=phase,
|
||||
epp=epp,
|
||||
mpp=pick,
|
||||
lpp=lpp,
|
||||
oepp=oepp,
|
||||
ompp=ompp,
|
||||
olpp=olpp)
|
||||
saved = self.savePick(phase, phasepicks)
|
||||
if saved:
|
||||
self.setDirty(True)
|
||||
|
||||
self.disconnectPressEvent()
|
||||
self.enable_ar_buttons()
|
||||
self.zoomAction.setEnabled(True)
|
||||
#self.pick_block = self.togglePickBlocker()
|
||||
#self.pick_block = self.togglPickBlocker()
|
||||
self.leave_picking_mode()
|
||||
self.setDirty(True)
|
||||
|
||||
def savePick(self, phase, phasepicks):
|
||||
if not self.getPhaseID(phase):
|
||||
self.warn_unknown_phase(phase)
|
||||
return
|
||||
|
||||
self.picks[phase] = phasepicks
|
||||
return True
|
||||
|
||||
def warn_unknown_phase(self, phase=None):
|
||||
QtGui.QMessageBox.warning(self, 'Unknown phase ID',
|
||||
'Could not identify phase ID: {}.'.format(phase))
|
||||
|
||||
def disconnectPressEvent(self):
|
||||
self.multicompfig.mpl_disconnect(self.cidpress)
|
||||
@ -2050,6 +2077,7 @@ class PickDlg(QDialog):
|
||||
self.removePhaseText()
|
||||
self.drawPicks(picktype='manual')
|
||||
self.drawPicks(picktype='auto')
|
||||
self.draw()
|
||||
|
||||
def drawPicks(self, phase=None, picktype='manual', textOnly=False, picks=None):
|
||||
# plotting picks
|
||||
@ -2091,18 +2119,19 @@ class PickDlg(QDialog):
|
||||
color = pick_color_plt(picktype, phaseID, quality)
|
||||
if not textOnly:
|
||||
linestyle_mpp, width_mpp = pick_linestyle_plt(picktype, 'mpp')
|
||||
ax.plot([mpp, mpp], ylims, color=color, linestyle=linestyle_mpp, linewidth=width_mpp,
|
||||
vl = ax.axvline(mpp, ylims[0], ylims[1], color=color, linestyle=linestyle_mpp, linewidth=width_mpp,
|
||||
label='{}-Pick (quality: {})'.format(phase, quality), picker=5)
|
||||
self.phaseLines.append(vl)
|
||||
if spe:
|
||||
ax.fill_between([mpp-spe, mpp+spe], ylims[0], ylims[1],
|
||||
alpha=.25, color=color, label='{}-SPE'.format(phase))
|
||||
if picks['epp']:
|
||||
linestyle_epp, width_epp = pick_linestyle_plt(picktype, 'epp')
|
||||
ax.plot([epp, epp], ylims, color=color, linestyle=linestyle_epp,
|
||||
ax.axvline(epp, ylims[0], ylims[1], color=color, linestyle=linestyle_epp,
|
||||
linewidth=width_epp, label='{}-EPP'.format(phase))
|
||||
if picks['lpp']:
|
||||
linestyle_lpp, width_lpp = pick_linestyle_plt(picktype, 'lpp')
|
||||
ax.plot([lpp, lpp], ylims, color=color, linestyle=linestyle_lpp,
|
||||
ax.axvline(lpp, ylims[0], ylims[1], color=color, linestyle=linestyle_lpp,
|
||||
linewidth=width_lpp, label='{}-LPP'.format(phase))
|
||||
# else:
|
||||
# ax.plot([mpp, mpp], ylims, color=color, linestyle=linestyle_mpp, linewidth=width_mpp,
|
||||
@ -2115,8 +2144,9 @@ class PickDlg(QDialog):
|
||||
if not textOnly:
|
||||
ax.plot(mpp, ylims[1], color=color, marker='v')
|
||||
ax.plot(mpp, ylims[0], color=color, marker='^')
|
||||
ax.vlines(mpp, ylims[0], ylims[1], color=color, linestyle=linestyle_mpp, linewidth=width_mpp,
|
||||
vl = ax.axvline(mpp, ylims[0], ylims[1], color=color, linestyle=linestyle_mpp, linewidth=width_mpp,
|
||||
picker=5, label='{}-Autopick (quality: {})'.format(phase, quality))
|
||||
self.phaseLines.append(vl)
|
||||
# append phase text (if textOnly: draw with current ylims)
|
||||
self.phaseText.append(ax.text(mpp, ylims[1], phase, color=color))
|
||||
else:
|
||||
@ -2124,24 +2154,121 @@ class PickDlg(QDialog):
|
||||
|
||||
ax.legend(loc=1)
|
||||
|
||||
def connect_mouse_motion(self):
|
||||
self.cidmotion = self.multicompfig.mpl_connect(
|
||||
'motion_notify_event', self.on_motion)
|
||||
|
||||
def connect_pick_delete(self):
|
||||
self.cidpick = self.multicompfig.mpl_connect('pick_event', self.onpick_delete)
|
||||
self.cidpick = self.multicompfig.mpl_connect('pick_event', self.onpick)
|
||||
self.cidpick = self.multicompfig.mpl_connect('motion_notify_event', self.on_hover_info)
|
||||
|
||||
def disconnect_pick_delete(self):
|
||||
if hasattr(self, 'cidpick'):
|
||||
self.multicompfig.mpl_disconnect(self.cidpick)
|
||||
|
||||
def on_motion(self, event):
|
||||
x = event.xdata
|
||||
if x is not None:
|
||||
time_code = 'T = {}, t = {} [s]'.format(self.stime+x, x)
|
||||
user_help = ' - Left-Click to Drag | Right-Click to Pan-Zoom |' \
|
||||
' Mousewheel to Zoom | Middle-Click to Delete Pick'
|
||||
self.statusbar.showMessage(time_code + user_help)
|
||||
|
||||
def onpick(self, event):
|
||||
if event.mouseevent.button == 1:
|
||||
self.onpick_info(event)
|
||||
elif event.mouseevent.button == 2:
|
||||
self.onpick_delete(event)
|
||||
|
||||
def on_hover_info(self, event):
|
||||
if not any([phase.contains(event)[0] for phase in self.phaseLines]):
|
||||
return
|
||||
x = event.xdata
|
||||
if not x:
|
||||
return
|
||||
allpicks, pick_rel, phase, picktype = self.identify_selected_picks(x)
|
||||
pick = allpicks[picktype][phase]
|
||||
message = '{} {}-pick'.format(picktype, phase)
|
||||
if 'mpp' in pick:
|
||||
message += ', MPP: {}'.format(pick['mpp'])
|
||||
if 'spe' in pick:
|
||||
message += ', SPE: {} [s]'.format(pick['spe'])
|
||||
if 'filteroptions' in pick:
|
||||
message += ', FILTER: {}'.format(pick['filteroptions'])
|
||||
x = event.x
|
||||
y = event.y
|
||||
y = self.size().height() - y
|
||||
pt = self.mapToGlobal(QtCore.QPoint(x, y))
|
||||
QtGui.QToolTip.showText(pt, message)
|
||||
|
||||
def onpick_info(self, event):
|
||||
if not event.mouseevent.button == 1:
|
||||
return
|
||||
x = event.mouseevent.xdata
|
||||
allpicks, pick_rel, phase, picktype = self.identify_selected_picks(x)
|
||||
pick = allpicks[picktype][phase]
|
||||
message = '{} {}-pick'.format(picktype, phase)
|
||||
if 'mpp' in pick:
|
||||
message += ', MPP: {}'.format(pick['mpp'])
|
||||
if 'spe' in pick:
|
||||
message += ', SPE: {}'.format(pick['spe'])
|
||||
if 'filteroptions' in pick:
|
||||
message += ', FILTER: {}'.format(pick['filteroptions'])
|
||||
|
||||
if self.renamePhaseAction.isChecked():
|
||||
self.renamePhase(picktype, phase)
|
||||
|
||||
self.statusbar.showMessage(message, 10e3)
|
||||
|
||||
def onpick_delete(self, event):
|
||||
if not event.mouseevent.button == 3:
|
||||
if not event.mouseevent.button == 2:
|
||||
return
|
||||
x = event.mouseevent.xdata
|
||||
self.remove_pick_by_x(x)
|
||||
self.refreshPlot()
|
||||
|
||||
def renamePhase(self, picktype, phase):
|
||||
allpicks = {'manual': self.picks,
|
||||
'auto': self.autopicks}
|
||||
picks = allpicks[picktype]
|
||||
dialog = QtGui.QInputDialog(parent=self)
|
||||
new_phase, executed = dialog.getText(self, 'Rename phase', 'Rename phase {} to:'.format(phase))
|
||||
if executed:
|
||||
try:
|
||||
self.renamePhaseInDict(picks, phase, new_phase)
|
||||
except KeyError as e:
|
||||
QtGui.QMessageBox.warning(self, 'Could not rename phase',
|
||||
'Could not rename phase {} to {}: {}'.format(phase, new_phase, e))
|
||||
self.leave_rename_phase()
|
||||
self.refreshPlot()
|
||||
|
||||
def renamePhaseInDict(self, picks, phase_old, phase_new):
|
||||
if phase_new in picks:
|
||||
raise KeyError('New phase ID already assigned.')
|
||||
picks_new = picks[phase_old].copy()
|
||||
saved = self.savePick(phase_new, picks_new)
|
||||
if saved:
|
||||
picks.pop(phase_old)
|
||||
self.setDirty(True)
|
||||
|
||||
def leave_rename_phase(self):
|
||||
self.renamePhaseAction.setChecked(False)
|
||||
self.multicompfig.set_frame_color()
|
||||
self.multicompfig.connectEvents()
|
||||
|
||||
def remove_pick_by_x(self, x):
|
||||
if not self.picks and not self.autopicks:
|
||||
return
|
||||
# init empty list and get station starttime
|
||||
allpicks, pick_rel, phase, picktype = self.identify_selected_picks(x)
|
||||
# delete the value from corresponding dictionary
|
||||
allpicks[picktype].pop(phase)
|
||||
# information output
|
||||
msg = 'Deleted {} pick for phase {}, at timestamp {} (relative time: {} s)'
|
||||
print(msg.format(picktype, phase, self.getStartTime()+pick_rel, pick_rel))
|
||||
self.setDirty(True)
|
||||
|
||||
def identify_selected_picks(self, x):
|
||||
# init empty list and get stat5ion starttime
|
||||
X = []
|
||||
starttime = self.getStartTime()
|
||||
# init dictionaries to iterate through and iterate over them
|
||||
@ -2159,12 +2286,9 @@ class PickDlg(QDialog):
|
||||
index, value = min(enumerate([val[0] for val in X]), key=lambda y: abs(y[1] - x))
|
||||
# unpack the found value
|
||||
pick_rel, phase, picktype = X[index]
|
||||
# delete the value from corresponding dictionary
|
||||
allpicks[picktype].pop(phase)
|
||||
# information output
|
||||
msg = 'Deleted {} pick for phase {}, at timestamp {} (relative time: {} s)'
|
||||
print(msg.format(picktype, phase, starttime+pick_rel, pick_rel))
|
||||
self.setDirty(True)
|
||||
return allpicks, pick_rel, phase, picktype
|
||||
|
||||
|
||||
|
||||
def drawPhaseText(self):
|
||||
self.drawPicks(picktype='manual', textOnly=True)
|
||||
@ -2219,11 +2343,8 @@ class PickDlg(QDialog):
|
||||
data.detrend('linear')
|
||||
data.taper(0.02, type='cosine')
|
||||
data.filter(**filtoptions)
|
||||
title += ' | {} filtered |'.format(filtoptions['type'])
|
||||
for key, value in filtoptions.items():
|
||||
if key == 'type':
|
||||
continue
|
||||
title += ' {}: {} |'.format(key, value)
|
||||
filtops_str = transformFilteroptions2String(filtoptions)
|
||||
title += ' | Filteroptions: {}'.format(filtops_str)
|
||||
self.multicompfig.plotWFData(wfdata=data, title=title,
|
||||
zoomx=self.getXLims(),
|
||||
zoomy=self.getYLims(),
|
||||
@ -2258,10 +2379,17 @@ class PickDlg(QDialog):
|
||||
if self.autoFilterAction.isChecked():
|
||||
self.filterActionP.setChecked(False)
|
||||
self.filterActionS.setChecked(False)
|
||||
data = self.getWFData().copy()
|
||||
title = self.getStation()
|
||||
filter = self.filterActionP.isChecked or self.filterActionS.isChecked()
|
||||
self.plotWFData(filter=filter)
|
||||
# data = self.getWFData().copy()
|
||||
# title = self.getStation()
|
||||
filter = False
|
||||
phase = None
|
||||
if self.filterActionP.isChecked():
|
||||
phase = 'P'
|
||||
filter = True
|
||||
if self.filterActionS.isChecked():
|
||||
phase = 'S'
|
||||
filter = True
|
||||
self.plotWFData(phase=phase, filter=filter)
|
||||
|
||||
def resetZoom(self):
|
||||
ax = self.multicompfig.axes[0]
|
||||
@ -2866,7 +2994,7 @@ class TuneAutopicker(QWidget):
|
||||
|
||||
y_top = 0.9 * ax.get_ylim()[1]
|
||||
y_bot = 0.9 * ax.get_ylim()[0]
|
||||
self._manual_pick_plots.append(ax.vlines(mpp, y_bot, y_top,
|
||||
self._manual_pick_plots.append(ax.axvline(mpp, y_bot, y_top,
|
||||
color=color, linewidth=2,
|
||||
label='manual {} Onset (quality: {})'.format(phase, quality)))
|
||||
self._manual_pick_plots.append(ax.plot([mpp - 0.5, mpp + 0.5],
|
||||
|
Loading…
Reference in New Issue
Block a user