Merge branch 'develop' into filterOptions

This commit is contained in:
2017-07-04 10:19:42 +02:00
51 changed files with 98966 additions and 71340 deletions

View File

@@ -1 +0,0 @@
97ee-dirty

View File

@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
"""
Created autumn/winter 2015.
Revised/extended summer 2017.
:author: Ludger Küperkoch / MAGS2 EP3 working group
"""
@@ -115,23 +116,30 @@ class Magnitude(object):
def calc(self):
pass
def updated_event(self):
self.event.magnitudes.append(self.net_magnitude())
def updated_event(self, magscaling=None):
self.event.magnitudes.append(self.net_magnitude(magscaling))
return self.event
def net_magnitude(self):
def net_magnitude(self, magscaling=None):
if self:
# TODO if an average Magnitude instead of the median is calculated
# StationMagnitudeContributions should be added to the returned
# Magnitude object
# mag_error => weights (magnitude error estimate from peak_to_peak, calcsourcespec?)
# weights => StationMagnitdeContribution
mag = ope.Magnitude(
mag=np.median([M.mag for M in self.magnitudes.values()]),
magnitude_type=self.type,
origin_id=self.origin_id,
station_count=len(self.magnitudes),
azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap)
if magscaling is not None and str(magscaling) is not '[0.0, 0.0]':
# scaling necessary
print("Scaling network magnitude ...")
mag = ope.Magnitude(
mag=np.median([M.mag for M in self.magnitudes.values()]) *\
magscaling[0] + magscaling[1],
magnitude_type=self.type,
origin_id=self.origin_id,
station_count=len(self.magnitudes),
azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap)
else:
# no saling necessary
mag = ope.Magnitude(
mag=np.median([M.mag for M in self.magnitudes.values()]),
magnitude_type=self.type,
origin_id=self.origin_id,
station_count=len(self.magnitudes),
azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap)
return mag
return None
@@ -153,7 +161,7 @@ class LocalMagnitude(Magnitude):
_amplitudes = dict()
def __init__(self, stream, event, calc_win, wascaling=None, verbosity=False, iplot=0):
def __init__(self, stream, event, calc_win, wascaling, verbosity=False, iplot=0):
super(LocalMagnitude, self).__init__(stream, event, verbosity, iplot)
self._calc_win = calc_win
@@ -207,6 +215,8 @@ class LocalMagnitude(Magnitude):
th = np.arange(0, len(sqH) * dt, dt)
# get maximum peak within pick window
iwin = getsignalwin(th, t0 - stime, self.calc_win)
ii = min([iwin[len(iwin)-1], len(th)])
iwin = iwin[0:ii]
wapp = np.max(sqH[iwin])
if self.verbose:
print("Determined Wood-Anderson peak-to-peak amplitude for station {0}: {1} "
@@ -257,12 +267,13 @@ class LocalMagnitude(Magnitude):
self.amplitudes = (station, amplitude)
# using standard Gutenberg-Richter relation
# or scale WA amplitude with given scaling relation
if self.wascaling == None:
if str(self.wascaling) == '[0.0, 0.0, 0.0]':
print("Calculating original Richter magnitude ...")
magnitude = ope.StationMagnitude(mag=np.log10(a0) \
+ richter_magnitude_scaling(delta))
else:
print("Calculating scaled local magnitude ...")
a0 = a0 * 1e03 # mm to nm (see Havskov & Ottemöller, 2010)
magnitude = ope.StationMagnitude(mag=np.log10(a0) \
+ self.wascaling[0] * np.log10(delta) + self.wascaling[1]
* delta + self.wascaling[2])

View File

@@ -6,11 +6,12 @@ import os
from obspy import read_events
from obspy.core import read, Stream, UTCDateTime
from obspy.io.sac import SacIOError
from obspy.core.event import Event
from obspy.core.event import Event as ObsPyEvent
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.utils import fnConstructor, full_range
from pylot.core.util.event import Event
class Data(object):
"""
@@ -33,7 +34,7 @@ class Data(object):
self.comp = 'Z'
self.wfdata = Stream()
self._new = False
if isinstance(evtdata, Event):
if isinstance(evtdata, ObsPyEvent) or isinstance(evtdata, Event):
pass
elif isinstance(evtdata, dict):
evt = readPILOTEvent(**evtdata)
@@ -49,7 +50,7 @@ class Data(object):
if 'Unknown format for file' in e.message:
if 'PHASES' in evtdata:
picks = picksdict_from_pilot(evtdata)
evtdata = Event()
evtdata = ObsPyEvent()
evtdata.picks = picks_from_picksdict(picks)
elif 'LOC' in evtdata:
raise NotImplementedError('PILOT location information '
@@ -61,7 +62,7 @@ class Data(object):
raise e
else: # create an empty Event object
self.setNew()
evtdata = Event()
evtdata = ObsPyEvent()
evtdata.picks = []
self.evtdata = evtdata
self.wforiginal = None
@@ -73,6 +74,8 @@ class Data(object):
def __add__(self, other):
assert isinstance(other, Data), "operands must be of same type 'Data'"
rs_id = self.get_evt_data().get('resource_id')
rs_id_other = other.get_evt_data().get('resource_id')
if other.isNew() and not self.isNew():
picks_to_add = other.get_evt_data().picks
old_picks = self.get_evt_data().picks
@@ -84,7 +87,7 @@ class Data(object):
self.evtdata = new.get_evt_data()
elif self.isNew() and other.isNew():
pass
elif self.get_evt_data().get('id') == other.get_evt_data().get('id'):
elif rs_id == rs_id_other:
other.setNew()
return self + other
else:
@@ -95,7 +98,7 @@ class Data(object):
def getPicksStr(self):
picks_str = ''
for pick in self.get_evt_data().picks:
picks_str += str(pick) + '\n'
picks_str += str(PyLoT) + '\n'
return picks_str
def getParent(self):
@@ -144,12 +147,13 @@ class Data(object):
# handle forbidden filenames especially on windows systems
return fnConstructor(str(ID))
def exportEvent(self, fnout, fnext='.xml'):
def exportEvent(self, fnout, fnext='.xml', fcheck='auto'):
"""
:param fnout:
:param fnext:
:param fcheck:
:raise KeyError:
"""
from pylot.core.util.defaults import OUTPUTFORMATS
@@ -160,13 +164,71 @@ class Data(object):
errmsg = '{0}; selected file extension {1} not ' \
'supported'.format(e, fnext)
raise FormatError(errmsg)
# check for already existing xml-file
if fnext == '.xml':
if os.path.isfile(fnout + fnext):
print("xml-file already exists! Check content ...")
cat_old = read_events(fnout + fnext)
checkflag = 0
for j in range(len(cat_old.events[0].picks)):
if cat_old.events[0].picks[j].method_id.id.split('/')[1] == fcheck:
print("Found %s pick(s), append to new catalog." % fcheck)
checkflag = 1
break
if checkflag == 1:
self.get_evt_data().write(fnout + fnext, format=evtformat)
cat_new = read_events(fnout + fnext)
cat_new.append(cat_old.events[0])
cat_new.write(fnout + fnext, format=evtformat)
else:
self.get_evt_data().write(fnout + fnext, format=evtformat)
else:
self.get_evt_data().write(fnout + fnext, format=evtformat)
# try exporting event via ObsPy
try:
self.get_evt_data().write(fnout + fnext, format=evtformat)
except KeyError as e:
raise KeyError('''{0} export format
not implemented: {1}'''.format(evtformat, e))
else:
# check for stations picked automatically as well as manually
# Prefer manual picks!
evtdata_copy = self.get_evt_data().copy()
evtdata_org = self.get_evt_data()
for i in range(len(evtdata_org.picks)):
if evtdata_org.picks[i].method_id == 'manual':
mstation = evtdata_org.picks[i].waveform_id.station_code
mstation_ext = mstation + '_'
for k in range(len(evtdata_copy.picks)):
if evtdata_copy.picks[k].waveform_id.station_code == mstation or \
evtdata_copy.picks[k].waveform_id.station_code == mstation_ext and \
evtdata_copy.picks[k].method_id == 'auto':
del evtdata_copy.picks[k]
break
lendiff = len(evtdata_org.picks) - len(evtdata_copy.picks)
if lendiff is not 0:
print("Manual as well as automatic picks available. Prefered the {} manual ones!".format(lendiff))
if fnext == '.obs':
try:
evtdata_copy.write(fnout + fnext, format=evtformat)
# write header afterwards
evid = str(evtdata_org.resource_id).split('/')[1]
header = '# EQEVENT: Label: EQ%s Loc: X 0.00 Y 0.00 Z 10.00 OT 0.00 \n' % evid
nllocfile = open(fnout + fnext)
l = nllocfile.readlines()
nllocfile.close()
l.insert(0, header)
nllocfile = open(fnout + fnext, 'w')
nllocfile.write("".join(l))
nllocfile.close()
except KeyError as e:
raise KeyError('''{0} export format
not implemented: {1}'''.format(evtformat, e))
if fnext == '.cnv':
try:
evtdata_org.write(fnout + fnext, format=evtformat)
except KeyError as e:
raise KeyError('''{0} export format
not implemented: {1}'''.format(evtformat, e))
def getComp(self):
"""
@@ -279,12 +341,12 @@ class Data(object):
def setEvtData(self, event):
self.evtdata = event
def applyEVTData(self, data, type='pick', authority_id='rub'):
def applyEVTData(self, data, typ='pick', authority_id='rub'):
"""
:param data:
:param type:
:param typ:
:param authority_id:
:raise OverwriteError:
"""
@@ -326,19 +388,27 @@ class Data(object):
information on the event to the actual data
:param event:
"""
if not self.isNew():
if self.isNew():
self.setEvtData(event)
else:
# prevent overwriting original pick information
picks = copy.deepcopy(self.get_evt_data().picks)
event_old = self.get_evt_data()
print(event_old.resource_id, event.resource_id)
if not event_old.resource_id == event.resource_id:
print("WARNING: Missmatch in event resource id's: {} and {}".format(
event_old.resource_id,
event.resource_id))
picks = copy.deepcopy(event_old.picks)
event = merge_picks(event, picks)
# apply event information from location
self.get_evt_data().update(event)
event_old.update(event)
applydata = {'pick': applyPicks,
'event': applyEvent}
applydata[type](data)
applydata[typ](data)
self._new = False
class GenericDataStructure(object):

View File

@@ -14,7 +14,7 @@ defaults = {'rootpath': {'type': str,
'value': ''},
'eventID': {'type': str,
'tooltip': 'event ID for single event processing',
'tooltip': 'event ID for single event processing (* for all events found in database)',
'value': ''},
'extent': {'type': str,
@@ -278,12 +278,14 @@ defaults = {'rootpath': {'type': str,
'value': 1.0},
'WAscaling': {'type': (float, float, float),
'tooltip': 'Scaling relation (log(Ao)+Alog(r)+Br+C) of Wood-Anderson amplitude Ao [nm]',
'value': (1.0, 1.0, 1.0)},
'tooltip': 'Scaling relation (log(Ao)+Alog(r)+Br+C) of Wood-Anderson amplitude Ao [nm] \
If zeros are set, original Richter magnitude is calculated!',
'value': (0., 0., 0.)},
'magscaling': {'type': (float, float),
'tooltip': 'Scaling relation for derived local magnitude [a*Ml+b]',
'value': (1.0, 1.0)},
'tooltip': 'Scaling relation for derived local magnitude [a*Ml+b]. \
If zeros are set, no scaling of network magnitude is applied!',
'value': (0., 0.)}
'minfreq': {'type': float,
'tooltip': 'Lower filter frequency',

View File

@@ -222,26 +222,25 @@ class PylotParameter(object):
# for key, value in self.iteritems():
# lines.append('{key}\t{value}\n'.format(key=key, value=value))
# fid_out.writelines(lines)
header = ('%This is a parameter input file for PyLoT/autoPyLoT.\n'+
'%All main and special settings regarding data handling\n'+
'%and picking are to be set here!\n'+
'%Parameters are optimized for local data sets!\n')
seperator = '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n'
'%Parameters are optimized for %{} data sets!\n'.format(self.get_main_para_names()['pick'][0]))
separator = '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n'
fid_out.write(header)
self.write_section(fid_out, self.get_main_para_names()['dirs'],
'main settings', seperator)
'main settings', separator)
self.write_section(fid_out, self.get_main_para_names()['nlloc'],
'NLLoc settings', seperator)
'NLLoc settings', separator)
self.write_section(fid_out, self.get_main_para_names()['smoment'],
'parameters for seismic moment estimation', seperator)
'parameters for seismic moment estimation', separator)
self.write_section(fid_out, self.get_main_para_names()['localmag'],
'settings local magnitude', seperator)
'settings local magnitude', separator)
self.write_section(fid_out, self.get_main_para_names()['filter'],
'filter settings', seperator)
self.write_section(fid_out, self.get_main_para_names()['pick'],
'common settings picker', seperator)
'common settings picker', separator)
fid_out.write(('#special settings for calculating CF#\n'+
'%!!Edit the following only if you know what you are doing!!%\n'))
self.write_section(fid_out, self.get_special_para_names()['z'],
@@ -253,9 +252,9 @@ class PylotParameter(object):
self.write_section(fid_out, self.get_special_para_names()['quality'],
'quality assessment', None)
def write_section(self, fid, names, title, seperator):
if seperator:
fid.write(seperator)
def write_section(self, fid, names, title, separator):
if separator:
fid.write(separator)
fid.write('#{}#\n'.format(title))
l_val = 50
l_name = 15

View File

@@ -7,6 +7,7 @@ import os
import scipy.io as sio
import warnings
from obspy.core import UTCDateTime
from obspy.core.util import AttribDict
from pylot.core.io.inputs import PylotParameter
from pylot.core.io.location import create_arrival, create_event, \
@@ -195,6 +196,7 @@ def picksdict_from_picks(evt):
phase = {}
station = pick.waveform_id.station_code
channel = pick.waveform_id.channel_code
network = pick.waveform_id.network_code
try:
onsets = picks[station]
except KeyError as e:
@@ -215,6 +217,7 @@ def picksdict_from_picks(evt):
phase['lpp'] = lpp
phase['spe'] = spe
phase['channel'] = channel
phase['network'] = network
try:
picker = str(pick.method_id)
if picker.startswith('smi:local/'):
@@ -231,7 +234,7 @@ def picks_from_picksdict(picks, creation_info=None):
picks_list = list()
for station, onsets in picks.items():
for label, phase in onsets.items():
if not isinstance(phase, dict):
if not isinstance(phase, dict) and not isinstance(phase, AttribDict):
continue
onset = phase['mpp']
try:
@@ -382,12 +385,12 @@ def reassess_pilot_event(root_dir, db_dir, event_id, out_dir=None, fn_param=None
evt.picks = picks_from_picksdict(picks_dict)
# write phase information to file
if not out_dir:
fnout_prefix = os.path.join(root_dir, db_dir, event_id, '{0}.'.format(event_id))
fnout_prefix = os.path.join(root_dir, db_dir, event_id, 'PyLoT_{0}.'.format(event_id))
else:
out_dir = os.path.join(out_dir, db_dir)
if not os.path.isdir(out_dir):
os.makedirs(out_dir)
fnout_prefix = os.path.join(out_dir, '{0}.'.format(event_id))
fnout_prefix = os.path.join(out_dir, 'PyLoT_{0}.'.format(event_id))
evt.write(fnout_prefix + 'xml', format='QUAKEML')
#evt.write(fnout_prefix + 'cnv', format='VELEST')
@@ -835,9 +838,10 @@ def merge_picks(event, picks):
err = pick.time_errors
phase = pick.phase_hint
station = pick.waveform_id.station_code
network = pick.waveform_id.network_code
method = pick.method_id
for p in event.picks:
if p.waveform_id.station_code == station and p.phase_hint == phase:
p.time, p.time_errors, p.method_id = time, err, method
del time, err, phase, station, method
p.time, p.time_errors, p.waveform_id.network_code, p.method_id = time, err, network, method
del time, err, phase, station, network, method
return event

View File

@@ -212,6 +212,14 @@ class AICPicker(AutoPicker):
self.Data[0].data = self.Data[0].data * 1000000
# get signal window
isignal = getsignalwin(self.Tcf, self.Pick, self.TSNR[2])
ii = min([isignal[len(isignal)-1], len(self.Tcf)])
isignal = isignal[0:ii]
try:
aic[isignal]
except IndexError as e:
msg = "Time series out of bounds! {}".format(e)
print(msg)
return
# calculate SNR from CF
self.SNR = max(abs(aic[isignal] - np.mean(aic[isignal]))) / \
max(abs(aic[inoise] - np.mean(aic[inoise])))

144
pylot/core/util/event.py Normal file
View File

@@ -0,0 +1,144 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
from obspy import UTCDateTime
from obspy.core.event import Event as ObsPyEvent
from obspy.core.event import Origin, Magnitude, ResourceIdentifier
from pylot.core.io.phases import picks_from_picksdict
class Event(ObsPyEvent):
'''
Pickable class derived from ~obspy.core.event.Event containing information on a single event.
'''
def __init__(self, path):
self.pylot_id = path.split('/')[-1]
# initialize super class
super(Event, self).__init__(resource_id=ResourceIdentifier('smi:local/'+self.pylot_id))
self.path = path
self.database = path.split('/')[-2]
self.datapath = path.split('/')[-3]
self.rootpath = '/' + os.path.join(*path.split('/')[:-3])
self.pylot_autopicks = {}
self.pylot_picks = {}
self.notes = ''
self._testEvent = False
self._refEvent = False
self.get_notes()
def get_notes_path(self):
notesfile = os.path.join(self.path, 'notes.txt')
return notesfile
def get_notes(self):
notesfile = self.get_notes_path()
if os.path.isfile(notesfile):
with open(notesfile) as infile:
path = str(infile.readlines()[0].split('\n')[0])
text = '[eventInfo: '+path+']'
self.addNotes(text)
try:
datetime = UTCDateTime(path.split('/')[-1])
origin = Origin(resource_id=self.resource_id, time=datetime, latitude=0, longitude=0, depth=0)
self.origins.append(origin)
except:
pass
def addNotes(self, notes):
self.notes = str(notes)
def clearNotes(self):
self.notes = None
def isRefEvent(self):
return self._refEvent
def isTestEvent(self):
return self._testEvent
def setRefEvent(self, bool):
self._refEvent = bool
if bool: self._testEvent = False
def setTestEvent(self, bool):
self._testEvent = bool
if bool: self._refEvent = False
def addPicks(self, picks):
'''
add pylot picks and overwrite existing
'''
for station in picks:
self.pylot_picks[station] = picks[station]
#add ObsPy picks
self.picks = picks_from_picksdict(self.pylot_picks)
def addAutopicks(self, autopicks):
for station in autopicks:
self.pylot_autopicks[station] = autopicks[station]
def setPick(self, station, pick):
if pick:
self.pylot_picks[station] = pick
self.picks = picks_from_picksdict(self.pylot_picks)
def setPicks(self, picks):
'''
set pylot picks and delete and overwrite all existing
'''
self.pylot_picks = picks
self.picks = picks_from_picksdict(self.pylot_picks)
def getPick(self, station):
if station in self.pylot_picks.keys():
return self.pylot_picks[station]
def getPicks(self):
return self.pylot_picks
def setAutopick(self, station, autopick):
if autopick:
self.pylot_autopicks[station] = autopick
def setAutopicks(self, autopicks):
self.pylot_autopicks = autopicks
def getAutopick(self, station):
if station in self.pylot_autopicks.keys():
return self.pylot_autopicks[station]
def getAutopicks(self):
return self.pylot_autopicks
def save(self, filename):
'''
Save PyLoT Event to a file.
Can be loaded by using event.load(filename).
'''
try:
import cPickle
except ImportError:
import _pickle as cPickle
try:
outfile = open(filename, 'wb')
cPickle.dump(self, outfile, -1)
except Exception as e:
print('Could not pickle PyLoT event. Reason: {}'.format(e))
@staticmethod
def load(filename):
'''
Load project from filename.
'''
try:
import cPickle
except ImportError:
import _pickle as cPickle
infile = open(filename, 'rb')
event = cPickle.load(infile)
print('Loaded %s' % filename)
return event

View File

@@ -22,6 +22,7 @@ class map_projection(QtGui.QWidget):
self.parser = parent.metadata[1]
self.picks = None
self.picks_dict = None
self.eventLoc = None
self.figure = figure
self.init_graphics()
self.init_stations()
@@ -244,6 +245,10 @@ class map_projection(QtGui.QWidget):
self.sc = self.basemap.scatter(self.lon, self.lat, s=50, facecolor='none', latlon=True,
zorder=10, picker=True, edgecolor='m', label='Not Picked')
self.cid = self.canvas.mpl_connect('pick_event', self.onpick)
if self.eventLoc:
lat, lon = self.eventLoc
self.sc_event = self.basemap.scatter(lon, lat, s=100, facecolor='red',
latlon=True, zorder=11, label='Event (might be outside map region)')
def scatter_picked_stations(self):
lon = self.lon_no_nan
@@ -274,8 +279,7 @@ class map_projection(QtGui.QWidget):
def refresh_drawings(self, picks=None):
self.picks_dict = picks
self.remove_drawings()
self.draw_everything()
self._refresh_drawings()
def _refresh_drawings(self):
self.remove_drawings()
@@ -303,6 +307,9 @@ class map_projection(QtGui.QWidget):
if hasattr(self, 'sc_picked'):
self.sc_picked.remove()
del(self.sc_picked)
if hasattr(self, 'sc_event'):
self.sc_event.remove()
del(self.sc_event)
if hasattr(self, 'cbar'):
self.cbar.remove()
del(self.cbar)

View File

@@ -12,7 +12,7 @@ import subprocess
from obspy import UTCDateTime, read
from pylot.core.io.inputs import PylotParameter
def _pickle_method(m):
if m.im_self is None:
return getattr, (m.im_class, m.im_func.func_name)

View File

@@ -35,6 +35,7 @@ from PySide.QtGui import QAction, QApplication, QCheckBox, QComboBox, \
from PySide.QtCore import QSettings, Qt, QUrl, Signal, Slot
from PySide.QtWebKit import QWebView
from obspy import Stream, UTCDateTime
from obspy.core.util import AttribDict
from pylot.core.io.data import Data
from pylot.core.io.inputs import FilterOptions, PylotParameter
from pylot.core.pick.utils import getSNR, earllatepicker, getnoisewin, \
@@ -707,7 +708,7 @@ class WaveformWidget(FigureCanvas):
self.draw()
def updateTitle(self, text):
self.getAxes().set_title(text)
self.getAxes().set_title(text, verticalalignment='bottom')
self.draw()
def updateWidget(self, xlabel, ylabel, title):
@@ -724,7 +725,7 @@ class WaveformWidget(FigureCanvas):
class PickDlg(QDialog):
update_picks = QtCore.Signal(dict)
def __init__(self, parent=None, data=None, station=None, picks=None,
def __init__(self, parent=None, data=None, station=None, network=None, picks=None,
autopicks=None, rotate=False, parameter=None, embedded=False):
super(PickDlg, self).__init__(parent)
@@ -732,6 +733,7 @@ class PickDlg(QDialog):
self.parameter = parameter
self._embedded = embedded
self.station = station
self.network = network
self.rotate = rotate
self.components = 'ZNE'
self.currentPhase = None
@@ -806,7 +808,15 @@ class PickDlg(QDialog):
self.cidscroll = self.connectScrollEvent(self.scrollZoom)
def setupUi(self):
menuBar = QtGui.QMenuBar(self)
if not self._embedded:
exitMenu = menuBar.addMenu('File')
exitAction = QtGui.QAction('Close', self)
exitAction.triggered.connect(self.close)
exitMenu.addAction(exitAction)
self.addPickPhases(menuBar)
# create matplotlib toolbar to inherit functionality
self.figToolBar = NavigationToolbar2QT(self.getPlotWidget(), self)
self.figToolBar.hide()
@@ -847,8 +857,8 @@ class PickDlg(QDialog):
self.p_button.setCheckable(True)
self.s_button.setCheckable(True)
# set button tooltips
self.p_button.setToolTip('Hotkey: "1"')
self.s_button.setToolTip('Hotkey: "2"')
# self.p_button.setToolTip('Hotkey: "1"')
# self.s_button.setToolTip('Hotkey: "2"')
# create accept/reject button
self.accept_button = QPushButton('&Accept Picks')
@@ -859,8 +869,8 @@ class PickDlg(QDialog):
self._shortcut_space = QtGui.QShortcut(QtGui.QKeySequence(' '), self)
self._shortcut_space.activated.connect(self.accept_button.clicked)
# button shortcuts (1 for P-button, 2 for S-button)
self.p_button.setShortcut(QKeySequence('1'))
self.s_button.setShortcut(QKeySequence('2'))
# self.p_button.setShortcut(QKeySequence('1'))
# self.s_button.setShortcut(QKeySequence('2'))
# layout the outermost appearance of the Pick Dialog
_outerlayout = QVBoxLayout()
@@ -892,9 +902,13 @@ class PickDlg(QDialog):
# merge widgets and layouts to establish the dialog
if not self._embedded:
_innerlayout.addWidget(_buttonbox)
_outerlayout.addWidget(menuBar)
_outerlayout.addWidget(_dialtoolbar)
_outerlayout.addLayout(_innerlayout)
_outerlayout.setStretch(0, 0)
_outerlayout.setStretch(1, 0)
_outerlayout.setStretch(2, 1)
# connect widget element signals with slots (methods to the dialog
# object
self.p_button.clicked.connect(self.p_clicked)
@@ -910,6 +924,60 @@ class PickDlg(QDialog):
self.setLayout(_outerlayout)
self.resize(1280, 720)
def addPickPhases(self, menuBar):
settings = QtCore.QSettings()
p_phases = settings.value('p_phases')
s_phases = settings.value('s_phases')
if p_phases:
p_phases = p_phases.split(',')
else:
p_phases = []
if s_phases:
s_phases = s_phases.split(',')
else:
s_phases = []
phases = {'P': p_phases,
'S': s_phases}
if not 'P' in phases['P'] and not 'p' in phases['P']:
phases['P'] = ['P'] + phases['P']
if not 'S' in phases['S'] and not 's' in phases['S']:
phases['S'] = ['S'] + phases['S']
picksMenu = menuBar.addMenu('Picks')
self.picksActions = {}
# dictionary points on corresponding phase_select function
phaseSelect = {'P': self.p_phase_select,
'S': self.s_phase_select}
nHotkey = 4 # max hotkeys per phase
hotkey = 1 # start hotkey
# loop over P and S (use explicit list instead of iter over dict.keys to keep order)
for phaseIndex, phaseID in enumerate(['P', 'S']):
# loop through phases in list
for index, phase in enumerate(phases[phaseID]):
# remove zeros
phase = phase.strip()
# add hotkeys
if not index >= nHotkey:
shortcut = str(hotkey)
hotkey += 1
else:
shortcut = None
# create action and add to menu
# phase name transferred using lambda function
slot = lambda phase=phase, phaseID=phaseID: phaseSelect[phaseID](phase)
picksAction = createAction(parent=self, text=phase,
slot=slot,
shortcut=shortcut)
picksMenu.addAction(picksAction)
self.picksActions[str(phase)] = picksAction # save action in dictionary
if phaseIndex == 0:
picksMenu.addSeparator()
def disconnectPressEvent(self):
widget = self.getPlotWidget()
widget.mpl_disconnect(self.cidpress)
@@ -952,9 +1020,32 @@ class PickDlg(QDialog):
def enable_ar_buttons(self, bool=True):
self.accept_button.setEnabled(bool)
self.reject_button.setEnabled(bool)
def p_phase_select(self, phase):
if not self.p_button.isChecked():
self.p_button.setChecked(True)
self.p_button.setText(phase)
else:
if str(phase) == str(self.p_button.text()):
self.reset_p_button()
else:
self.p_button.setText(phase)
self.p_clicked()
def s_phase_select(self, phase):
if not self.s_button.isChecked():
self.s_button.setChecked(True)
self.s_button.setText(phase)
else:
if str(phase) == str(self.s_button.text()):
self.reset_s_button()
else:
self.s_button.setText(phase)
self.s_clicked()
def p_clicked(self):
if self.p_button.isChecked():
self.reset_s_button()
self.s_button.setEnabled(False)
self.init_p_pick()
else:
@@ -962,7 +1053,8 @@ class PickDlg(QDialog):
def s_clicked(self):
if self.s_button.isChecked():
self.p_button.setEnabled(False)
self.reset_p_button()
self.p_button.setEnabled(False)
self.init_s_pick()
else:
self.leave_picking_mode()
@@ -971,13 +1063,13 @@ class PickDlg(QDialog):
self.set_button_color(self.p_button, 'yellow')
self.updateCurrentLimits()
self.activatePicking()
self.currentPhase = 'P'
self.currentPhase = str(self.p_button.text())
def init_s_pick(self):
self.set_button_color(self.s_button, 'yellow')
self.updateCurrentLimits()
self.activatePicking()
self.currentPhase = 'S'
self.currentPhase = str(self.s_button.text())
def set_button_color(self, button, color = None):
if type(color) == QtGui.QColor:
@@ -989,14 +1081,22 @@ class PickDlg(QDialog):
elif type(color) == str or not color:
button.setStyleSheet("background-color: {}".format(color))
def reset_p_button(self):
self.set_button_color(self.p_button)
self.p_button.setEnabled(True)
self.p_button.setChecked(False)
self.p_button.setText('P')
def reset_s_button(self):
self.set_button_color(self.s_button)
self.s_button.setEnabled(True)
self.s_button.setChecked(False)
self.s_button.setText('S')
def leave_picking_mode(self):
self.currentPhase = None
self.set_button_color(self.p_button)
self.set_button_color(self.s_button)
self.p_button.setEnabled(True)
self.s_button.setEnabled(True)
self.p_button.setChecked(False)
self.s_button.setChecked(False)
self.reset_p_button()
self.reset_s_button()
self.getPlotWidget().plotWFData(wfdata=self.getWFData(),
title=self.getStation())
self.drawAllPicks()
@@ -1035,6 +1135,8 @@ class PickDlg(QDialog):
return self.components
def getStation(self):
if self.network and self.station:
return self.network+'.'+self.station
return self.station
def getPlotWidget(self):
@@ -1057,7 +1159,7 @@ class PickDlg(QDialog):
return self._user
def getFilterOptions(self, phase):
options = self.filteroptions[phase]
options = self.filteroptions[phase[0]]
return FilterOptions(**options)
def getXLims(self):
@@ -1132,11 +1234,10 @@ class PickDlg(QDialog):
self.disconnectMotionEvent()
self.cidpress = self.connectPressEvent(self.setPick)
print(self.currentPhase)
if self.currentPhase == 'P':
if self.currentPhase.startswith('P'):
self.set_button_color(self.p_button, 'green')
self.setIniPickP(gui_event, wfdata, trace_number)
elif self.currentPhase == 'S':
elif self.currentPhase.startswith('S'):
self.set_button_color(self.s_button, 'green')
self.setIniPickS(gui_event, wfdata)
@@ -1169,7 +1270,7 @@ class PickDlg(QDialog):
# filter data and trace on which is picked prior to determination of SNR
phase = self.currentPhase
filteroptions = self.getFilterOptions(phase).parseFilterOptions()
filteroptions = self.getFilterOptions(phase[0]).parseFilterOptions()
if filteroptions:
data.filter(**filteroptions)
wfdata.filter(**filteroptions)
@@ -1360,9 +1461,11 @@ class PickDlg(QDialog):
'S': ('m', 'm--', 'r-', 'rv', 'r^', 'r', 'm:')
}
if self.getPicks(picktype):
if phase is not None and type(self.getPicks(picktype)[phase]) is dict:
picks = self.getPicks(picktype)[phase]
colors = phase_col[phase[0].upper()]
if phase is not None:
if (type(self.getPicks(picktype)[phase]) is dict
or type(self.getPicks(picktype)[phase]) is AttribDict):
picks = self.getPicks(picktype)[phase]
colors = phase_col[phase[0].upper()]
elif phase is None:
for phase in self.getPicks(picktype):
self.drawPicks(phase, picktype)
@@ -1387,7 +1490,8 @@ class PickDlg(QDialog):
ax.plot([mpp + spe, mpp + spe], ylims, colors[1])
ax.plot([mpp, mpp], ylims, colors[2], label='{}-Pick'.format(phase))
else:
ax.plot([mpp, mpp], ylims, colors[6], label='{}-Pick (NO PICKERROR)'.format(phase))
ax.plot([mpp, mpp], ylims, colors[6], label='{}-Pick (NO PICKERROR)'.format(phase))
ax.text(mpp, ylims[1], phase)
elif picktype == 'auto':
ax.plot(mpp, ylims[1], colors[3],
@@ -1646,7 +1750,7 @@ class TuneAutopicker(QWidget):
model = self.stationBox.model()
for network, station in stations:
item = QtGui.QStandardItem(network+'.'+station)
if station in self.get_current_event().picks:
if station in self.get_current_event().pylot_picks:
item.setBackground(self.parent._colors['ref'])
model.appendRow(item)
@@ -1687,8 +1791,8 @@ class TuneAutopicker(QWidget):
self.listWidget.scrollToBottom()
def get_current_event(self):
index = self.eventBox.currentIndex()
return self.eventBox.itemData(index)
path = self.eventBox.currentText()
return self.parent.project.getEventFromPath(path)
def get_current_event_name(self):
return self.eventBox.currentText().split('/')[-1]
@@ -1698,13 +1802,13 @@ class TuneAutopicker(QWidget):
def get_current_event_picks(self, station):
event = self.get_current_event()
if station in event.picks.keys():
return event.picks[station]
if station in event.pylot_picks.keys():
return event.pylot_picks[station]
def get_current_event_autopicks(self, station):
event = self.get_current_event()
if event.autopicks:
return event.autopicks[station]
if event.pylot_autopicks:
return event.pylot_autopicks[station]
def get_current_station(self):
return str(self.stationBox.currentText()).split('.')[-1]
@@ -1855,6 +1959,9 @@ class TuneAutopicker(QWidget):
self.init_tab_names()
def fill_eventbox(self):
project = self.parent.project
if not project:
return
# update own list
self.parent.fill_eventbox(eventBox=self.eventBox, select_events='ref')
index_start = self.parent.eventBox.currentIndex()
@@ -1862,11 +1969,15 @@ class TuneAutopicker(QWidget):
if index == -1:
index += 1
nevents = self.eventBox.model().rowCount()
if self.eventBox.itemData(index).isTestEvent():
path = self.eventBox.itemText(index)
if project.getEventFromPath(path).isTestEvent():
for index in range(nevents):
if not self.eventBox.itemData(index).isTestEvent():
break
elif index == nevents - 1:
path = self.eventBox.itemText(index)
if project.getEventFromPath(index):
if not project.getEventFromPath(index).isTestEvent():
break
#in case all events are marked as test events and last event is reached
if index == nevents - 1:
index = -1
self.eventBox.setCurrentIndex(index)
if not index == index_start:
@@ -1911,8 +2022,8 @@ class TuneAutopicker(QWidget):
self._warn('Could not execute picker:\n{}'.format(
self.ap_thread._executedError))
return
self.picks = self.ap_thread.data
if not self.picks:
self.pylot_picks = self.ap_thread.data
if not self.pylot_picks:
self._warn('No picks found. See terminal output.')
return
#renew tabs
@@ -2456,6 +2567,7 @@ class PropertiesDlg(QDialog):
elif setting.startswith('Channel N'):
component = 'N'
compclass.setCompPosition(value, component, False)
settings.sync()
@@ -2547,7 +2659,7 @@ class OutputsTab(PropTab):
settings = QSettings()
curval = settings.value("output/Format", None)
eventOutputLabel = QLabel("event ouput format")
eventOutputLabel = QLabel("event/picks output format")
self.eventOutputComboBox = QComboBox()
eventoutputformats = OUTPUTFORMATS.keys()
self.eventOutputComboBox.addItems(eventoutputformats)
@@ -2568,13 +2680,45 @@ class OutputsTab(PropTab):
def resetValues(self, infile):
values = {"output/Format": self.eventOutputComboBox.setCurrentIndex(1)}
return values
class PhasesTab(PropTab):
def __init__(self, parent=None):
super(PhasesTab, self).__init__(parent)
pass
self.PphasesEdit = QLineEdit()
self.SphasesEdit = QLineEdit()
PphasesLabel = QLabel("P Phases to pick")
SphasesLabel = QLabel("S Phases to pick")
settings = QSettings()
Pphases = settings.value('p_phases')
Sphases = settings.value('s_phases')
self.PphasesEdit.setText("%s" % Pphases)
self.SphasesEdit.setText("%s" % Sphases)
layout = QGridLayout()
layout.addWidget(PphasesLabel, 0, 0)
layout.addWidget(SphasesLabel, 1, 0)
layout.addWidget(self.PphasesEdit, 0, 1)
layout.addWidget(self.SphasesEdit, 1, 1)
self.setLayout(layout)
def getValues(self):
values = {'p_phases': self.PphasesEdit.text(),
's_phases': self.SphasesEdit.text()}
return values
def resetValues(self, infile=None):
Pphases = 'P, Pg, Pn, PmP, P1, P2, P3'
Sphases = 'S, Sg, Sn, SmS, S1, S2, S3'
values = {'p_phases': self.PphasesEdit.setText(Pphases),
's_phases': self.SphasesEdit.setText(Sphases)}
return values
class GraphicsTab(PropTab):
def __init__(self, parent=None):
@@ -2619,7 +2763,12 @@ class GraphicsTab(PropTab):
'pyqtgraphic': self.checkbox_pg.isChecked()}
return values
def resetValues(self, infile=None):
values = {'nth_sample': self.spinbox_nth_sample.setValue(1),
'pyqtgraphic': self.checkbox_pg.setChecked(True)}
return values
class ChannelOrderTab(PropTab):
def __init__(self, parent=None, infile=None):
super(ChannelOrderTab, self).__init__(parent)