Merge remote-tracking branch 'origin/develop' into feature/refactor
This commit is contained in:
commit
5258a7e9b4
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
*.pyc
|
||||
*~
|
||||
pylot/RELEASE-VERSION
|
||||
*.idea
|
||||
|
329
PyLoT.py
329
PyLoT.py
@ -86,7 +86,7 @@ from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \
|
||||
PylotCanvas, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \
|
||||
getDataType, ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \
|
||||
CompareEventsWidget
|
||||
from pylot.core.util.map_projection import map_projection
|
||||
from pylot.core.util.array_map import Array_map
|
||||
from pylot.core.util.structure import DATASTRUCTURE
|
||||
from pylot.core.util.thread import Thread, Worker
|
||||
from pylot.core.util.version import get_git_version as _getVersionString
|
||||
@ -138,6 +138,9 @@ class MainWindow(QMainWindow):
|
||||
self._eventChanged = [False, False]
|
||||
self.apd_local = None
|
||||
self.apd_sge = None
|
||||
self.stations_highlighted = []
|
||||
self.obspy_dmt = False
|
||||
self.nextStation = False
|
||||
|
||||
self.poS_id = None
|
||||
self.ae_id = None
|
||||
@ -615,6 +618,10 @@ class MainWindow(QMainWindow):
|
||||
|
||||
# add scroll area used in case number of traces gets too high
|
||||
self.wf_scroll_area = QtGui.QScrollArea(self)
|
||||
self.wf_scroll_area.setVisible(False)
|
||||
self.no_data_label = QLabel('No Data')
|
||||
self.no_data_label.setStyleSheet('color: red')
|
||||
self.no_data_label.setAlignment(Qt.AlignCenter)
|
||||
|
||||
# create central matplotlib figure canvas widget
|
||||
self.init_wfWidget()
|
||||
@ -632,11 +639,17 @@ class MainWindow(QMainWindow):
|
||||
array_tab.setLayout(self.array_layout)
|
||||
events_tab.setLayout(self.events_layout)
|
||||
|
||||
# tighten up layouts inside tabs
|
||||
for layout in [self.wf_layout, self.array_layout, self.events_layout]:
|
||||
layout.setSpacing(0)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
# add tabs to main tab widget
|
||||
self.tabs.addTab(wf_tab, 'Waveform Plot')
|
||||
self.tabs.addTab(array_tab, 'Array Map')
|
||||
self.tabs.addTab(events_tab, 'Eventlist')
|
||||
|
||||
self.wf_layout.addWidget(self.no_data_label)
|
||||
self.wf_layout.addWidget(self.wf_scroll_area)
|
||||
self.wf_scroll_area.setWidgetResizable(True)
|
||||
self.init_array_tab()
|
||||
@ -1217,6 +1230,8 @@ class MainWindow(QMainWindow):
|
||||
tv.verticalHeader().hide()
|
||||
tv.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
|
||||
|
||||
current_event = self.get_current_event()
|
||||
|
||||
eventBox.setView(tv)
|
||||
eventBox.clear()
|
||||
model = eventBox.model()
|
||||
@ -1249,6 +1264,17 @@ class MainWindow(QMainWindow):
|
||||
event_ref = event.isRefEvent()
|
||||
event_test = event.isTestEvent()
|
||||
|
||||
time = lat = lon = depth = mag = None
|
||||
if len(event.origins) == 1:
|
||||
origin = event.origins[0]
|
||||
time = origin.time + 0 # add 0 because there was an exception for time = 0s
|
||||
lat = origin.latitude
|
||||
lon = origin.longitude
|
||||
depth = origin.depth
|
||||
if len(event.magnitudes) == 1:
|
||||
magnitude = event.magnitudes[0]
|
||||
mag = magnitude.mag
|
||||
|
||||
# text = '{path:{plen}} | manual: [{p:3d}] | auto: [{a:3d}]'
|
||||
# text = text.format(path=event_path,
|
||||
# plen=plmax,
|
||||
@ -1256,6 +1282,11 @@ class MainWindow(QMainWindow):
|
||||
# a=event_nautopicks)
|
||||
|
||||
item_path = QtGui.QStandardItem('{path:{plen}}'.format(path=event_path, plen=plmax))
|
||||
item_time = QtGui.QStandardItem('{}'.format(time))
|
||||
item_lat = QtGui.QStandardItem('{}'.format(lat))
|
||||
item_lon = QtGui.QStandardItem('{}'.format(lon))
|
||||
item_depth = QtGui.QStandardItem('{}'.format(depth))
|
||||
item_mag = QtGui.QStandardItem('{}'.format(mag))
|
||||
item_nmp = QtGui.QStandardItem(str(ma_count['manual']))
|
||||
item_nmp.setIcon(self.manupicksicon_small)
|
||||
item_nap = QtGui.QStandardItem(str(ma_count['auto']))
|
||||
@ -1281,10 +1312,17 @@ class MainWindow(QMainWindow):
|
||||
# item.setFont(font)
|
||||
# item2.setForeground(QtGui.QColor('black'))
|
||||
# item2.setFont(font)
|
||||
itemlist = [item_path, item_nmp, item_nap, item_ref, item_test, item_notes]
|
||||
if event_test and select_events == 'ref':
|
||||
itemlist = [item_path, item_time, item_lat, item_lon, item_depth,
|
||||
item_mag, item_nmp, item_nap, item_ref, item_test, item_notes]
|
||||
for item in itemlist:
|
||||
item.setTextAlignment(Qt.AlignCenter)
|
||||
if event_test and select_events == 'ref' or self.isEmpty(event_path):
|
||||
for item in itemlist:
|
||||
item.setEnabled(False)
|
||||
|
||||
#item color
|
||||
self.setItemColor(itemlist, id, event, current_event)
|
||||
|
||||
model.appendRow(itemlist)
|
||||
if not event.path == self.eventBox.itemText(id).strip():
|
||||
message = ('Path missmatch creating eventbox.\n'
|
||||
@ -1296,6 +1334,23 @@ class MainWindow(QMainWindow):
|
||||
eventBox.setCurrentIndex(index)
|
||||
self.refreshRefTestButtons()
|
||||
|
||||
def isEmpty(self, event_path):
|
||||
wf_stat = {True: 'processed',
|
||||
False: 'raw',
|
||||
None: None}
|
||||
|
||||
# self.data.processed is only None for PyLoT datastructure, else True or False
|
||||
wf_dir = wf_stat[self.data.processed]
|
||||
if wf_dir is not None:
|
||||
wf_path = os.path.join(event_path, wf_dir)
|
||||
if wf_dir is 'processed' and not os.path.exists(wf_path):
|
||||
wf_path = os.path.join(event_path, 'raw')
|
||||
else:
|
||||
wf_path = event_path
|
||||
if not os.path.exists(wf_path):
|
||||
return True
|
||||
return not bool(os.listdir(wf_path))
|
||||
|
||||
def filename_from_action(self, action):
|
||||
if action.data() is None:
|
||||
filt = "Supported file formats" \
|
||||
@ -1373,7 +1428,10 @@ class MainWindow(QMainWindow):
|
||||
def exportAllEvents(self, outformats=['.xml']):
|
||||
for event in self.project.eventlist:
|
||||
self.get_data().setEvtData(event)
|
||||
self.saveData(event, event.path, outformats)
|
||||
try:
|
||||
self.saveData(event, event.path, outformats)
|
||||
except Exception as e:
|
||||
print('WARNING! Could not save event {}. Reason: {}'.format(event.path, e))
|
||||
|
||||
def enableSaveEventAction(self):
|
||||
self.saveEventAction.setEnabled(True)
|
||||
@ -1617,10 +1675,10 @@ class MainWindow(QMainWindow):
|
||||
if self._eventChanged[1]:
|
||||
self.refresh_array_map()
|
||||
if not plotted and self._eventChanged[0]:
|
||||
# newWF(False) = load data without plotting
|
||||
# newWF(plot=False) = load data without plotting
|
||||
self.newWF(plot=False)
|
||||
|
||||
def newWF(self, plot=True):
|
||||
def newWF(self, event=None, plot=True):
|
||||
'''
|
||||
Load new data and plot if necessary.
|
||||
'''
|
||||
@ -1634,6 +1692,7 @@ class MainWindow(QMainWindow):
|
||||
call modal plot thread method when finished.
|
||||
'''
|
||||
if load:
|
||||
self.prepareLoadWaveformData()
|
||||
self.wfd_thread = Thread(self, self.loadWaveformData,
|
||||
progressText='Reading data input...',
|
||||
pb_widget=self.mainProgressBarWidget)
|
||||
@ -1646,6 +1705,16 @@ class MainWindow(QMainWindow):
|
||||
if plot and not load:
|
||||
self.plotWaveformDataThread()
|
||||
|
||||
def prepareLoadWaveformData(self):
|
||||
self.fnames = self.getWFFnames_from_eventbox()
|
||||
self.fnames_syn = []
|
||||
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)
|
||||
|
||||
def loadWaveformData(self):
|
||||
'''
|
||||
Load waveform data corresponding to current selected event.
|
||||
@ -1657,14 +1726,48 @@ class MainWindow(QMainWindow):
|
||||
# ans = self.data.setWFData(self.getWFFnames())
|
||||
# else:
|
||||
# ans = False
|
||||
self.fnames = self.getWFFnames_from_eventbox()
|
||||
eventpath = self.get_current_event_path()
|
||||
basepath = eventpath.split(os.path.basename(eventpath))[0]
|
||||
obspy_dmt = check_obspydmt_structure(basepath)
|
||||
|
||||
self.data.setWFData(self.fnames,
|
||||
self.fnames_syn,
|
||||
checkRotated=True,
|
||||
metadata=self.metadata,
|
||||
obspy_dmt=obspy_dmt)
|
||||
metadata=self.metadata)
|
||||
|
||||
def prepareObspyDMT_data(self, eventpath):
|
||||
qcbox_processed = self.dataPlot.qcombo_processed
|
||||
qcheckb_syn = self.dataPlot.syn_checkbox
|
||||
qcbox_processed.setEnabled(False)
|
||||
qcheckb_syn.setEnabled(False)
|
||||
for fpath in os.listdir(eventpath):
|
||||
fpath = fpath.split('/')[-1]
|
||||
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 'processed' in fpath:
|
||||
qcbox_processed.setEnabled(True)
|
||||
if qcbox_processed.isEnabled():
|
||||
wftype = qcbox_processed.currentText()
|
||||
else:
|
||||
wftype = 'raw'
|
||||
qcbox_processed.setCurrentIndex(qcbox_processed.findText(wftype))
|
||||
eventpath_dmt = os.path.join(eventpath, wftype)
|
||||
self.fnames = [os.path.join(eventpath_dmt, filename) for filename in os.listdir(eventpath_dmt)]
|
||||
|
||||
# def setWFstatus(self):
|
||||
# '''
|
||||
# show status of current data, can be either 'raw' or 'processed'
|
||||
# :param status:
|
||||
# :return:
|
||||
# '''
|
||||
# status = self.data.processed
|
||||
# wf_stat_color = {True: 'green',
|
||||
# False: 'black',
|
||||
# None: None}
|
||||
# wf_stat = {True: 'processed',
|
||||
# False: 'raw',
|
||||
# None: None}
|
||||
# self.dataPlot.setQCboxItem(wf_stat[status])
|
||||
|
||||
def check_plot_quantity(self):
|
||||
"""
|
||||
@ -1757,7 +1860,10 @@ 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)
|
||||
for times, data, times_syn, data_syn in plots:
|
||||
self.dataPlot.plotWidget.getPlotItem().plot(times, data,
|
||||
pen=self.dataPlot.pen_linecolor)
|
||||
@ -1765,8 +1871,7 @@ class MainWindow(QMainWindow):
|
||||
self.dataPlot.plotWidget.getPlotItem().plot(times_syn, data_syn,
|
||||
pen=self.dataPlot.pen_linecolor_syn)
|
||||
self.dataPlot.reinitMoveProxy()
|
||||
self.dataPlot.plotWidget.showAxis('left')
|
||||
self.dataPlot.plotWidget.showAxis('bottom')
|
||||
self.highlight_stations()
|
||||
|
||||
def finishWaveformDataPlot(self):
|
||||
self.comparable = self.checkEvents4comparison()
|
||||
@ -1842,12 +1947,10 @@ class MainWindow(QMainWindow):
|
||||
comparable[event.pylot_id] = self.checkEvent4comparison(event)
|
||||
return comparable
|
||||
|
||||
def clearWaveformDataPlot(self):
|
||||
def clearWaveformDataPlot(self, refresh_plot=False):
|
||||
self.disconnectWFplotEvents()
|
||||
if self.pg:
|
||||
self.dataPlot.plotWidget.getPlotItem().clear()
|
||||
self.dataPlot.plotWidget.hideAxis('bottom')
|
||||
self.dataPlot.plotWidget.hideAxis('left')
|
||||
else:
|
||||
for ax in self.dataPlot.axes:
|
||||
ax.cla()
|
||||
@ -1863,6 +1966,9 @@ class MainWindow(QMainWindow):
|
||||
self.openEventAction.setEnabled(False)
|
||||
self.openEventsAutoAction.setEnabled(False)
|
||||
self.loadpilotevent.setEnabled(False)
|
||||
if not refresh_plot:
|
||||
self.wf_scroll_area.setVisible(False)
|
||||
self.no_data_label.setVisible(True)
|
||||
self.disableSaveEventAction()
|
||||
self.draw()
|
||||
|
||||
@ -1871,7 +1977,7 @@ class MainWindow(QMainWindow):
|
||||
Open a modal thread to plot current waveform data.
|
||||
'''
|
||||
self.check_plot_quantity()
|
||||
self.clearWaveformDataPlot()
|
||||
self.clearWaveformDataPlot(refresh_plot=True)
|
||||
self.wfp_thread = Thread(self, self.plotWaveformData,
|
||||
arg=filter,
|
||||
progressText='Plotting waveform data...',
|
||||
@ -1904,9 +2010,10 @@ class MainWindow(QMainWindow):
|
||||
self.plot_method = 'fast'
|
||||
else:
|
||||
self.plot_method = 'normal'
|
||||
plots = plotWidget.plotWFData(wfdata=wfst, wfsyn=wfsyn, title=title, mapping=False, component=comp,
|
||||
nth_sample=int(nth_sample), method=self.plot_method)
|
||||
return plots
|
||||
rval = plotWidget.plotWFData(wfdata=wfst, wfsyn=wfsyn, title=title, mapping=False, component=comp,
|
||||
nth_sample=int(nth_sample), method=self.plot_method)
|
||||
plots, gaps = rval if rval else ([], [])
|
||||
return plots, gaps
|
||||
|
||||
def adjustPlotHeight(self):
|
||||
if self.pg:
|
||||
@ -2135,10 +2242,12 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def pickOnStation(self, gui_event):
|
||||
if self.pg:
|
||||
if not gui_event.button() == 1:
|
||||
button = gui_event.button()
|
||||
if not button in [1, 4]:
|
||||
return
|
||||
else:
|
||||
if not gui_event.button == 1:
|
||||
button = gui_event.button
|
||||
if not button == 1:
|
||||
return
|
||||
|
||||
if self.pg:
|
||||
@ -2149,27 +2258,59 @@ class MainWindow(QMainWindow):
|
||||
wfID = self.getWFID(ycoord)
|
||||
|
||||
if wfID is None: return
|
||||
self.pickDialog(wfID)
|
||||
|
||||
def pickDialog(self, wfID, nextStation=False):
|
||||
station = self.getStationName(wfID)
|
||||
network = self.getNetworkName(wfID)
|
||||
station = self.getStationName(wfID)
|
||||
if button == 1:
|
||||
self.pickDialog(wfID, network, station)
|
||||
elif button == 4:
|
||||
self.toggle_station_color(wfID, network, station)
|
||||
|
||||
def toggle_station_color(self, wfID, network, station):
|
||||
black_pen = pg.mkPen((0, 0, 0))
|
||||
red_pen = pg.mkPen((200, 50, 50))
|
||||
line_item = self.dataPlot.plotWidget.getPlotItem().listDataItems()[wfID - 1]
|
||||
current_pen = line_item.opts['pen']
|
||||
nwst = '{}.{}'.format(network, station)
|
||||
if current_pen == black_pen:
|
||||
line_item.setPen(red_pen)
|
||||
if not nwst in self.stations_highlighted:
|
||||
self.stations_highlighted.append(nwst)
|
||||
else:
|
||||
line_item.setPen(black_pen)
|
||||
if nwst in self.stations_highlighted:
|
||||
self.stations_highlighted.pop(self.stations_highlighted.index(nwst))
|
||||
|
||||
def highlight_stations(self):
|
||||
for wfID, value in self.getPlotWidget().getPlotDict().items():
|
||||
station, channel, network = value
|
||||
nwst = '{}.{}'.format(network, station)
|
||||
if nwst in self.stations_highlighted:
|
||||
self.toggle_station_color(wfID, network, station)
|
||||
|
||||
def pickDialog(self, wfID, network=None, station=None):
|
||||
if not network:
|
||||
network = self.getNetworkName(wfID)
|
||||
if not station:
|
||||
station = self.getStationName(wfID)
|
||||
if not station or not network:
|
||||
return
|
||||
self.update_status('picking on station {0}'.format(station))
|
||||
data = self.get_data().getOriginalWFData().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),
|
||||
station=station, network=network,
|
||||
picks=self.getPicksOnStation(station, 'manual'),
|
||||
autopicks=self.getPicksOnStation(station, 'auto'),
|
||||
metadata=self.metadata, event=event,
|
||||
filteroptions=self.filteroptions)
|
||||
filteroptions=self.filteroptions, wftype=wftype)
|
||||
if self.filterActionP.isChecked() or self.filterActionS.isChecked():
|
||||
pickDlg.currentPhase = self.getSeismicPhase()
|
||||
pickDlg.filterWFData()
|
||||
pickDlg.nextStation.setChecked(nextStation)
|
||||
pickDlg.nextStation.setChecked(self.nextStation)
|
||||
pickDlg.nextStation.stateChanged.connect(self.toggle_next_station)
|
||||
if pickDlg.exec_():
|
||||
if pickDlg._dirty:
|
||||
self.setDirty(True)
|
||||
@ -2179,13 +2320,13 @@ class MainWindow(QMainWindow):
|
||||
self.enableSaveEventAction()
|
||||
if replot1 or replot2:
|
||||
self.plotWaveformDataThread()
|
||||
self.drawPicks()
|
||||
|
||||
self.draw()
|
||||
else:
|
||||
self.drawPicks(station)
|
||||
self.draw()
|
||||
if pickDlg.nextStation.isChecked():
|
||||
self.pickDialog(wfID - 1, nextStation=pickDlg.nextStation.isChecked())
|
||||
if self.nextStation:
|
||||
self.pickDialog(wfID - 1)
|
||||
else:
|
||||
self.update_status('picks discarded ({0})'.format(station))
|
||||
if not self.get_loc_flag() and self.check4Loc():
|
||||
@ -2194,8 +2335,13 @@ class MainWindow(QMainWindow):
|
||||
elif self.get_loc_flag() and not self.check4Loc():
|
||||
self.set_loc_flag(False)
|
||||
|
||||
def toggle_next_station(self, signal):
|
||||
self.nextStation = bool(signal)
|
||||
|
||||
def addListItem(self, text):
|
||||
self.listWidget.addItem(text)
|
||||
textlist = text.split('\n')
|
||||
for text in textlist:
|
||||
self.listWidget.addItem(text)
|
||||
self.listWidget.scrollToBottom()
|
||||
|
||||
def init_fig_dict(self):
|
||||
@ -2254,7 +2400,7 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def tune_autopicker(self):
|
||||
'''
|
||||
Initiates TuneAutopicker widget use to interactively
|
||||
Initiates TuneAutopicker widget used to interactively
|
||||
tune parameters for autopicking algorithm.
|
||||
'''
|
||||
# figures and canvas have to be iniated from the main GUI
|
||||
@ -2263,7 +2409,7 @@ class MainWindow(QMainWindow):
|
||||
self.init_fig_dict()
|
||||
#if not self.tap:
|
||||
# init TuneAutopicker object
|
||||
self.tap = TuneAutopicker(self)
|
||||
self.tap = TuneAutopicker(self, self.obspy_dmt)
|
||||
# first call of update to init tabs with empty canvas
|
||||
self.update_autopicker()
|
||||
# connect update signal of TuneAutopicker with update function
|
||||
@ -2345,6 +2491,7 @@ class MainWindow(QMainWindow):
|
||||
# export current picks etc.
|
||||
self.exportAllEvents(['.xml'])
|
||||
|
||||
wfpath = self.dataPlot.qcombo_processed.currentText() if self.obspy_dmt else ''
|
||||
# define arguments for picker
|
||||
args = {'parameter': self._inputs,
|
||||
'station': 'all',
|
||||
@ -2353,8 +2500,8 @@ class MainWindow(QMainWindow):
|
||||
'iplot': 0,
|
||||
'fig_dict': None,
|
||||
'fig_dict_wadatijack': self.fig_dict_wadatijack,
|
||||
'locflag': 0}
|
||||
|
||||
'savexml': False,
|
||||
'obspyDMT_wfpath': wfpath}
|
||||
# init pick thread
|
||||
self.mp_thread = QtCore.QThreadPool()
|
||||
self.mp_worker = Worker(autoPyLoT, args, redirect_stdout=True)
|
||||
@ -2363,6 +2510,7 @@ class MainWindow(QMainWindow):
|
||||
|
||||
self.mp_worker.signals.message.connect(self.addListItem)
|
||||
self.mp_worker.signals.result.connect(self.finalizeAutoPick)
|
||||
self.mp_worker.signals.finished.connect(self.enableAutoPickWidget)
|
||||
|
||||
self.mp_thread.start(self.mp_worker)
|
||||
|
||||
@ -2377,7 +2525,6 @@ class MainWindow(QMainWindow):
|
||||
self.apd_sge.show()
|
||||
|
||||
def finalizeAutoPick(self, result):
|
||||
self.apw.enable(True)
|
||||
if result:
|
||||
self.init_canvas_dict_wadatijack()
|
||||
for eventID in result.keys():
|
||||
@ -2393,6 +2540,9 @@ class MainWindow(QMainWindow):
|
||||
self.drawPicks(picktype='auto')
|
||||
self.draw()
|
||||
|
||||
def enableAutoPickWidget(self, event=None):
|
||||
self.apw.enable(True)
|
||||
|
||||
def get_event_from_id(self, eventID):
|
||||
for event in self.project.eventlist:
|
||||
if event.pylot_id == eventID:
|
||||
@ -2607,55 +2757,28 @@ class MainWindow(QMainWindow):
|
||||
"""
|
||||
if not self.okToContinue():
|
||||
return
|
||||
settings = QSettings()
|
||||
# get location tool hook
|
||||
loctool = settings.value("loc/tool", "nll")
|
||||
parameter = self._inputs
|
||||
loctool = 'nll'
|
||||
lt = locateTool[loctool]
|
||||
# get working directory
|
||||
locroot = settings.value("{0}/rootPath".format(loctool), None)
|
||||
locroot = parameter['nllocroot']
|
||||
if locroot is None:
|
||||
self.PyLoTprefs()
|
||||
self.locate_event()
|
||||
|
||||
infile = settings.value("{0}/inputFile".format(loctool), None)
|
||||
ctrfile = os.path.join(locroot, 'run', parameter['ctrfile'])
|
||||
|
||||
if not infile:
|
||||
caption = 'Select {0} input file'.format(loctool)
|
||||
filt = "Supported file formats" \
|
||||
" (*.in *.ini *.conf *.cfg)"
|
||||
ans = QFileDialog().getOpenFileName(self, caption=caption,
|
||||
filter=filt, dir=locroot)
|
||||
if ans[0]:
|
||||
infile = ans[0]
|
||||
else:
|
||||
QMessageBox.information(self,
|
||||
self.tr('No infile selected'),
|
||||
self.tr('Inputfile necessary for localization.'))
|
||||
return
|
||||
settings.setValue("{0}/inputFile".format(loctool), infile)
|
||||
settings.sync()
|
||||
if loctool == 'nll':
|
||||
ttt = settings.value("{0}/travelTimeTables", None)
|
||||
ok = False
|
||||
if ttt is None:
|
||||
while not ok:
|
||||
text, ok = QInputDialog.getText(self, 'Pattern for travel time tables',
|
||||
'Base name of travel time tables',
|
||||
echo=QLineEdit.Normal,
|
||||
text="ttime")
|
||||
ttt = text
|
||||
|
||||
outfile = settings.value("{0}/outputFile".format(loctool),
|
||||
os.path.split(os.tempnam())[-1])
|
||||
ttt = parameter['ttpatter']
|
||||
outfile = parameter['outpatter']
|
||||
eventname = self.get_current_event_name()
|
||||
obsdir = os.path.join(self._inputs['rootpath'], self._inputs['datapath'], self._inputs['database'], eventname)
|
||||
self.saveData(event=self.get_current_event(), directory=obsdir, outformats='.obs')
|
||||
filename = 'PyLoT_' + eventname
|
||||
locpath = os.path.join(locroot, 'loc', filename)
|
||||
phasefile = os.path.join(obsdir, filename + '.obs')
|
||||
lt.modify_inputs(infile, locroot, filename, phasefile, ttt)
|
||||
lt.modify_inputs(ctrfile, locroot, filename, phasefile, ttt)
|
||||
try:
|
||||
lt.locate(infile)
|
||||
lt.locate(ctrfile)
|
||||
except RuntimeError as e:
|
||||
print(e.message)
|
||||
#finally:
|
||||
@ -2721,10 +2844,7 @@ class MainWindow(QMainWindow):
|
||||
self.init_metadata()
|
||||
if not self.metadata:
|
||||
return
|
||||
self.am_figure = Figure()
|
||||
self.am_canvas = FigureCanvas(self.am_figure)
|
||||
self.am_toolbar = NavigationToolbar(self.am_canvas, self)
|
||||
self.array_map = map_projection(self)
|
||||
self.array_map = Array_map(self)
|
||||
# self.array_map_thread()
|
||||
self.array_layout.addWidget(self.array_map)
|
||||
self.tabs.setCurrentIndex(index)
|
||||
@ -2763,7 +2883,8 @@ class MainWindow(QMainWindow):
|
||||
lon = event.origins[0].longitude
|
||||
self.array_map.eventLoc = (lat, lon)
|
||||
if self.get_current_event():
|
||||
self.array_map.refresh_drawings(self.get_current_event().getPicks())
|
||||
self.array_map.refresh_drawings(self.get_current_event().getPicks(),
|
||||
self.get_current_event().getAutopicks(),)
|
||||
self._eventChanged[1] = False
|
||||
|
||||
def init_event_table(self, tabindex=2):
|
||||
@ -2817,14 +2938,6 @@ class MainWindow(QMainWindow):
|
||||
event.addNotes(notes)
|
||||
self.fill_eventbox()
|
||||
|
||||
def set_background_color(items, color):
|
||||
for item in items:
|
||||
item.setBackground(color)
|
||||
|
||||
def set_foreground_color(items, color):
|
||||
for item in items:
|
||||
item.setForeground(color)
|
||||
|
||||
current_event = self.get_current_event()
|
||||
|
||||
# generate delete icon
|
||||
@ -2894,7 +3007,7 @@ class MainWindow(QMainWindow):
|
||||
if hasattr(event, 'origins'):
|
||||
if event.origins:
|
||||
origin = event.origins[0]
|
||||
item_time.setText(str(origin.time).split('.')[0])
|
||||
item_time.setText(str(origin.time + 0).split('.')[0]) # +0 as workaround in case time=0s
|
||||
item_lon.setText(str(origin.longitude))
|
||||
item_lat.setText(str(origin.latitude))
|
||||
item_depth.setText(str(origin.depth))
|
||||
@ -2928,11 +3041,7 @@ class MainWindow(QMainWindow):
|
||||
item_nmp, item_nap, item_ref, item_test, item_notes]
|
||||
self.project._table.append(column)
|
||||
|
||||
if index%2:
|
||||
set_background_color(column, QtGui.QColor(*(245, 245, 245, 255)))
|
||||
|
||||
if event == current_event:
|
||||
set_foreground_color(column, QtGui.QColor(*(0, 143, 143, 255)))
|
||||
self.setItemColor(column, index, event, current_event)
|
||||
|
||||
# manipulate items
|
||||
item_ref.setBackground(self._ref_test_colors['ref'])
|
||||
@ -2954,6 +3063,24 @@ class MainWindow(QMainWindow):
|
||||
self.events_layout.addWidget(self.event_table)
|
||||
self.tabs.setCurrentIndex(tabindex)
|
||||
|
||||
def setItemColor(self, item_list, index, event, current_event):
|
||||
def set_background_color(items, color):
|
||||
for item in items:
|
||||
item.setBackground(color)
|
||||
|
||||
def set_foreground_color(items, color):
|
||||
for item in items:
|
||||
item.setForeground(color)
|
||||
|
||||
if index % 2:
|
||||
set_background_color(item_list, QtGui.QColor(*(245, 245, 245, 255)))
|
||||
|
||||
if self.isEmpty(event.path):
|
||||
set_foreground_color(item_list, QtGui.QColor(*(180, 180, 180, 255)))
|
||||
|
||||
if event == current_event:
|
||||
set_background_color(item_list, QtGui.QColor(*(0, 143, 143, 255)))
|
||||
|
||||
def read_metadata_thread(self, fninv):
|
||||
self.rm_thread = Thread(self, read_metadata, arg=fninv, progressText='Reading metadata...',
|
||||
pb_widget=self.mainProgressBarWidget)
|
||||
@ -3003,19 +3130,17 @@ class MainWindow(QMainWindow):
|
||||
settings.setValue("inventoryFile", self.project.inv_path)
|
||||
|
||||
fninv = settings.value("inventoryFile", None)
|
||||
if fninv and ask_default:
|
||||
if (fninv and ask_default) and not new:
|
||||
ans = QMessageBox.question(self, self.tr("Use default metadata..."),
|
||||
self.tr(
|
||||
"Do you want to use the default value for metadata?\n({})".format(fninv)),
|
||||
QMessageBox.Yes | QMessageBox.No,
|
||||
QMessageBox.Yes)
|
||||
if ans == QMessageBox.No:
|
||||
if not set_inv(settings):
|
||||
return None
|
||||
elif ans == QMessageBox.Yes:
|
||||
if ans == QMessageBox.Yes:
|
||||
self.read_metadata_thread(fninv)
|
||||
if fninv and not ask_default:
|
||||
self.read_metadata_thread(fninv)
|
||||
return
|
||||
set_inv(settings)
|
||||
|
||||
|
||||
def calc_magnitude(self, type='ML'):
|
||||
self.init_metadata()
|
||||
@ -3197,9 +3322,11 @@ class MainWindow(QMainWindow):
|
||||
self.fill_eventbox()
|
||||
self.getPlotWidget().draw()
|
||||
if self.plot_method == 'fast':
|
||||
self.dataPlot.setPermText('MIN/MAX plot', color='red')
|
||||
self.dataPlot.setPermText(1, ' MIN/MAX plot ', color='red')
|
||||
else:
|
||||
self.dataPlot.setPermText()
|
||||
self.dataPlot.setPermText(1)
|
||||
self.dataPlot.setPermText(0, '| Number of traces: {} |'.format(len(self.getPlotWidget().getPlotDict())))
|
||||
|
||||
|
||||
def _setDirty(self):
|
||||
self.setDirty(True)
|
||||
|
72
autoPyLoT.py
72
autoPyLoT.py
@ -34,7 +34,7 @@ __version__ = _getVersionString()
|
||||
|
||||
|
||||
def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, eventid=None, savepath=None,
|
||||
savexml=True, station='all', iplot=0, ncores=0):
|
||||
savexml=True, station='all', iplot=0, ncores=0, obspyDMT_wfpath=False):
|
||||
"""
|
||||
Determine phase onsets automatically utilizing the automatic picking
|
||||
algorithms by Kueperkoch et al. 2010/2012.
|
||||
@ -94,7 +94,6 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
fig_dict = None
|
||||
fig_dict_wadatijack = None
|
||||
|
||||
locflag = 1
|
||||
if input_dict and isinstance(input_dict, dict):
|
||||
if 'parameter' in input_dict:
|
||||
parameter = input_dict['parameter']
|
||||
@ -110,10 +109,10 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
eventid = input_dict['eventid']
|
||||
if 'iplot' in input_dict:
|
||||
iplot = input_dict['iplot']
|
||||
if 'locflag' in input_dict:
|
||||
locflag = input_dict['locflag']
|
||||
if 'savexml' in input_dict:
|
||||
savexml = input_dict['savexml']
|
||||
if 'obspyDMT_wfpath' in input_dict:
|
||||
obspyDMT_wfpath = input_dict['obspyDMT_wfpath']
|
||||
|
||||
if not parameter:
|
||||
if inputfile:
|
||||
@ -151,7 +150,8 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
datastructure.setExpandFields(exf)
|
||||
|
||||
# check if default location routine NLLoc is available
|
||||
if real_None(parameter['nllocbin']) and locflag:
|
||||
if real_None(parameter['nllocbin']):
|
||||
locflag = 1
|
||||
# get NLLoc-root path
|
||||
nllocroot = parameter.get('nllocroot')
|
||||
# get path to NLLoc executable
|
||||
@ -167,7 +167,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
ttpat = parameter.get('ttpatter')
|
||||
# pattern of NLLoc-output file
|
||||
nllocoutpatter = parameter.get('outpatter')
|
||||
maxnumit = 3 # maximum number of iterations for re-picking
|
||||
maxnumit = 2 # maximum number of iterations for re-picking
|
||||
else:
|
||||
locflag = 0
|
||||
print(" !!! ")
|
||||
@ -175,6 +175,14 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
print("!!No source parameter estimation possible!!")
|
||||
print(" !!! ")
|
||||
|
||||
wfpath_extension = ''
|
||||
if obspyDMT_wfpath not in [None, False, 'False', '']:
|
||||
wfpath_extension = obspyDMT_wfpath
|
||||
print('Using obspyDMT structure. There will be no restitution, as pre-processed data are expected.')
|
||||
if wfpath_extension != 'processed':
|
||||
print('WARNING: Expecting wfpath_extension to be "processed" for'
|
||||
' pre-processed data but received "{}" instead!!!'.format(wfpath_extension))
|
||||
|
||||
if not input_dict:
|
||||
# started in production mode
|
||||
datapath = datastructure.expandDataPath()
|
||||
@ -219,6 +227,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
glocflag = locflag
|
||||
for eventpath in events:
|
||||
evID = os.path.split(eventpath)[-1]
|
||||
event_datapath = os.path.join(eventpath, wfpath_extension)
|
||||
fext = '.xml'
|
||||
filename = os.path.join(eventpath, 'PyLoT_' + evID + fext)
|
||||
try:
|
||||
@ -231,7 +240,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
pylot_event = Event(eventpath) # event should be path to event directory
|
||||
data.setEvtData(pylot_event)
|
||||
if fnames == 'None':
|
||||
data.setWFData(glob.glob(os.path.join(datapath, eventpath, '*')))
|
||||
data.setWFData(glob.glob(os.path.join(datapath, event_datapath, '*')))
|
||||
# the following is necessary because within
|
||||
# multiple event processing no event ID is provided
|
||||
# in autopylot.in
|
||||
@ -268,12 +277,18 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
wfdat = check4doubled(wfdat)
|
||||
wfdat = trim_station_components(wfdat, trim_start=True, trim_end=False)
|
||||
metadata = read_metadata(parameter.get('invdir'))
|
||||
# rotate stations to ZNE
|
||||
wfdat = check4rotated(wfdat, metadata)
|
||||
# TODO: (idea) read metadata from obspy_dmt database
|
||||
# if not wfpath_extension:
|
||||
# metadata = read_metadata(parameter.get('invdir'))
|
||||
# else:
|
||||
# metadata = None
|
||||
corr_dat = None
|
||||
if locflag:
|
||||
print("Restitute data ...")
|
||||
corr_dat = restitute_data(wfdat.copy(), *metadata, ncores=ncores)
|
||||
if metadata:
|
||||
# rotate stations to ZNE
|
||||
wfdat = check4rotated(wfdat, metadata)
|
||||
if locflag:
|
||||
print("Restitute data ...")
|
||||
corr_dat = restitute_data(wfdat.copy(), *metadata, ncores=ncores)
|
||||
if not corr_dat and locflag:
|
||||
locflag = 2
|
||||
print('Working on event %s. Stations: %s' % (eventpath, station))
|
||||
@ -331,7 +346,8 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
picks[stats]['P'].update(props)
|
||||
evt = moment_mag.updated_event()
|
||||
net_mw = moment_mag.net_magnitude()
|
||||
print("Network moment magnitude: %4.1f" % net_mw.mag)
|
||||
if net_mw is not None:
|
||||
print("Network moment magnitude: %4.1f" % net_mw.mag)
|
||||
# calculate local (Richter) magntiude
|
||||
WAscaling = parameter.get('WAscaling')
|
||||
magscaling = parameter.get('magscaling')
|
||||
@ -348,8 +364,15 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
evt = local_mag.updated_event(magscaling)
|
||||
net_ml = local_mag.net_magnitude(magscaling)
|
||||
print("Network local magnitude: %4.1f" % net_ml.mag)
|
||||
print("Network local magnitude scaled with:")
|
||||
print("%f * Ml + %f" % (magscaling[0], magscaling[1]))
|
||||
if magscaling == None:
|
||||
scaling = False
|
||||
elif magscaling[0] != 0 and magscaling[1] != 0:
|
||||
scaling = False
|
||||
else:
|
||||
scaling = True
|
||||
if scaling:
|
||||
print("Network local magnitude scaled with:")
|
||||
print("%f * Ml + %f" % (magscaling[0], magscaling[1]))
|
||||
else:
|
||||
print("autoPyLoT: No NLLoc-location file available!")
|
||||
print("No source parameter estimation possible!")
|
||||
@ -406,7 +429,8 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
picks[stats]['P'].update(props)
|
||||
evt = moment_mag.updated_event()
|
||||
net_mw = moment_mag.net_magnitude()
|
||||
print("Network moment magnitude: %4.1f" % net_mw.mag)
|
||||
if net_mw is not None:
|
||||
print("Network moment magnitude: %4.1f" % net_mw.mag)
|
||||
# calculate local (Richter) magntiude
|
||||
WAscaling = parameter.get('WAscaling')
|
||||
magscaling = parameter.get('magscaling')
|
||||
@ -424,8 +448,15 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
evt = local_mag.updated_event(magscaling)
|
||||
net_ml = local_mag.net_magnitude(magscaling)
|
||||
print("Network local magnitude: %4.1f" % net_ml.mag)
|
||||
print("Network local magnitude scaled with:")
|
||||
print("%f * Ml + %f" % (magscaling[0], magscaling[1]))
|
||||
if magscaling == None:
|
||||
scaling = False
|
||||
elif magscaling[0] != 0 and magscaling[1] != 0:
|
||||
scaling = False
|
||||
else:
|
||||
scaling = True
|
||||
if scaling:
|
||||
print("Network local magnitude scaled with:")
|
||||
print("%f * Ml + %f" % (magscaling[0], magscaling[1]))
|
||||
else:
|
||||
print("autoPyLoT: No NLLoc-location file available! Stop iteration!")
|
||||
locflag = 9
|
||||
@ -512,9 +543,12 @@ if __name__ == "__main__":
|
||||
parser.add_argument('-c', '-C', '--ncores', type=int,
|
||||
action='store', default=0,
|
||||
help='''optional, number of CPU cores used for parallel processing (default: all available(=0))''')
|
||||
parser.add_argument('-dmt', '-DMT', '--obspy_dmt_wfpath', type=str,
|
||||
action='store', default=False,
|
||||
help='''optional, wftype (raw, processed) used for obspyDMT database structure''')
|
||||
|
||||
cla = parser.parse_args()
|
||||
|
||||
picks = autoPyLoT(inputfile=str(cla.inputfile), fnames=str(cla.fnames),
|
||||
eventid=str(cla.eventid), savepath=str(cla.spath),
|
||||
ncores=cla.ncores, iplot=int(cla.iplot))
|
||||
ncores=cla.ncores, iplot=int(cla.iplot), obspyDMT_wfpath=str(cla.obspy_dmt_wfpath))
|
||||
|
@ -7,7 +7,7 @@
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt4 import QtCore
|
||||
from PySide import QtCore
|
||||
|
||||
qt_resource_data = "\
|
||||
\x00\x00\x9e\x04\
|
||||
|
@ -7,7 +7,7 @@
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt4 import QtCore
|
||||
from PySide import QtCore
|
||||
|
||||
qt_resource_data = "\
|
||||
\x00\x00\x9e\x04\
|
||||
|
@ -4,19 +4,19 @@
|
||||
%Parameters are optimized for %extent data sets!
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#main settings#
|
||||
#rootpath# %project path
|
||||
#datapath# %data path
|
||||
#database# %name of data base
|
||||
#eventID# %event ID for single event processing (* for all events found in database)
|
||||
#invdir# %full path to inventory or dataless-seed file
|
||||
/DATA/Insheim #rootpath# %project path
|
||||
EVENT_DATA/LOCAL #datapath# %data path
|
||||
2018.02_Insheim #database# %name of data base
|
||||
e0006.038.18 #eventID# %event ID for single event processing (* for all events found in database)
|
||||
/DATA/Insheim/STAT_INFO #invdir# %full path to inventory or dataless-seed file
|
||||
PILOT #datastructure# %choose data structure
|
||||
True #apverbose# %choose 'True' or 'False' for terminal output
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#NLLoc settings#
|
||||
None #nllocbin# %path to NLLoc executable
|
||||
None #nllocroot# %root of NLLoc-processing directory
|
||||
None #phasefile# %name of autoPyLoT-output phase file for NLLoc
|
||||
None #ctrfile# %name of autoPyLoT-output control file for NLLoc
|
||||
/home/ludger/NLLOC #nllocbin# %path to NLLoc executable
|
||||
/home/ludger/NLLOC/Insheim #nllocroot# %root of NLLoc-processing directory
|
||||
AUTOPHASES.obs #phasefile# %name of autoPyLoT-output phase file for NLLoc
|
||||
Insheim_min1d032016_auto.in #ctrfile# %name of autoPyLoT-output control file for NLLoc
|
||||
ttime #ttpatter# %pattern of NLLoc ttimes from grid
|
||||
AUTOLOC_nlloc #outpatter# %pattern of NLLoc-output file
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
@ -27,31 +27,31 @@ AUTOLOC_nlloc #outpatter# %pattern of
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#settings local magnitude#
|
||||
1.11 0.0009 -2.0 #WAscaling# %Scaling relation (log(Ao)+Alog(r)+Br+C) of Wood-Anderson amplitude Ao [nm] If zeros are set, original Richter magnitude is calculated!
|
||||
1.0382 -0.447 #magscaling# %Scaling relation for derived local magnitude [a*Ml+b]. If zeros are set, no scaling of network magnitude is applied!
|
||||
0.0 0.0 #magscaling# %Scaling relation for derived local magnitude [a*Ml+b]. If zeros are set, no scaling of network magnitude is applied!
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#filter settings#
|
||||
1.0 1.0 #minfreq# %Lower filter frequency [P, S]
|
||||
10.0 10.0 #maxfreq# %Upper filter frequency [P, S]
|
||||
2 2 #filter_order# %filter order [P, S]
|
||||
2.0 2.0 #minfreq# %Lower filter frequency [P, S]
|
||||
30.0 15.0 #maxfreq# %Upper filter frequency [P, S]
|
||||
3 3 #filter_order# %filter order [P, S]
|
||||
bandpass bandpass #filter_type# %filter type (bandpass, bandstop, lowpass, highpass) [P, S]
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#common settings picker#
|
||||
local #extent# %extent of array ("local", "regional" or "global")
|
||||
15.0 #pstart# %start time [s] for calculating CF for P-picking
|
||||
60.0 #pstop# %end time [s] for calculating CF for P-picking
|
||||
-1.0 #sstart# %start time [s] relative to P-onset for calculating CF for S-picking
|
||||
7.0 #pstart# %start time [s] for calculating CF for P-picking
|
||||
16.0 #pstop# %end time [s] for calculating CF for P-picking
|
||||
-0.5 #sstart# %start time [s] relative to P-onset for calculating CF for S-picking
|
||||
10.0 #sstop# %end time [s] after P-onset for calculating CF for S-picking
|
||||
True #use_taup# %use estimated traveltimes from TauPy for calculating windows for CF
|
||||
False #use_taup# %use estimated traveltimes from TauPy for calculating windows for CF
|
||||
iasp91 #taup_model# %define TauPy model for traveltime estimation
|
||||
2.0 10.0 #bpz1# %lower/upper corner freq. of first band pass filter Z-comp. [Hz]
|
||||
2.0 12.0 #bpz2# %lower/upper corner freq. of second band pass filter Z-comp. [Hz]
|
||||
2.0 8.0 #bph1# %lower/upper corner freq. of first band pass filter H-comp. [Hz]
|
||||
2.0 10.0 #bph2# %lower/upper corner freq. of second band pass filter z-comp. [Hz]
|
||||
2.0 20.0 #bpz1# %lower/upper corner freq. of first band pass filter Z-comp. [Hz]
|
||||
2.0 30.0 #bpz2# %lower/upper corner freq. of second band pass filter Z-comp. [Hz]
|
||||
2.0 10.0 #bph1# %lower/upper corner freq. of first band pass filter H-comp. [Hz]
|
||||
2.0 15.0 #bph2# %lower/upper corner freq. of second band pass filter z-comp. [Hz]
|
||||
#special settings for calculating CF#
|
||||
%!!Edit the following only if you know what you are doing!!%
|
||||
#Z-component#
|
||||
HOS #algoP# %choose algorithm for P-onset determination (HOS, ARZ, or AR3)
|
||||
7.0 #tlta# %for HOS-/AR-AIC-picker, length of LTA window [s]
|
||||
4.0 #tlta# %for HOS-/AR-AIC-picker, length of LTA window [s]
|
||||
4 #hosorder# %for HOS-picker, order of Higher Order Statistics
|
||||
2 #Parorder# %for AR-picker, order of AR process of Z-component
|
||||
1.2 #tdet1z# %for AR-picker, length of AR determination window [s] for Z-component, 1st pick
|
||||
@ -59,12 +59,12 @@ HOS #algoP# %choose algo
|
||||
0.6 #tdet2z# %for AR-picker, length of AR determination window [s] for Z-component, 2nd pick
|
||||
0.2 #tpred2z# %for AR-picker, length of AR prediction window [s] for Z-component, 2nd pick
|
||||
0.001 #addnoise# %add noise to seismogram for stable AR prediction
|
||||
3.0 0.1 0.5 1.0 #tsnrz# %for HOS/AR, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s]
|
||||
3.0 0.0 1.0 0.5 #tsnrz# %for HOS/AR, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s]
|
||||
3.0 #pickwinP# %for initial AIC pick, length of P-pick window [s]
|
||||
6.0 #Precalcwin# %for HOS/AR, window length [s] for recalculation of CF (relative to 1st pick)
|
||||
0.2 #aictsmooth# %for HOS/AR, take average of samples for smoothing of AIC-function [s]
|
||||
0.4 #aictsmooth# %for HOS/AR, take average of samples for smoothing of AIC-function [s]
|
||||
0.1 #tsmoothP# %for HOS/AR, take average of samples for smoothing CF [s]
|
||||
0.001 #ausP# %for HOS/AR, artificial uplift of samples (aus) of CF (P)
|
||||
0.4 #ausP# %for HOS/AR, artificial uplift of samples (aus) of CF (P)
|
||||
1.3 #nfacP# %for HOS/AR, noise factor for noise level determination (P)
|
||||
#H-components#
|
||||
ARH #algoS# %choose algorithm for S-onset determination (ARH or AR3)
|
||||
@ -75,7 +75,7 @@ ARH #algoS# %choose algo
|
||||
4 #Sarorder# %for AR-picker, order of AR process of H-components
|
||||
5.0 #Srecalcwin# %for AR-picker, window length [s] for recalculation of CF (2nd pick) (H)
|
||||
4.0 #pickwinS# %for initial AIC pick, length of S-pick window [s]
|
||||
2.0 0.3 1.5 1.0 #tsnrh# %for ARH/AR3, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s]
|
||||
2.0 0.2 1.5 1.0 #tsnrh# %for ARH/AR3, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s]
|
||||
1.0 #aictsmoothS# %for AIC-picker, take average of samples for smoothing of AIC-function [s]
|
||||
0.7 #tsmoothS# %for AR-picker, take average of samples for smoothing CF [s] (S)
|
||||
0.9 #ausS# %for HOS/AR, artificial uplift of samples (aus) of CF (S)
|
||||
@ -85,16 +85,16 @@ ARH #algoS# %choose algo
|
||||
2.0 #minFMSNR# %miniumum required SNR for first-motion determination
|
||||
0.2 #fmpickwin# %pick window around P onset for calculating zero crossings
|
||||
#quality assessment#
|
||||
0.02 0.04 0.08 0.16 #timeerrorsP# %discrete time errors [s] corresponding to picking weights [0 1 2 3] for P
|
||||
0.04 0.08 0.16 0.32 #timeerrorsS# %discrete time errors [s] corresponding to picking weights [0 1 2 3] for S
|
||||
0.04 0.08 0.16 0.32 #timeerrorsP# %discrete time errors [s] corresponding to picking weights [0 1 2 3] for P
|
||||
0.05 0.10 0.20 0.40 #timeerrorsS# %discrete time errors [s] corresponding to picking weights [0 1 2 3] for S
|
||||
0.8 #minAICPslope# %below this slope [counts/s] the initial P pick is rejected
|
||||
1.1 #minAICPSNR# %below this SNR the initial P pick is rejected
|
||||
1.0 #minAICSslope# %below this slope [counts/s] the initial S pick is rejected
|
||||
1.5 #minAICSSNR# %below this SNR the initial S pick is rejected
|
||||
1.0 #minsiglength# %length of signal part for which amplitudes must exceed noiselevel [s]
|
||||
1.0 #noisefactor# %noiselevel*noisefactor=threshold
|
||||
10.0 #minpercent# %required percentage of amplitudes exceeding threshold
|
||||
1.5 #zfac# %P-amplitude must exceed at least zfac times RMS-S amplitude
|
||||
6.0 #mdttolerance# %maximum allowed deviation of P picks from median [s]
|
||||
1.1 #noisefactor# %noiselevel*noisefactor=threshold
|
||||
50.0 #minpercent# %required percentage of amplitudes exceeding threshold
|
||||
1.1 #zfac# %P-amplitude must exceed at least zfac times RMS-S amplitude
|
||||
5.0 #mdttolerance# %maximum allowed deviation of P picks from median [s]
|
||||
1.0 #wdttolerance# %maximum allowed deviation from Wadati-diagram
|
||||
5.0 #jackfactor# %pick is removed if the variance of the subgroup with the pick removed is larger than the mean variance of all subgroups times safety factor
|
||||
2.0 #jackfactor# %pick is removed if the variance of the subgroup with the pick removed is larger than the mean variance of all subgroups times safety factor
|
||||
|
@ -6,6 +6,7 @@ Revised/extended summer 2017.
|
||||
|
||||
:author: Ludger Küperkoch / MAGS2 EP3 working group
|
||||
"""
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import obspy.core.event as ope
|
||||
@ -121,7 +122,13 @@ class Magnitude(object):
|
||||
|
||||
def net_magnitude(self, magscaling=None):
|
||||
if self:
|
||||
if magscaling is not None and str(magscaling) is not '[0.0, 0.0]':
|
||||
if magscaling == None:
|
||||
scaling = False
|
||||
elif magscaling[0] != 0 and magscaling[1] != 0:
|
||||
scaling = False
|
||||
else:
|
||||
scaling = True
|
||||
if scaling:
|
||||
# scaling necessary
|
||||
print("Scaling network magnitude ...")
|
||||
mag = ope.Magnitude(
|
||||
@ -140,7 +147,6 @@ class Magnitude(object):
|
||||
station_count=len(self.magnitudes),
|
||||
azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap)
|
||||
return mag
|
||||
return None
|
||||
|
||||
|
||||
class LocalMagnitude(Magnitude):
|
||||
@ -219,7 +225,7 @@ class LocalMagnitude(Magnitude):
|
||||
sqH = np.sqrt(power_sum)
|
||||
|
||||
# get time array
|
||||
th = np.arange(0, len(sqH) * dt, dt)
|
||||
th=np.arange(0, st[0].stats.npts/st[0].stats.sampling_rate, st[0].stats.delta)
|
||||
# get maximum peak within pick window
|
||||
iwin = getsignalwin(th, t0 - stime, self.calc_win)
|
||||
ii = min([iwin[len(iwin) - 1], len(th)])
|
||||
|
@ -15,7 +15,7 @@ from pylot.core.util.event import Event
|
||||
from pylot.core.util.utils import fnConstructor, full_range, remove_underscores, check4gaps, check4doubled, \
|
||||
check4rotated, trim_station_components
|
||||
import pylot.core.loc.velest as velest
|
||||
|
||||
from pylot.core.util.obspyDMT_interface import qml_from_obspyDMT
|
||||
|
||||
class Data(object):
|
||||
"""
|
||||
@ -43,7 +43,7 @@ class Data(object):
|
||||
elif isinstance(evtdata, dict):
|
||||
evt = readPILOTEvent(**evtdata)
|
||||
evtdata = evt
|
||||
elif isinstance(evtdata, str):
|
||||
elif type(evtdata) in [str, unicode]:
|
||||
try:
|
||||
cat = read_events(evtdata)
|
||||
if len(cat) is not 1:
|
||||
@ -60,6 +60,8 @@ class Data(object):
|
||||
raise NotImplementedError('PILOT location information '
|
||||
'read support not yet '
|
||||
'implemeted.')
|
||||
elif 'event.pkl' in evtdata:
|
||||
evtdata = qml_from_obspyDMT(evtdata)
|
||||
else:
|
||||
raise e
|
||||
else:
|
||||
@ -72,6 +74,7 @@ class Data(object):
|
||||
self.wforiginal = None
|
||||
self.cuttimes = None
|
||||
self.dirty = False
|
||||
self.processed = None
|
||||
|
||||
def __str__(self):
|
||||
return str(self.wfdata)
|
||||
@ -368,7 +371,7 @@ class Data(object):
|
||||
data.filter(**kwargs)
|
||||
self.dirty = True
|
||||
|
||||
def setWFData(self, fnames, checkRotated=False, metadata=None, obspy_dmt=False):
|
||||
def setWFData(self, fnames, fnames_syn=None, checkRotated=False, metadata=None):
|
||||
"""
|
||||
Clear current waveform data and set given waveform data
|
||||
:param fnames: waveform data names to append
|
||||
@ -377,30 +380,31 @@ class Data(object):
|
||||
self.wfdata = Stream()
|
||||
self.wforiginal = None
|
||||
self.wfsyn = Stream()
|
||||
wffnames = None
|
||||
wffnames_syn = None
|
||||
wfdir = 'processed' if 'processed' in [fname.split('/')[-1] for fname in fnames] else 'raw'
|
||||
if obspy_dmt:
|
||||
for fpath in fnames:
|
||||
if fpath.endswith(wfdir):
|
||||
wffnames = [os.path.join(fpath, fname) for fname in os.listdir(fpath)]
|
||||
if 'syngine' in fpath.split('/')[-1]:
|
||||
wffnames_syn = [os.path.join(fpath, fname) for fname in os.listdir(fpath)]
|
||||
else:
|
||||
wffnames = fnames
|
||||
if wffnames is not None:
|
||||
self.appendWFData(wffnames)
|
||||
if wffnames_syn is not None:
|
||||
self.appendWFData(wffnames_syn, synthetic=True)
|
||||
# if obspy_dmt:
|
||||
# wfdir = 'raw'
|
||||
# self.processed = False
|
||||
# for fname in fnames:
|
||||
# if fname.endswith('processed'):
|
||||
# wfdir = 'processed'
|
||||
# self.processed = True
|
||||
# break
|
||||
# for fpath in fnames:
|
||||
# if fpath.endswith(wfdir):
|
||||
# wffnames = [os.path.join(fpath, fname) for fname in os.listdir(fpath)]
|
||||
# if 'syngine' in fpath.split('/')[-1]:
|
||||
# wffnames_syn = [os.path.join(fpath, fname) for fname in os.listdir(fpath)]
|
||||
# else:
|
||||
# wffnames = fnames
|
||||
if fnames is not None:
|
||||
self.appendWFData(fnames)
|
||||
if fnames_syn is not None:
|
||||
self.appendWFData(fnames_syn, synthetic=True)
|
||||
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)
|
||||
@ -441,7 +445,7 @@ class Data(object):
|
||||
except SacIOError as se:
|
||||
warnmsg += '{0}\n{1}\n'.format(fname, se)
|
||||
if warnmsg:
|
||||
warnmsg = 'WARNING: unable to read\n' + warnmsg
|
||||
warnmsg = 'WARNING in appendWFData: unable to read waveform data\n' + warnmsg
|
||||
print(warnmsg)
|
||||
|
||||
def getWFData(self):
|
||||
|
@ -100,9 +100,9 @@ def autopickevent(data, param, iplot=0, fig_dict=None, fig_dict_wadatijack=None,
|
||||
|
||||
# quality control
|
||||
# median check and jackknife on P-onset times
|
||||
jk_checked_onsets = checkPonsets(all_onsets, mdttolerance, jackfactor, 1, fig_dict_wadatijack)
|
||||
jk_checked_onsets = checkPonsets(all_onsets, mdttolerance, jackfactor, iplot, fig_dict_wadatijack)
|
||||
# check S-P times (Wadati)
|
||||
wadationsets = wadaticheck(jk_checked_onsets, wdttolerance, 1, fig_dict_wadatijack)
|
||||
wadationsets = wadaticheck(jk_checked_onsets, wdttolerance, iplot, fig_dict_wadatijack)
|
||||
return wadationsets
|
||||
|
||||
|
||||
@ -1057,8 +1057,64 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
||||
# read your pylot.in for details!
|
||||
plt_flag = 0
|
||||
|
||||
# get picking parameter dictionaries
|
||||
p_params, s_params, first_motion_params, signal_length_params = get_pickparams(pickparam)
|
||||
# special parameters for P picking
|
||||
algoP = pickparam.get('algoP')
|
||||
pstart = pickparam.get('pstart')
|
||||
pstop = pickparam.get('pstop')
|
||||
thosmw = pickparam.get('tlta')
|
||||
tsnrz = pickparam.get('tsnrz')
|
||||
hosorder = pickparam.get('hosorder')
|
||||
bpz1 = pickparam.get('bpz1')
|
||||
bpz2 = pickparam.get('bpz2')
|
||||
pickwinP = pickparam.get('pickwinP')
|
||||
aictsmoothP = pickparam.get('aictsmooth')
|
||||
tsmoothP = pickparam.get('tsmoothP')
|
||||
ausP = pickparam.get('ausP')
|
||||
nfacP = pickparam.get('nfacP')
|
||||
tpred1z = pickparam.get('tpred1z')
|
||||
tdet1z = pickparam.get('tdet1z')
|
||||
tpred2z = pickparam.get('tpred2z')
|
||||
tdet2z = pickparam.get('tdet2z')
|
||||
Parorder = pickparam.get('Parorder')
|
||||
addnoise = pickparam.get('addnoise')
|
||||
Precalcwin = pickparam.get('Precalcwin')
|
||||
minAICPslope = pickparam.get('minAICPslope')
|
||||
minAICPSNR = pickparam.get('minAICPSNR')
|
||||
timeerrorsP = pickparam.get('timeerrorsP')
|
||||
# special parameters for S picking
|
||||
algoS = pickparam.get('algoS')
|
||||
sstart = pickparam.get('sstart')
|
||||
sstop = pickparam.get('sstop')
|
||||
use_taup = real_Bool(pickparam.get('use_taup'))
|
||||
taup_model = pickparam.get('taup_model')
|
||||
bph1 = pickparam.get('bph1')
|
||||
bph2 = pickparam.get('bph2')
|
||||
tsnrh = pickparam.get('tsnrh')
|
||||
pickwinS = pickparam.get('pickwinS')
|
||||
tpred1h = pickparam.get('tpred1h')
|
||||
tdet1h = pickparam.get('tdet1h')
|
||||
tpred2h = pickparam.get('tpred2h')
|
||||
tdet2h = pickparam.get('tdet2h')
|
||||
Sarorder = pickparam.get('Sarorder')
|
||||
aictsmoothS = pickparam.get('aictsmoothS')
|
||||
tsmoothS = pickparam.get('tsmoothS')
|
||||
ausS = pickparam.get('ausS')
|
||||
minAICSslope = pickparam.get('minAICSslope')
|
||||
minAICSSNR = pickparam.get('minAICSSNR')
|
||||
Srecalcwin = pickparam.get('Srecalcwin')
|
||||
nfacS = pickparam.get('nfacS')
|
||||
timeerrorsS = pickparam.get('timeerrorsS')
|
||||
# parameters for first-motion determination
|
||||
minFMSNR = pickparam.get('minFMSNR')
|
||||
fmpickwin = pickparam.get('fmpickwin')
|
||||
minfmweight = pickparam.get('minfmweight')
|
||||
# parameters for checking signal length
|
||||
minsiglength = pickparam.get('minsiglength')
|
||||
minpercent = pickparam.get('minpercent')
|
||||
nfacsl = pickparam.get('noisefactor')
|
||||
# parameter to check for spuriously picked S onset
|
||||
zfac = pickparam.get('zfac')
|
||||
# path to inventory-, dataless- or resp-files
|
||||
|
||||
# initialize output
|
||||
Pweight = 4 # weight for P onset
|
||||
@ -1159,6 +1215,8 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
||||
if p_params['use_taup'] is True:
|
||||
Lc = np.inf
|
||||
print('autopickstation: use_taup flag active.')
|
||||
if not metadata:
|
||||
metadata = [None, None]
|
||||
if not metadata[1]:
|
||||
print('Warning: Could not use TauPy to estimate onsets as there are no metadata given.')
|
||||
else:
|
||||
@ -1207,7 +1265,7 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
||||
return
|
||||
|
||||
Ldiff = Lwf - abs(Lc)
|
||||
if Ldiff < 0 or pstop <= pstart:
|
||||
if Ldiff <= 0 or pstop <= pstart or pstop - pstart <= thosmw:
|
||||
msg = 'autopickstation: Cutting times are too large for actual ' \
|
||||
'waveform!\nUsing entire waveform instead!'
|
||||
if verbose: print(msg)
|
||||
@ -1345,8 +1403,8 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
||||
elif p_params['algoP'] == 'ARZ':
|
||||
# calculate ARZ-CF using subclass ARZcf of class
|
||||
# CharcteristicFunction
|
||||
cf2 = ARZcf(z_copy, cuttimes2, p_params['tpred1z'], p_params['Parorder'], p_params['tdet1z'],
|
||||
p_params['addnoise']) # instance of ARZcf
|
||||
cf2 = ARZcf(z_copy, cuttimes2, tpred2z, Parorder, tdet2z,
|
||||
addnoise) # instance of ARZcf
|
||||
##############################################################
|
||||
# get refined onset time from CF2 using class Picker
|
||||
assert isinstance(cf2, CharacteristicFunction), 'cf2 is not set ' \
|
||||
@ -1401,7 +1459,8 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
||||
msg = "autopickstation: P-weight: {0}, " \
|
||||
"SNR: {1}, SNR[dB]: {2}, Polarity: {3}".format(Pweight, SNRP, SNRPdB, FM)
|
||||
print(msg)
|
||||
msg = 'autopickstation: Refined P-Pick: {} s | P-Error: {} s'.format(mpickP, Perror)
|
||||
msg = 'autopickstation: Refind P-Pick: {} s | P-Error: {} s'.format(zdat[0].stats.starttime \
|
||||
+ mpickP, Perror)
|
||||
print(msg)
|
||||
Sflag = 1
|
||||
|
||||
@ -1667,7 +1726,8 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
||||
lpickS = lpick[ipick]
|
||||
Serror = pickerr[ipick]
|
||||
|
||||
msg = 'autopickstation: Refined S-Pick: {} s | S-Error: {} s'.format(mpickS, Serror)
|
||||
msg = 'autopickstation: Refined S-Pick: {} s | S-Error: {} s'.format(hdat[0].stats.starttime \
|
||||
+ mpickS, Serror)
|
||||
print(msg)
|
||||
|
||||
# get SNR
|
||||
|
@ -78,7 +78,7 @@ class CharacteristicFunction(object):
|
||||
return self.cut
|
||||
|
||||
def setCut(self, cut):
|
||||
self.cut = cut
|
||||
self.cut = (int(cut[0]), int(cut[1]))
|
||||
|
||||
def getTime1(self):
|
||||
return self.t1
|
||||
|
@ -233,12 +233,41 @@ class AICPicker(AutoPicker):
|
||||
|
||||
# quality assessment using SNR and slope from CF
|
||||
if self.Pick is not None:
|
||||
self.Data[0].data = check_counts_ms(self.Data[0].data)
|
||||
# get noise window
|
||||
inoise = getnoisewin(self.Tcf, self.Pick, self.TSNR[0], self.TSNR[1])
|
||||
# check, if these are counts or m/s, important for slope estimation!
|
||||
# this is quick and dirty, better solution? #Todo wtf
|
||||
if max(self.Data[0].data < 1e-3) and max(self.Data[0].data >= 1e-6):
|
||||
self.Data[0].data = self.Data[0].data * 1000000.
|
||||
elif max(self.Data[0].data < 1e-6):
|
||||
self.Data[0].data = self.Data[0].data * 1e13
|
||||
# get signal window
|
||||
isignal = getsignalwin(self.Tcf, self.Pick, self.TSNR[2])
|
||||
if len(isignal) == 0:
|
||||
return
|
||||
ii = min([isignal[len(isignal) - 1], len(self.Tcf)])
|
||||
isignal = isignal[0:ii]
|
||||
try:
|
||||
self.Data[0].data[isignal]
|
||||
except IndexError as e:
|
||||
msg = "Time series out of bounds! {}".format(e)
|
||||
print(msg)
|
||||
return
|
||||
# calculate SNR from CF
|
||||
# subtract beginning of Tcf to get sample index in self.Data, which
|
||||
# is cut out off trace
|
||||
self.SNR = getSNR(self.Data, self.TSNR, self.Pick-self.Tcf[0])[0] # TODO Check wether this yields similar results
|
||||
self.SNR = max(abs(self.Data[0].data[isignal])) / \
|
||||
abs(np.mean(self.Data[0].data[inoise]))
|
||||
# calculate slope from CF after initial pick
|
||||
# get slope window
|
||||
tslope = self.TSNR[3] # slope determination window
|
||||
tsafety = self.TSNR[1] # safety gap, AIC is usually a little bit too late
|
||||
if tsafety >= 0:
|
||||
islope = np.where((self.Tcf <= min([self.Pick + tslope + tsafety, self.Tcf[-1]])) \
|
||||
& (self.Tcf >= self.Pick)) # TODO: put this in a seperate function like getsignalwin
|
||||
else:
|
||||
islope = np.where((self.Tcf <= min([self.Pick + tslope, self.Tcf[-1]])) \
|
||||
& (self.Tcf >= self.Pick + tsafety)) # TODO: put this in a seperate function like getsignalwin
|
||||
# find maximum within slope determination window
|
||||
# 'cause slope should be calculated up to first local minimum only!
|
||||
try:
|
||||
self.slope, iislope, datafit = calcSlope(self.Data, self.aicsmooth, self.Tcf, self.Pick, self.TSNR)
|
||||
except Exception:
|
||||
@ -264,6 +293,56 @@ class AICPicker(AutoPicker):
|
||||
pass
|
||||
plt.close(fig)
|
||||
return
|
||||
if len(dataslope) < 2:
|
||||
print('No or not enough data in slope window found!')
|
||||
return
|
||||
try:
|
||||
imaxs, = argrelmax(dataslope)
|
||||
imaxs.size
|
||||
imax = imaxs[0]
|
||||
except ValueError as e:
|
||||
print(e, 'picker: argrelmax not working!')
|
||||
imax = np.argmax(dataslope)
|
||||
iislope = islope[0][0:imax + 1]
|
||||
if len(iislope) < 2:
|
||||
# calculate slope from initial onset to maximum of AIC function
|
||||
print("AICPicker: Not enough data samples left for slope calculation!")
|
||||
print("Calculating slope from initial onset to maximum of AIC function ...")
|
||||
imax = np.argmax(aicsmooth[islope[0][0:-1]])
|
||||
if imax == 0:
|
||||
print("AICPicker: Maximum for slope determination right at the beginning of the window!")
|
||||
print("Choose longer slope determination window!")
|
||||
if self.iplot > 1:
|
||||
if self.fig == None or self.fig == 'None':
|
||||
fig = plt.figure()
|
||||
plt_flag = 1
|
||||
else:
|
||||
fig = self.fig
|
||||
ax = fig.add_subplot(111)
|
||||
x = self.Data[0].data
|
||||
ax.plot(self.Tcf, x / max(x), color=self._linecolor, linewidth=0.7, label='(HOS-/AR-) Data')
|
||||
ax.plot(self.Tcf, aicsmooth / max(aicsmooth), 'r', label='Smoothed AIC-CF')
|
||||
ax.legend(loc=1)
|
||||
ax.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
|
||||
ax.set_yticks([])
|
||||
ax.set_title(self.Data[0].stats.station)
|
||||
if plt_flag == 1:
|
||||
fig.show()
|
||||
try: input()
|
||||
except SyntaxError: pass
|
||||
plt.close(fig)
|
||||
return
|
||||
iislope = islope[0][0:imax+1]
|
||||
dataslope = self.Data[0].data[iislope]
|
||||
# calculate slope as polynomal fit of order 1
|
||||
xslope = np.arange(0, len(dataslope), 1)
|
||||
P = np.polyfit(xslope, dataslope, 1)
|
||||
datafit = np.polyval(P, xslope)
|
||||
if datafit[0] >= datafit[-1]:
|
||||
print('AICPicker: Negative slope, bad onset skipped!')
|
||||
else:
|
||||
self.slope = 1 / (len(dataslope) * self.Data[0].stats.delta) * (datafit[-1] - datafit[0])
|
||||
|
||||
else:
|
||||
self.SNR = -1
|
||||
self.slope = -1
|
||||
@ -305,24 +384,23 @@ class AICPicker(AutoPicker):
|
||||
label='Slope Window')
|
||||
ax2.plot(self.Tcf[iislope], datafit, 'g', linewidth=2, label='Slope')
|
||||
|
||||
ax1.set_title('Station %s, SNR=%7.2f, Slope= %12.2f counts/s' % (self.Data[0].stats.station,
|
||||
self.SNR, self.slope))
|
||||
if self.slope is not None:
|
||||
ax1.set_title('Station %s, SNR=%7.2f, Slope= %12.2f counts/s' % (self.Data[0].stats.station,
|
||||
self.SNR, self.slope))
|
||||
else:
|
||||
ax1.set_title('Station %s, SNR=%7.2f' % (self.Data[0].stats.station, self.SNR))
|
||||
ax2.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
|
||||
ax2.set_ylabel('Counts')
|
||||
ax2.set_yticks([])
|
||||
ax2.legend(loc=1)
|
||||
if plt_flag == 1:
|
||||
fig.show()
|
||||
try: input()
|
||||
except SyntaxError: pass
|
||||
plt.close(fig)
|
||||
else:
|
||||
ax1.set_title(self.Data[0].stats.station)
|
||||
if plt_flag == 1:
|
||||
fig.show()
|
||||
try: input()
|
||||
except SyntaxError: pass
|
||||
plt.close(fig)
|
||||
|
||||
if plt_flag == 1:
|
||||
fig.show()
|
||||
try: input()
|
||||
except SyntaxError: pass
|
||||
plt.close(fig)
|
||||
|
||||
if self.Pick == None:
|
||||
print('AICPicker: Could not find minimum, picking window too short?')
|
||||
|
458
pylot/core/util/array_map.py
Normal file
458
pylot/core/util/array_map.py
Normal file
@ -0,0 +1,458 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import obspy
|
||||
from PySide import QtGui
|
||||
from mpl_toolkits.basemap import Basemap
|
||||
from matplotlib.figure import Figure
|
||||
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
|
||||
from pylot.core.util.widgets import PickDlg, PylotCanvas
|
||||
from scipy.interpolate import griddata
|
||||
|
||||
plt.interactive(False)
|
||||
|
||||
|
||||
class Array_map(QtGui.QWidget):
|
||||
def __init__(self, parent, figure=None):
|
||||
'''
|
||||
Create a map of the array.
|
||||
:param parent: PyLoT Mainwindow class
|
||||
:param figure:
|
||||
'''
|
||||
QtGui.QWidget.__init__(self)
|
||||
self._parent = parent
|
||||
self.metadata_type = parent.metadata[0]
|
||||
self.metadata = parent.metadata[1]
|
||||
self.picks = None
|
||||
self.picks_dict = None
|
||||
self.autopicks_dict = None
|
||||
self.eventLoc = None
|
||||
self.figure = figure
|
||||
self.init_graphics()
|
||||
self.init_stations()
|
||||
self.init_basemap(resolution='l')
|
||||
self.init_map()
|
||||
self._style = parent._style
|
||||
# self.show()
|
||||
|
||||
def init_map(self):
|
||||
self.init_lat_lon_dimensions()
|
||||
self.init_lat_lon_grid()
|
||||
self.init_x_y_dimensions()
|
||||
self.connectSignals()
|
||||
self.draw_everything()
|
||||
self.canvas.setZoomBorders2content()
|
||||
|
||||
def onpick(self, event):
|
||||
ind = event.ind
|
||||
button = event.mouseevent.button
|
||||
if ind == [] or not button == 1:
|
||||
return
|
||||
data = self._parent.get_data().getWFData()
|
||||
for index in ind:
|
||||
station = str(self._station_onpick_ids[index].split('.')[-1])
|
||||
try:
|
||||
data = data.select(station=station)
|
||||
if not data:
|
||||
self._warn('No data for station {}'.format(station))
|
||||
return
|
||||
pickDlg = PickDlg(self._parent, parameter=self._parent._inputs,
|
||||
data=data,
|
||||
station=station,
|
||||
picks=self._parent.get_current_event().getPick(station),
|
||||
autopicks=self._parent.get_current_event().getAutopick(station),
|
||||
filteroptions=self._parent.filteroptions)
|
||||
except Exception as e:
|
||||
message = 'Could not generate Plot for station {st}.\n {er}'.format(st=station, er=e)
|
||||
self._warn(message)
|
||||
print(message, e)
|
||||
return
|
||||
pyl_mw = self._parent
|
||||
try:
|
||||
if pickDlg.exec_():
|
||||
pyl_mw.setDirty(True)
|
||||
pyl_mw.update_status('picks accepted ({0})'.format(station))
|
||||
replot = pyl_mw.get_current_event().setPick(station, pickDlg.getPicks())
|
||||
self._refresh_drawings()
|
||||
if replot:
|
||||
pyl_mw.plotWaveformData()
|
||||
pyl_mw.drawPicks()
|
||||
pyl_mw.draw()
|
||||
else:
|
||||
pyl_mw.drawPicks(station)
|
||||
pyl_mw.draw()
|
||||
else:
|
||||
pyl_mw.update_status('picks discarded ({0})'.format(station))
|
||||
except Exception as e:
|
||||
message = 'Could not save picks for station {st}.\n{er}'.format(st=station, er=e)
|
||||
self._warn(message)
|
||||
print(message, e)
|
||||
|
||||
def connectSignals(self):
|
||||
self.comboBox_phase.currentIndexChanged.connect(self._refresh_drawings)
|
||||
self.comboBox_am.currentIndexChanged.connect(self._refresh_drawings)
|
||||
self.canvas.mpl_connect('motion_notify_event', self.mouse_moved)
|
||||
#self.zoom_id = self.basemap.ax.figure.canvas.mpl_connect('scroll_event', self.zoom)
|
||||
|
||||
def _from_dict(self, function, key):
|
||||
return function(self.stations_dict.values(), key=lambda x: x[key])[key]
|
||||
|
||||
def get_min_from_stations(self, key):
|
||||
return self._from_dict(min, key)
|
||||
|
||||
def get_max_from_stations(self, key):
|
||||
return self._from_dict(max, key)
|
||||
|
||||
def get_min_from_picks(self):
|
||||
return min(self.picks_rel.values())
|
||||
|
||||
def get_max_from_picks(self):
|
||||
return max(self.picks_rel.values())
|
||||
|
||||
def mouse_moved(self, event):
|
||||
if not event.inaxes == self.main_ax:
|
||||
return
|
||||
x = event.xdata
|
||||
y = event.ydata
|
||||
lat, lon = self.basemap(x, y, inverse=True)
|
||||
self.status_label.setText('Latitude: {}, Longitude: {}'.format(lat, lon))
|
||||
|
||||
def current_picks_dict(self):
|
||||
picktype = self.comboBox_am.currentText()
|
||||
auto_manu = {'auto': self.autopicks_dict,
|
||||
'manual': self.picks_dict}
|
||||
return auto_manu[picktype]
|
||||
|
||||
def init_graphics(self):
|
||||
if not self.figure:
|
||||
self.figure = Figure()
|
||||
|
||||
self.status_label = QtGui.QLabel()
|
||||
|
||||
self.main_ax = self.figure.add_subplot(111)
|
||||
self.canvas = PylotCanvas(self.figure, parent=self._parent, multicursor=True,
|
||||
panZoomX=False, panZoomY=False)
|
||||
|
||||
self.main_box = QtGui.QVBoxLayout()
|
||||
self.setLayout(self.main_box)
|
||||
|
||||
self.top_row = QtGui.QHBoxLayout()
|
||||
self.main_box.addLayout(self.top_row, 1)
|
||||
|
||||
self.comboBox_phase = QtGui.QComboBox()
|
||||
self.comboBox_phase.insertItem(0, 'P')
|
||||
self.comboBox_phase.insertItem(1, 'S')
|
||||
|
||||
self.comboBox_am = QtGui.QComboBox()
|
||||
self.comboBox_am.insertItem(0, 'auto')
|
||||
self.comboBox_am.insertItem(1, 'manual')
|
||||
|
||||
self.top_row.addWidget(QtGui.QLabel('Select a phase: '))
|
||||
self.top_row.addWidget(self.comboBox_phase)
|
||||
self.top_row.setStretch(1, 1) # set stretch of item 1 to 1
|
||||
self.top_row.addWidget(QtGui.QLabel('Pick type: '))
|
||||
self.top_row.addWidget(self.comboBox_am)
|
||||
self.top_row.setStretch(3, 1) # set stretch of item 1 to 1
|
||||
|
||||
self.main_box.addWidget(self.canvas, 1)
|
||||
self.main_box.addWidget(self.status_label, 0)
|
||||
|
||||
|
||||
def init_stations(self):
|
||||
def stat_info_from_parser(parser):
|
||||
stations_dict = {}
|
||||
for station in parser.stations:
|
||||
station_name = station[0].station_call_letters
|
||||
network_name = station[0].network_code
|
||||
if not station_name in stations_dict.keys():
|
||||
st_id = network_name + '.' + station_name
|
||||
stations_dict[st_id] = {'latitude': station[0].latitude,
|
||||
'longitude': station[0].longitude}
|
||||
return stations_dict
|
||||
|
||||
def stat_info_from_inventory(inventory):
|
||||
stations_dict = {}
|
||||
for network in inventory.networks:
|
||||
for station in network.stations:
|
||||
station_name = station.code
|
||||
network_name = network_name.code
|
||||
if not station_name in stations_dict.keys():
|
||||
st_id = network_name + '.' + station_name
|
||||
stations_dict[st_id] = {'latitude': station[0].latitude,
|
||||
'longitude': station[0].longitude}
|
||||
return stations_dict
|
||||
|
||||
read_stat = {'xml': stat_info_from_inventory,
|
||||
'dless': stat_info_from_parser}
|
||||
|
||||
self.stations_dict = read_stat[self.metadata_type](self.metadata)
|
||||
self.latmin = self.get_min_from_stations('latitude')
|
||||
self.lonmin = self.get_min_from_stations('longitude')
|
||||
self.latmax = self.get_max_from_stations('latitude')
|
||||
self.lonmax = self.get_max_from_stations('longitude')
|
||||
|
||||
def init_picks(self):
|
||||
def get_picks(station_dict):
|
||||
picks = {}
|
||||
phase = self.comboBox_phase.currentText()
|
||||
for st_id in station_dict.keys():
|
||||
try:
|
||||
station_name = st_id.split('.')[-1]
|
||||
pick = self.current_picks_dict()[station_name][phase]
|
||||
if pick['picker'] == 'auto':
|
||||
if pick['weight'] > 3:
|
||||
continue
|
||||
picks[st_id] = pick['mpp']
|
||||
except KeyError:
|
||||
continue
|
||||
except Exception as e:
|
||||
print('Cannot display pick for station {}. Reason: {}'.format(station_name, e))
|
||||
return picks
|
||||
|
||||
def get_picks_rel(picks):
|
||||
picks_rel = {}
|
||||
picks_utc = []
|
||||
for pick in picks.values():
|
||||
if type(pick) is obspy.core.utcdatetime.UTCDateTime:
|
||||
picks_utc.append(pick)
|
||||
self._earliest_picktime = min(picks_utc)
|
||||
for st_id, pick in picks.items():
|
||||
if type(pick) is obspy.core.utcdatetime.UTCDateTime:
|
||||
pick -= self._earliest_picktime
|
||||
picks_rel[st_id] = pick
|
||||
return picks_rel
|
||||
|
||||
self.picks = get_picks(self.stations_dict)
|
||||
self.picks_rel = get_picks_rel(self.picks)
|
||||
|
||||
def init_lat_lon_dimensions(self):
|
||||
# init minimum and maximum lon and lat dimensions
|
||||
self.londim = self.lonmax - self.lonmin
|
||||
self.latdim = self.latmax - self.latmin
|
||||
|
||||
def init_x_y_dimensions(self):
|
||||
# transformation of lat/lon to ax coordinate system
|
||||
for st_id, coords in self.stations_dict.items():
|
||||
lat, lon = coords['latitude'], coords['longitude']
|
||||
coords['x'], coords['y'] = self.basemap(lon, lat)
|
||||
|
||||
self.xdim = self.get_max_from_stations('x') - self.get_min_from_stations('x')
|
||||
self.ydim = self.get_max_from_stations('y') - self.get_min_from_stations('y')
|
||||
|
||||
def init_basemap(self, resolution='l'):
|
||||
# basemap = Basemap(projection=projection, resolution = resolution, ax=self.main_ax)
|
||||
width = 5e6
|
||||
height = 2e6
|
||||
basemap = Basemap(projection='lcc', resolution=resolution, ax=self.main_ax,
|
||||
width=width, height=height,
|
||||
lat_0=(self.latmin + self.latmax) / 2.,
|
||||
lon_0=(self.lonmin + self.lonmax) / 2.)
|
||||
|
||||
# basemap.fillcontinents(color=None, lake_color='aqua',zorder=1)
|
||||
basemap.drawmapboundary(zorder=2) # fill_color='darkblue')
|
||||
basemap.shadedrelief(zorder=3)
|
||||
basemap.drawcountries(zorder=4)
|
||||
basemap.drawstates(zorder=5)
|
||||
basemap.drawcoastlines(zorder=6)
|
||||
# labels = [left,right,top,bottom]
|
||||
parallels = np.arange(-90, 90, 5.)
|
||||
parallels_small = np.arange(-90, 90, 2.5)
|
||||
basemap.drawparallels(parallels_small, linewidth=0.5, zorder=7)
|
||||
basemap.drawparallels(parallels, zorder=7)
|
||||
meridians = np.arange(-180, 180, 5.)
|
||||
meridians_small = np.arange(-180, 180, 2.5)
|
||||
basemap.drawmeridians(meridians_small, linewidth=0.5, zorder=7)
|
||||
basemap.drawmeridians(meridians, zorder=7)
|
||||
self.basemap = basemap
|
||||
self.figure._tight = True
|
||||
self.figure.tight_layout()
|
||||
|
||||
def init_lat_lon_grid(self, nstep=250):
|
||||
# create a regular grid to display colormap
|
||||
lataxis = np.linspace(self.latmin, self.latmax, nstep)
|
||||
lonaxis = np.linspace(self.lonmin, self.lonmax, nstep)
|
||||
self.longrid, self.latgrid = np.meshgrid(lonaxis, lataxis)
|
||||
|
||||
def init_picksgrid(self):
|
||||
picks, lats, lons = self.get_picks_lat_lon()
|
||||
try:
|
||||
self.picksgrid_active = griddata((lats, lons), picks, (self.latgrid, self.longrid),
|
||||
method='linear')
|
||||
except Exception as e:
|
||||
self._warn('Could not init picksgrid: {}'.format(e))
|
||||
|
||||
def get_st_lat_lon_for_plot(self):
|
||||
stations = []
|
||||
latitudes = []
|
||||
longitudes = []
|
||||
for st_id, coords in self.stations_dict.items():
|
||||
stations.append(st_id)
|
||||
latitudes.append(coords['latitude'])
|
||||
longitudes.append(coords['longitude'])
|
||||
return stations, latitudes, longitudes
|
||||
|
||||
def get_st_x_y_for_plot(self):
|
||||
stations = []
|
||||
xs = []
|
||||
ys = []
|
||||
for st_id, coords in self.stations_dict.items():
|
||||
stations.append(st_id)
|
||||
xs.append(coords['x'])
|
||||
ys.append(coords['y'])
|
||||
return stations, xs, ys
|
||||
|
||||
def get_picks_lat_lon(self):
|
||||
picks = []
|
||||
latitudes = []
|
||||
longitudes = []
|
||||
for st_id, pick in self.picks_rel.items():
|
||||
picks.append(pick)
|
||||
latitudes.append(self.stations_dict[st_id]['latitude'])
|
||||
longitudes.append(self.stations_dict[st_id]['longitude'])
|
||||
return picks, latitudes, longitudes
|
||||
|
||||
def draw_contour_filled(self, nlevel='50'):
|
||||
levels = np.linspace(self.get_min_from_picks(), self.get_max_from_picks(), nlevel)
|
||||
self.contourf = self.basemap.contourf(self.longrid, self.latgrid, self.picksgrid_active,
|
||||
levels, latlon=True, zorder=9, alpha=0.5)
|
||||
|
||||
def scatter_all_stations(self):
|
||||
stations, lats, lons = self.get_st_lat_lon_for_plot()
|
||||
self.sc = self.basemap.scatter(lons, lats, 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)
|
||||
self._station_onpick_ids = stations
|
||||
if self.eventLoc:
|
||||
lats, lons = self.eventLoc
|
||||
self.sc_event = self.basemap.scatter(lons, lats, s=100, facecolor='red',
|
||||
latlon=True, zorder=11, label='Event (might be outside map region)')
|
||||
|
||||
def scatter_picked_stations(self):
|
||||
picks, lats, lons = self.get_picks_lat_lon()
|
||||
# workaround because of an issue with latlon transformation of arrays with len <3
|
||||
if len(lons) <= 2 and len(lats) <= 2:
|
||||
self.sc_picked = self.basemap.scatter(lons[0], lats[0], s=50, facecolor='white',
|
||||
c=picks[0], latlon=True, zorder=11, label='Picked')
|
||||
if len(lons) == 2 and len(lats) == 2:
|
||||
self.sc_picked = self.basemap.scatter(lons[1], lats[1], s=50, facecolor='white',
|
||||
c=picks[1], latlon=True, zorder=11)
|
||||
else:
|
||||
self.sc_picked = self.basemap.scatter(lons, lats, s=50, facecolor='white',
|
||||
c=picks, latlon=True, zorder=11, label='Picked')
|
||||
|
||||
def annotate_ax(self):
|
||||
self.annotations = []
|
||||
stations, xs, ys = self.get_st_x_y_for_plot()
|
||||
for st, x, y in zip(stations, xs, ys):
|
||||
self.annotations.append(self.main_ax.annotate(' %s' % st, xy=(x, y),
|
||||
fontsize='x-small', color='white', zorder=12))
|
||||
self.legend = self.main_ax.legend(loc=1)
|
||||
self.legend.get_frame().set_facecolor((1, 1, 1, 0.75))
|
||||
|
||||
def add_cbar(self, label):
|
||||
self.cbax_bg = inset_axes(self.main_ax, width="6%", height="75%", loc=5)
|
||||
cbax = inset_axes(self.main_ax, width='2%', height='70%', loc=5)
|
||||
cbar = self.main_ax.figure.colorbar(self.sc_picked, cax = cbax)
|
||||
cbar.set_label(label)
|
||||
cbax.yaxis.tick_left()
|
||||
cbax.yaxis.set_label_position('left')
|
||||
for spine in self.cbax_bg.spines.values():
|
||||
spine.set_visible(False)
|
||||
self.cbax_bg.yaxis.set_ticks([])
|
||||
self.cbax_bg.xaxis.set_ticks([])
|
||||
self.cbax_bg.patch.set_facecolor((1, 1, 1, 0.75))
|
||||
return cbar
|
||||
|
||||
def refresh_drawings(self, picks=None, autopicks=None):
|
||||
self.picks_dict = picks
|
||||
self.autopicks_dict = autopicks
|
||||
self._refresh_drawings()
|
||||
|
||||
def _refresh_drawings(self):
|
||||
self.remove_drawings()
|
||||
self.draw_everything()
|
||||
|
||||
def draw_everything(self):
|
||||
if self.picks_dict or self.autopicks_dict:
|
||||
self.init_picks()
|
||||
if len(self.picks) >= 3:
|
||||
self.init_picksgrid()
|
||||
self.draw_contour_filled()
|
||||
self.scatter_all_stations()
|
||||
if self.picks_dict or self.autopicks_dict:
|
||||
self.scatter_picked_stations()
|
||||
self.cbar = self.add_cbar(label='Time relative to first onset ({}) [s]'.format(self._earliest_picktime))
|
||||
self.comboBox_phase.setEnabled(True)
|
||||
else:
|
||||
self.comboBox_phase.setEnabled(False)
|
||||
self.annotate_ax()
|
||||
self.canvas.draw()
|
||||
|
||||
def remove_drawings(self):
|
||||
if hasattr(self, 'cbar'):
|
||||
self.cbar.remove()
|
||||
self.cbax_bg.remove()
|
||||
del (self.cbar, self.cbax_bg)
|
||||
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, 'contourf'):
|
||||
self.remove_contourf()
|
||||
del (self.contourf)
|
||||
if hasattr(self, 'cid'):
|
||||
self.canvas.mpl_disconnect(self.cid)
|
||||
del (self.cid)
|
||||
try:
|
||||
self.sc.remove()
|
||||
except Exception as e:
|
||||
print('Warning: could not remove station scatter plot.\nReason: {}'.format(e))
|
||||
try:
|
||||
self.legend.remove()
|
||||
except Exception as e:
|
||||
print('Warning: could not remove legend. Reason: {}'.format(e))
|
||||
self.canvas.draw()
|
||||
|
||||
def remove_contourf(self):
|
||||
for item in self.contourf.collections:
|
||||
item.remove()
|
||||
|
||||
def remove_annotations(self):
|
||||
for annotation in self.annotations:
|
||||
annotation.remove()
|
||||
|
||||
def zoom(self, event):
|
||||
map = self.basemap
|
||||
xlim = map.ax.get_xlim()
|
||||
ylim = map.ax.get_ylim()
|
||||
x, y = event.xdata, event.ydata
|
||||
zoom = {'up': 1. / 2.,
|
||||
'down': 2.}
|
||||
|
||||
if not event.xdata or not event.ydata:
|
||||
return
|
||||
|
||||
if event.button in zoom:
|
||||
factor = zoom[event.button]
|
||||
xdiff = (xlim[1] - xlim[0]) * factor
|
||||
xl = x - 0.5 * xdiff
|
||||
xr = x + 0.5 * xdiff
|
||||
ydiff = (ylim[1] - ylim[0]) * factor
|
||||
yb = y - 0.5 * ydiff
|
||||
yt = y + 0.5 * ydiff
|
||||
|
||||
if xl < map.xmin or yb < map.ymin or xr > map.xmax or yt > map.ymax:
|
||||
xl, xr = map.xmin, map.xmax
|
||||
yb, yt = map.ymin, map.ymax
|
||||
map.ax.set_xlim(xl, xr)
|
||||
map.ax.set_ylim(yb, yt)
|
||||
map.ax.figure.canvas.draw()
|
||||
|
||||
def _warn(self, message):
|
||||
self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning,
|
||||
'Warning', message)
|
||||
self.qmb.show()
|
@ -12,6 +12,186 @@ from pylot.core.util.utils import key_for_set_value, find_in_list, \
|
||||
remove_underscores, gen_Pool
|
||||
|
||||
|
||||
class Metadata(object):
|
||||
def __init__(self, inventory=None):
|
||||
self.inventories = []
|
||||
if os.path.isdir(inventory):
|
||||
self.add_inventory(inventory)
|
||||
if os.path.isfile(inventory):
|
||||
self.add_inventory_file(inventory)
|
||||
self.seed_ids = {}
|
||||
self.inventory_files = {}
|
||||
|
||||
|
||||
def add_inventory(self, path_to_inventory):
|
||||
# add paths to list of inventories
|
||||
assert (os.path.isdir(path_to_inventory)), '{} is no directory'.format(path_to_inventory)
|
||||
if not path_to_inventory in self.inventories:
|
||||
self.inventories.append(path_to_inventory)
|
||||
|
||||
|
||||
def add_inventory_file(self, path_to_inventory_file):
|
||||
assert (os.path.isfile(path_to_inventory_file)), '{} is no directory'.format(path_to_inventory_file)
|
||||
self.add_inventory(os.path.split(path_to_inventory_file)[0])
|
||||
if not path_to_inventory_file in self.inventory_files.keys():
|
||||
self.read_single_file(path_to_inventory_file)
|
||||
|
||||
|
||||
def remove_inventory(self, path_to_inventory):
|
||||
if not path_to_inventory in self.inventories:
|
||||
print('Path {} not in inventories list.'.format(path_to_inventory))
|
||||
return
|
||||
self.inventories.remove(path_to_inventory)
|
||||
|
||||
|
||||
def get_metadata(self, seed_id):
|
||||
# get metadata for a specific seed_id, if not already read, try to read from inventories
|
||||
if not seed_id in self.seed_ids.keys():
|
||||
self._read_inventory_data(seed_id)
|
||||
# if seed id is not found read all inventories and try to find it there
|
||||
if not seed_id in self.seed_ids.keys():
|
||||
print('No data found for seed id {}. Trying to find it in all known inventories...'.format(seed_id))
|
||||
self.read_all()
|
||||
for inv_fname, metadata in self.inventory_files.items():
|
||||
# use get_coordinates to check for seed_id
|
||||
if metadata['data'].get_coordinates(seed_id):
|
||||
self.seed_ids[seed_id] = inv_fname
|
||||
return metadata
|
||||
print('Could not find metadata for station {}'.format(seed_id))
|
||||
return None
|
||||
fname = self.seed_ids[seed_id]
|
||||
return self.inventory_files[fname]
|
||||
|
||||
|
||||
def read_all(self):
|
||||
for inventory in self.inventories:
|
||||
for inv_fname in os.listdir(inventory):
|
||||
inv_fname = os.path.join(inventory, inv_fname)
|
||||
if not self.read_single_file(inv_fname):
|
||||
continue
|
||||
|
||||
|
||||
def read_single_file(self, inv_fname):
|
||||
if not inv_fname in self.inventory_files.keys():
|
||||
pass
|
||||
else:
|
||||
if not self.inventory_files[inv_fname]:
|
||||
pass
|
||||
else:
|
||||
return
|
||||
try:
|
||||
invtype, robj = self._read_metadata_file(inv_fname)
|
||||
if robj == None:
|
||||
return
|
||||
except Exception as e:
|
||||
print('Could not read file {}'.format(inv_fname))
|
||||
return
|
||||
self.inventory_files[inv_fname] = {'invtype': invtype,
|
||||
'data': robj}
|
||||
return True
|
||||
|
||||
|
||||
def get_coordinates(self, seed_id):
|
||||
metadata = self.get_metadata(seed_id)
|
||||
return metadata['data'].get_coordinates(seed_id)
|
||||
|
||||
|
||||
def get_paz(self, seed_id, time=None):
|
||||
metadata = self.get_metadata(seed_id)
|
||||
if metadata['invtype'] in ['dless', 'dseed']:
|
||||
return metadata['data'].get_paz(seed_id)
|
||||
elif metadata['invtype'] in ['resp', 'xml']:
|
||||
if not time:
|
||||
print('Time needed to extract metadata from station inventory.')
|
||||
return None
|
||||
resp = metadata['data'].get_response(seed_id, time)
|
||||
return resp.get_paz(seed_id)
|
||||
|
||||
|
||||
def _read_inventory_data(self, seed_id=None):
|
||||
for inventory in self.inventories:
|
||||
if self._read_metadata_iterator(path_to_inventory=inventory, station_seed_id=seed_id):
|
||||
return
|
||||
|
||||
|
||||
def _read_metadata_iterator(self, path_to_inventory, station_seed_id):
|
||||
'''
|
||||
search for metadata for a specific station iteratively
|
||||
'''
|
||||
station, network, location, channel = station_seed_id.split('.')
|
||||
fnames = glob.glob(os.path.join(path_to_inventory, '*' + station_seed_id + '*'))
|
||||
if not fnames:
|
||||
# search for station name in filename
|
||||
fnames = glob.glob(os.path.join(path_to_inventory, '*' + station + '*'))
|
||||
if not fnames:
|
||||
# search for network name in filename
|
||||
fnames = glob.glob(os.path.join(path_to_inventory, '*' + network + '*'))
|
||||
if not fnames:
|
||||
print('Could not find filenames matching station name, network name or seed id')
|
||||
return
|
||||
for fname in fnames:
|
||||
if fname in self.inventory_files.keys():
|
||||
if self.inventory_files[fname]:
|
||||
# file already read
|
||||
continue
|
||||
invtype, robj = self._read_metadata_file(os.path.join(path_to_inventory, fname))
|
||||
try:
|
||||
robj.get_coordinates(station_seed_id)
|
||||
self.inventory_files[fname] = {'invtype': invtype,
|
||||
'data': robj}
|
||||
if station_seed_id in self.seed_ids.keys():
|
||||
print('WARNING: Overwriting metadata for station {}'.format(station_seed_id))
|
||||
self.seed_ids[station_seed_id] = fname
|
||||
return True
|
||||
except Exception as e:
|
||||
continue
|
||||
print('Could not find metadata for station_seed_id {} in path {}'.format(station_seed_id, path_to_inventory))
|
||||
|
||||
|
||||
def _read_metadata_file(self, path_to_inventory_filename):
|
||||
'''
|
||||
function reading metadata files (either dataless seed, xml or resp)
|
||||
:param path_to_inventory_filename:
|
||||
:return: file type/ending, inventory object (Parser or Inventory)
|
||||
'''
|
||||
# functions used to read metadata for different file endings (or file types)
|
||||
read_functions = {'dless': self._read_dless,
|
||||
'dseed': self._read_dless,
|
||||
'xml': self._read_inventory_file,
|
||||
'resp': self._read_inventory_file}
|
||||
file_ending = path_to_inventory_filename.split('.')[-1]
|
||||
if file_ending in read_functions.keys():
|
||||
robj, exc = read_functions[file_ending](path_to_inventory_filename)
|
||||
if exc is not None:
|
||||
raise exc
|
||||
return file_ending, robj
|
||||
# in case file endings did not match the above keys, try and error
|
||||
for file_type in ['dless', 'xml']:
|
||||
robj, exc = read_functions[file_type](path_to_inventory_filename)
|
||||
if exc is None:
|
||||
return file_type, robj
|
||||
return None, None
|
||||
|
||||
|
||||
def _read_dless(self, path_to_inventory):
|
||||
exc = None
|
||||
try:
|
||||
parser = Parser(path_to_inventory)
|
||||
except Exception as exc:
|
||||
parser = None
|
||||
return parser, exc
|
||||
|
||||
|
||||
def _read_inventory_file(self, path_to_inventory):
|
||||
exc = None
|
||||
try:
|
||||
inv = read_inventory(path_to_inventory)
|
||||
except Exception as exc:
|
||||
inv = None
|
||||
return inv, exc
|
||||
|
||||
|
||||
|
||||
def time_from_header(header):
|
||||
"""
|
||||
Function takes in the second line from a .gse file and takes out the date and time from that line.
|
||||
@ -196,6 +376,33 @@ def read_metadata(path_to_inventory):
|
||||
return invtype, robj
|
||||
|
||||
|
||||
# idea to optimize read_metadata
|
||||
# def read_metadata_new(path_to_inventory):
|
||||
# metadata_objects = []
|
||||
# # read multiple files from directory
|
||||
# if os.path.isdir(path_to_inventory):
|
||||
# fnames = os.listdir(path_to_inventory)
|
||||
# # read single file
|
||||
# elif os.path.isfile(path_to_inventory):
|
||||
# fnames = [path_to_inventory]
|
||||
# else:
|
||||
# print("Neither dataless-SEED file, inventory-xml file nor "
|
||||
# "RESP-file found!")
|
||||
# print("!!WRONG CALCULATION OF SOURCE PARAMETERS!!")
|
||||
# fnames = []
|
||||
#
|
||||
# for fname in fnames:
|
||||
# path_to_inventory_filename = os.path.join(path_to_inventory, fname)
|
||||
# try:
|
||||
# ftype, robj = read_metadata_file(path_to_inventory_filename)
|
||||
# metadata_objects.append((ftype, robj))
|
||||
# except Exception as e:
|
||||
# print('Could not read metadata file {} '
|
||||
# 'because of the following Exception: {}'.format(path_to_inventory_filename, e))
|
||||
# return metadata_objects
|
||||
|
||||
|
||||
|
||||
def restitute_trace(input_tuple):
|
||||
tr, invtype, inobj, unit, force = input_tuple
|
||||
|
||||
|
@ -7,6 +7,7 @@ from obspy import UTCDateTime
|
||||
from obspy.core.event import Event as ObsPyEvent
|
||||
from obspy.core.event import Origin, ResourceIdentifier
|
||||
from pylot.core.io.phases import picks_from_picksdict
|
||||
from pylot.core.util.obspyDMT_interface import qml_from_obspyDMT
|
||||
|
||||
|
||||
class Event(ObsPyEvent):
|
||||
@ -33,6 +34,7 @@ class Event(ObsPyEvent):
|
||||
self._testEvent = False
|
||||
self._refEvent = False
|
||||
self.get_notes()
|
||||
self.get_obspy_event_info()
|
||||
|
||||
def get_notes_path(self):
|
||||
"""
|
||||
@ -43,6 +45,18 @@ class Event(ObsPyEvent):
|
||||
notesfile = os.path.join(self.path, 'notes.txt')
|
||||
return notesfile
|
||||
|
||||
def get_obspy_event_info(self):
|
||||
infile_pickle = os.path.join(self.path, 'info/event.pkl')
|
||||
if not os.path.isfile(infile_pickle):
|
||||
return
|
||||
try:
|
||||
event_dmt = qml_from_obspyDMT(infile_pickle)
|
||||
except Exception as e:
|
||||
print('Could not get obspy event info: {}'.format(e))
|
||||
return
|
||||
self.magnitudes = event_dmt.magnitudes
|
||||
self.origins = event_dmt.origins
|
||||
|
||||
def get_notes(self):
|
||||
"""
|
||||
set self.note attribute to content of notes file
|
||||
|
@ -1,377 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import obspy
|
||||
from PySide import QtGui
|
||||
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
|
||||
from mpl_toolkits.basemap import Basemap
|
||||
from pylot.core.util.widgets import PickDlg
|
||||
from scipy.interpolate import griddata
|
||||
|
||||
plt.interactive(False)
|
||||
|
||||
|
||||
class map_projection(QtGui.QWidget):
|
||||
def __init__(self, parent, figure=None):
|
||||
'''
|
||||
|
||||
:param: picked, can be False, auto, manual
|
||||
:value: str
|
||||
'''
|
||||
QtGui.QWidget.__init__(self)
|
||||
self._parent = parent
|
||||
self.metadata = parent.metadata
|
||||
self.parser = parent.metadata[1]
|
||||
self.picks = None
|
||||
self.picks_dict = None
|
||||
self.eventLoc = None
|
||||
self.figure = figure
|
||||
self.init_graphics()
|
||||
self.init_stations()
|
||||
self.init_basemap(resolution='l')
|
||||
self.init_map()
|
||||
self._style = parent._style
|
||||
# self.show()
|
||||
|
||||
def init_map(self):
|
||||
self.init_lat_lon_dimensions()
|
||||
self.init_lat_lon_grid()
|
||||
self.init_x_y_dimensions()
|
||||
self.connectSignals()
|
||||
self.draw_everything()
|
||||
|
||||
def onpick(self, event):
|
||||
ind = event.ind
|
||||
button = event.mouseevent.button
|
||||
if ind == [] or not button == 1:
|
||||
return
|
||||
data = self._parent.get_data().getWFData()
|
||||
for index in ind:
|
||||
station = str(self.station_names[index].split('.')[-1])
|
||||
try:
|
||||
pickDlg = PickDlg(self, parameter=self._parent._inputs,
|
||||
data=data.select(station=station),
|
||||
station=station,
|
||||
picks=self._parent.get_current_event().getPick(station),
|
||||
autopicks=self._parent.get_current_event().getAutopick(station))
|
||||
except Exception as e:
|
||||
message = 'Could not generate Plot for station {st}.\n {er}'.format(st=station, er=e)
|
||||
self._warn(message)
|
||||
print(message, e)
|
||||
return
|
||||
pyl_mw = self._parent
|
||||
try:
|
||||
if pickDlg.exec_():
|
||||
pyl_mw.setDirty(True)
|
||||
pyl_mw.update_status('picks accepted ({0})'.format(station))
|
||||
replot = pyl_mw.get_current_event().setPick(station, pickDlg.getPicks())
|
||||
self._refresh_drawings()
|
||||
if replot:
|
||||
pyl_mw.plotWaveformData()
|
||||
pyl_mw.drawPicks()
|
||||
pyl_mw.draw()
|
||||
else:
|
||||
pyl_mw.drawPicks(station)
|
||||
pyl_mw.draw()
|
||||
else:
|
||||
pyl_mw.update_status('picks discarded ({0})'.format(station))
|
||||
except Exception as e:
|
||||
message = 'Could not save picks for station {st}.\n{er}'.format(st=station, er=e)
|
||||
self._warn(message)
|
||||
print(message, e)
|
||||
|
||||
def connectSignals(self):
|
||||
self.comboBox_phase.currentIndexChanged.connect(self._refresh_drawings)
|
||||
self.zoom_id = self.basemap.ax.figure.canvas.mpl_connect('scroll_event', self.zoom)
|
||||
|
||||
def init_graphics(self):
|
||||
if not self.figure:
|
||||
if not hasattr(self._parent, 'am_figure'):
|
||||
self.figure = plt.figure()
|
||||
self.toolbar = NavigationToolbar(self.figure.canvas, self)
|
||||
else:
|
||||
self.figure = self._parent.am_figure
|
||||
self.toolbar = self._parent.am_toolbar
|
||||
|
||||
self.main_ax = self.figure.add_subplot(111)
|
||||
self.canvas = self.figure.canvas
|
||||
|
||||
self.main_box = QtGui.QVBoxLayout()
|
||||
self.setLayout(self.main_box)
|
||||
|
||||
self.top_row = QtGui.QHBoxLayout()
|
||||
self.main_box.addLayout(self.top_row)
|
||||
|
||||
self.comboBox_phase = QtGui.QComboBox()
|
||||
self.comboBox_phase.insertItem(0, 'P')
|
||||
self.comboBox_phase.insertItem(1, 'S')
|
||||
|
||||
self.comboBox_am = QtGui.QComboBox()
|
||||
self.comboBox_am.insertItem(0, 'auto')
|
||||
self.comboBox_am.insertItem(1, 'manual')
|
||||
|
||||
self.top_row.addWidget(QtGui.QLabel('Select a phase: '))
|
||||
self.top_row.addWidget(self.comboBox_phase)
|
||||
self.top_row.setStretch(1, 1) # set stretch of item 1 to 1
|
||||
|
||||
self.main_box.addWidget(self.canvas)
|
||||
self.main_box.addWidget(self.toolbar)
|
||||
|
||||
def init_stations(self):
|
||||
def get_station_names_lat_lon(parser):
|
||||
station_names = []
|
||||
lat = []
|
||||
lon = []
|
||||
for station in parser.stations:
|
||||
station_name = station[0].station_call_letters
|
||||
network = station[0].network_code
|
||||
if not station_name in station_names:
|
||||
station_names.append(network + '.' + station_name)
|
||||
lat.append(station[0].latitude)
|
||||
lon.append(station[0].longitude)
|
||||
return station_names, lat, lon
|
||||
|
||||
station_names, lat, lon = get_station_names_lat_lon(self.parser)
|
||||
self.station_names = station_names
|
||||
self.lat = lat
|
||||
self.lon = lon
|
||||
|
||||
def init_picks(self):
|
||||
phase = self.comboBox_phase.currentText()
|
||||
|
||||
def get_picks(station_names):
|
||||
picks = []
|
||||
for station in station_names:
|
||||
try:
|
||||
station = station.split('.')[-1]
|
||||
picks.append(self.picks_dict[station][phase]['mpp'])
|
||||
except:
|
||||
picks.append(np.nan)
|
||||
return picks
|
||||
|
||||
def get_picks_rel(picks):
|
||||
picks_rel = []
|
||||
picks_utc = []
|
||||
for pick in picks:
|
||||
if type(pick) is obspy.core.utcdatetime.UTCDateTime:
|
||||
picks_utc.append(pick)
|
||||
minp = min(picks_utc)
|
||||
for pick in picks:
|
||||
if type(pick) is obspy.core.utcdatetime.UTCDateTime:
|
||||
pick -= minp
|
||||
picks_rel.append(pick)
|
||||
return picks_rel
|
||||
|
||||
self.picks = get_picks(self.station_names)
|
||||
self.picks_rel = get_picks_rel(self.picks)
|
||||
|
||||
def init_picks_active(self):
|
||||
def remove_nan_picks(picks):
|
||||
picks_no_nan = []
|
||||
for pick in picks:
|
||||
if not np.isnan(pick):
|
||||
picks_no_nan.append(pick)
|
||||
return picks_no_nan
|
||||
|
||||
self.picks_no_nan = remove_nan_picks(self.picks_rel)
|
||||
|
||||
def init_stations_active(self):
|
||||
def remove_nan_lat_lon(picks, lat, lon):
|
||||
lat_no_nan = []
|
||||
lon_no_nan = []
|
||||
for index, pick in enumerate(picks):
|
||||
if not np.isnan(pick):
|
||||
lat_no_nan.append(lat[index])
|
||||
lon_no_nan.append(lon[index])
|
||||
return lat_no_nan, lon_no_nan
|
||||
|
||||
self.lat_no_nan, self.lon_no_nan = remove_nan_lat_lon(self.picks_rel, self.lat, self.lon)
|
||||
|
||||
def init_lat_lon_dimensions(self):
|
||||
def get_lon_lat_dim(lon, lat):
|
||||
londim = max(lon) - min(lon)
|
||||
latdim = max(lat) - min(lat)
|
||||
return londim, latdim
|
||||
|
||||
self.londim, self.latdim = get_lon_lat_dim(self.lon, self.lat)
|
||||
|
||||
def init_x_y_dimensions(self):
|
||||
def get_x_y_dim(x, y):
|
||||
xdim = max(x) - min(x)
|
||||
ydim = max(y) - min(y)
|
||||
return xdim, ydim
|
||||
|
||||
self.x, self.y = self.basemap(self.lon, self.lat)
|
||||
self.xdim, self.ydim = get_x_y_dim(self.x, self.y)
|
||||
|
||||
def init_basemap(self, resolution='l'):
|
||||
# basemap = Basemap(projection=projection, resolution = resolution, ax=self.main_ax)
|
||||
basemap = Basemap(projection='lcc', resolution=resolution, ax=self.main_ax,
|
||||
width=5e6, height=2e6,
|
||||
lat_0=(min(self.lat) + max(self.lat)) / 2.,
|
||||
lon_0=(min(self.lon) + max(self.lon)) / 2.)
|
||||
|
||||
# basemap.fillcontinents(color=None, lake_color='aqua',zorder=1)
|
||||
basemap.drawmapboundary(zorder=2) # fill_color='darkblue')
|
||||
basemap.shadedrelief(zorder=3)
|
||||
basemap.drawcountries(zorder=4)
|
||||
basemap.drawstates(zorder=5)
|
||||
basemap.drawcoastlines(zorder=6)
|
||||
self.basemap = basemap
|
||||
self.figure.tight_layout()
|
||||
|
||||
def init_lat_lon_grid(self):
|
||||
def get_lat_lon_axis(lat, lon):
|
||||
steplat = (max(lat) - min(lat)) / 250
|
||||
steplon = (max(lon) - min(lon)) / 250
|
||||
|
||||
lataxis = np.arange(min(lat), max(lat), steplat)
|
||||
lonaxis = np.arange(min(lon), max(lon), steplon)
|
||||
return lataxis, lonaxis
|
||||
|
||||
def get_lat_lon_grid(lataxis, lonaxis):
|
||||
longrid, latgrid = np.meshgrid(lonaxis, lataxis)
|
||||
return latgrid, longrid
|
||||
|
||||
self.lataxis, self.lonaxis = get_lat_lon_axis(self.lat, self.lon)
|
||||
self.latgrid, self.longrid = get_lat_lon_grid(self.lataxis, self.lonaxis)
|
||||
|
||||
def init_picksgrid(self):
|
||||
self.picksgrid_no_nan = griddata((self.lat_no_nan, self.lon_no_nan),
|
||||
self.picks_no_nan, (self.latgrid, self.longrid),
|
||||
method='linear') ##################
|
||||
|
||||
def draw_contour_filled(self, nlevel='50'):
|
||||
levels = np.linspace(min(self.picks_no_nan), max(self.picks_no_nan), nlevel)
|
||||
self.contourf = self.basemap.contourf(self.longrid, self.latgrid, self.picksgrid_no_nan,
|
||||
levels, latlon=True, zorder=9, alpha=0.5)
|
||||
|
||||
def scatter_all_stations(self):
|
||||
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
|
||||
lat = self.lat_no_nan
|
||||
|
||||
# workaround because of an issue with latlon transformation of arrays with len <3
|
||||
if len(lon) <= 2 and len(lat) <= 2:
|
||||
self.sc_picked = self.basemap.scatter(lon[0], lat[0], s=50, facecolor='white',
|
||||
c=self.picks_no_nan[0], latlon=True, zorder=11, label='Picked')
|
||||
if len(lon) == 2 and len(lat) == 2:
|
||||
self.sc_picked = self.basemap.scatter(lon[1], lat[1], s=50, facecolor='white',
|
||||
c=self.picks_no_nan[1], latlon=True, zorder=11)
|
||||
else:
|
||||
self.sc_picked = self.basemap.scatter(lon, lat, s=50, facecolor='white',
|
||||
c=self.picks_no_nan, latlon=True, zorder=11, label='Picked')
|
||||
|
||||
def annotate_ax(self):
|
||||
self.annotations = []
|
||||
for index, name in enumerate(self.station_names):
|
||||
self.annotations.append(self.main_ax.annotate(' %s' % name, xy=(self.x[index], self.y[index]),
|
||||
fontsize='x-small', color='white', zorder=12))
|
||||
self.legend = self.main_ax.legend(loc=1)
|
||||
|
||||
def add_cbar(self, label):
|
||||
cbar = self.main_ax.figure.colorbar(self.sc_picked, fraction=0.025)
|
||||
cbar.set_label(label)
|
||||
return cbar
|
||||
|
||||
def refresh_drawings(self, picks=None):
|
||||
self.picks_dict = picks
|
||||
self._refresh_drawings()
|
||||
|
||||
def _refresh_drawings(self):
|
||||
self.remove_drawings()
|
||||
self.draw_everything()
|
||||
|
||||
def draw_everything(self):
|
||||
if self.picks_dict:
|
||||
self.init_picks()
|
||||
self.init_picks_active()
|
||||
self.init_stations_active()
|
||||
if len(self.picks_no_nan) >= 3:
|
||||
self.init_picksgrid()
|
||||
self.draw_contour_filled()
|
||||
self.scatter_all_stations()
|
||||
if self.picks_dict:
|
||||
self.scatter_picked_stations()
|
||||
self.cbar = self.add_cbar(label='Time relative to first onset [s]')
|
||||
self.comboBox_phase.setEnabled(True)
|
||||
else:
|
||||
self.comboBox_phase.setEnabled(False)
|
||||
self.annotate_ax()
|
||||
self.canvas.draw()
|
||||
|
||||
def remove_drawings(self):
|
||||
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)
|
||||
if hasattr(self, 'contourf'):
|
||||
self.remove_contourf()
|
||||
del (self.contourf)
|
||||
if hasattr(self, 'cid'):
|
||||
self.canvas.mpl_disconnect(self.cid)
|
||||
del (self.cid)
|
||||
try:
|
||||
self.sc.remove()
|
||||
except Exception as e:
|
||||
print('Warning: could not remove station scatter plot.\nReason: {}'.format(e))
|
||||
try:
|
||||
self.legend.remove()
|
||||
except Exception as e:
|
||||
print('Warning: could not remove legend. Reason: {}'.format(e))
|
||||
self.canvas.draw()
|
||||
|
||||
def remove_contourf(self):
|
||||
for item in self.contourf.collections:
|
||||
item.remove()
|
||||
|
||||
def remove_annotations(self):
|
||||
for annotation in self.annotations:
|
||||
annotation.remove()
|
||||
|
||||
def zoom(self, event):
|
||||
map = self.basemap
|
||||
xlim = map.ax.get_xlim()
|
||||
ylim = map.ax.get_ylim()
|
||||
x, y = event.xdata, event.ydata
|
||||
zoom = {'up': 1. / 2.,
|
||||
'down': 2.}
|
||||
|
||||
if not event.xdata or not event.ydata:
|
||||
return
|
||||
|
||||
if event.button in zoom:
|
||||
factor = zoom[event.button]
|
||||
xdiff = (xlim[1] - xlim[0]) * factor
|
||||
xl = x - 0.5 * xdiff
|
||||
xr = x + 0.5 * xdiff
|
||||
ydiff = (ylim[1] - ylim[0]) * factor
|
||||
yb = y - 0.5 * ydiff
|
||||
yt = y + 0.5 * ydiff
|
||||
|
||||
if xl < map.xmin or yb < map.ymin or xr > map.xmax or yt > map.ymax:
|
||||
xl, xr = map.xmin, map.xmax
|
||||
yb, yt = map.ymin, map.ymax
|
||||
map.ax.set_xlim(xl, xr)
|
||||
map.ax.set_ylim(yb, yt)
|
||||
map.ax.figure.canvas.draw()
|
||||
|
||||
def _warn(self, message):
|
||||
self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning,
|
||||
'Warning', message)
|
||||
self.qmb.show()
|
@ -25,4 +25,20 @@ def check_obspydmt_eventfolder(folder):
|
||||
except Exception as e:
|
||||
return False, e
|
||||
|
||||
check_obspydmt_eventfolder('20110311_054623.a')
|
||||
def qml_from_obspyDMT(path):
|
||||
import pickle
|
||||
from obspy.core.event import Event, Magnitude, Origin
|
||||
|
||||
if not os.path.exists(path):
|
||||
return IOError('Could not find Event at {}'.format(path))
|
||||
infile = open(path, 'rb')
|
||||
event_dmt = pickle.load(infile)
|
||||
ev = Event(resource_id=event_dmt['event_id'])
|
||||
origin = Origin(resource_id=event_dmt['origin_id'], time=event_dmt['datetime'], longitude=event_dmt['longitude'],
|
||||
latitude=event_dmt['latitude'], depth=event_dmt['depth'])
|
||||
mag = Magnitude(mag=event_dmt['magnitude'], magnitude_type=event_dmt['magnitude_type'],
|
||||
origin_id=event_dmt['origin_id'])
|
||||
ev.magnitudes.append(mag)
|
||||
ev.origins.append(origin)
|
||||
return ev
|
||||
|
||||
|
@ -16,6 +16,9 @@ import time
|
||||
|
||||
import numpy as np
|
||||
|
||||
import matplotlib
|
||||
matplotlib.use('QT4Agg')
|
||||
|
||||
from matplotlib.figure import Figure
|
||||
|
||||
try:
|
||||
@ -26,6 +29,7 @@ from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT
|
||||
from matplotlib.widgets import MultiCursor
|
||||
from matplotlib.tight_layout import get_renderer, get_subplotspec_list, get_tight_layout_figure
|
||||
from scipy.signal import argrelmin, argrelmax
|
||||
from obspy import read
|
||||
|
||||
from PySide import QtCore, QtGui
|
||||
from PySide.QtGui import QAction, QApplication, QCheckBox, QComboBox, \
|
||||
@ -447,23 +451,25 @@ class WaveformWidgetPG(QtGui.QWidget):
|
||||
self.orig_parent = parent
|
||||
# attribute plotdict is a dictionary connecting position and a name
|
||||
self.plotdict = dict()
|
||||
# init labels
|
||||
self.xlabel = None
|
||||
self.ylabel = None
|
||||
self.title = None
|
||||
# create plot
|
||||
self.main_layout = QtGui.QVBoxLayout()
|
||||
self.label_layout = QtGui.QHBoxLayout()
|
||||
self.status_label = QtGui.QLabel()
|
||||
self.perm_label = QtGui.QLabel()
|
||||
self.setLayout(self.main_layout)
|
||||
self.add_labels()
|
||||
self.connect_signals()
|
||||
self.plotWidget = self.pg.PlotWidget(self.parent(), title=title)
|
||||
self.main_layout.addWidget(self.plotWidget)
|
||||
self.main_layout.addLayout(self.label_layout)
|
||||
self.label_layout.addWidget(self.status_label)
|
||||
self.label_layout.addWidget(self.perm_label)
|
||||
self.init_labels()
|
||||
self.activateObspyDMToptions(False)
|
||||
self.plotWidget.showGrid(x=False, y=True, alpha=0.3)
|
||||
self.plotWidget.hideAxis('bottom')
|
||||
self.plotWidget.hideAxis('left')
|
||||
self.wfstart, self.wfend = 0, 0
|
||||
self.pen_multicursor = self.pg.mkPen(self.parent()._style['multicursor']['rgba'])
|
||||
self.pen_linecolor = self.pg.mkPen(self.parent()._style['linecolor']['rgba'])
|
||||
self.pen_linecolor_highlight = self.pg.mkPen((255, 100, 100, 255))
|
||||
self.pen_linecolor_syn = self.pg.mkPen((100, 0, 255, 255))
|
||||
self.reinitMoveProxy()
|
||||
self._proxy = self.pg.SignalProxy(self.plotWidget.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
|
||||
@ -489,12 +495,59 @@ class WaveformWidgetPG(QtGui.QWidget):
|
||||
self.vLine.setPos(mousePoint.x())
|
||||
self.hLine.setPos(mousePoint.y())
|
||||
|
||||
def connect_signals(self):
|
||||
self.qcombo_processed.activated.connect(self.parent().newWF)
|
||||
self.syn_checkbox.clicked.connect(self.parent().newWF)
|
||||
|
||||
def init_labels(self):
|
||||
self.label_layout.addWidget(self.status_label)
|
||||
for label in self.perm_labels:
|
||||
self.label_layout.addWidget(label)
|
||||
self.label_layout.addWidget(self.syn_checkbox)
|
||||
self.label_layout.addWidget(self.qcombo_processed)
|
||||
self.syn_checkbox.setLayoutDirection(Qt.RightToLeft)
|
||||
self.label_layout.setStretch(0, 4)
|
||||
self.label_layout.setStretch(1, 0)
|
||||
self.label_layout.setStretch(2, 0)
|
||||
self.label_layout.setStretch(3, 0)
|
||||
self.label_layout.setStretch(4, 3)
|
||||
self.label_layout.setStretch(5, 1)
|
||||
|
||||
def add_labels(self):
|
||||
self.status_label = QtGui.QLabel()
|
||||
self.perm_labels = []
|
||||
for index in range(3):
|
||||
label = QtGui.QLabel()
|
||||
self.perm_labels.append(label)
|
||||
self.qcombo_processed = QtGui.QComboBox()
|
||||
self.syn_checkbox = QtGui.QCheckBox('synthetics')
|
||||
self.addQCboxItem('processed', 'green')
|
||||
self.addQCboxItem('raw', 'black')
|
||||
#self.perm_qcbox_right.setAlignment(2)
|
||||
self.setLayout(self.main_layout)
|
||||
|
||||
def getPlotDict(self):
|
||||
return self.plotdict
|
||||
|
||||
def setPermText(self, text=None, color='black'):
|
||||
self.perm_label.setText(text)
|
||||
self.perm_label.setStyleSheet('color: {}'.format(color))
|
||||
def activateObspyDMToptions(self, activate):
|
||||
self.syn_checkbox.setVisible(activate)
|
||||
self.qcombo_processed.setVisible(activate)
|
||||
|
||||
def setPermText(self, number, text=None, color='black'):
|
||||
if not 0 <= number < len(self.perm_labels):
|
||||
raise ValueError('No label for number {}'.format(number))
|
||||
self.perm_labels[number].setText(text)
|
||||
self.perm_labels[number].setStyleSheet('color: {}'.format(color))
|
||||
|
||||
def addQCboxItem(self, text=None, color='black'):
|
||||
item = QtGui.QStandardItem(text)
|
||||
model = self.qcombo_processed.model()
|
||||
model.appendRow(item)
|
||||
item.setForeground(QtGui.QColor('{}'.format(color)))
|
||||
|
||||
def setQCboxItem(self, text):
|
||||
index = self.qcombo_processed.findText(text)
|
||||
self.qcombo_processed.setCurrentIndex(index)
|
||||
|
||||
def setPlotDict(self, key, value):
|
||||
self.plotdict[key] = value
|
||||
@ -529,6 +582,14 @@ class WaveformWidgetPG(QtGui.QWidget):
|
||||
else:
|
||||
st_select = wfdata
|
||||
|
||||
gaps = st_select.get_gaps()
|
||||
if gaps:
|
||||
merged = ['{}.{}.{}.{}'.format(*gap[:4]) for gap in gaps]
|
||||
st_select.merge()
|
||||
print('Merged the following stations because of gaps:')
|
||||
for merged_station in merged:
|
||||
print(merged_station)
|
||||
|
||||
# list containing tuples of network, station, channel (for sorting)
|
||||
nsc = []
|
||||
for trace in st_select:
|
||||
@ -552,6 +613,8 @@ class WaveformWidgetPG(QtGui.QWidget):
|
||||
st_syn = wfsyn.select(network=network, station=station, channel=channel)
|
||||
if st_syn:
|
||||
trace_syn = st_syn[0].copy()
|
||||
else:
|
||||
trace_syn = Trace()
|
||||
if mapping:
|
||||
comp = channel[-1]
|
||||
n = compclass.getPlotPosition(str(comp))
|
||||
@ -568,9 +631,11 @@ class WaveformWidgetPG(QtGui.QWidget):
|
||||
time_ax_syn = prepTimeAxis(stime_syn, trace_syn)
|
||||
|
||||
if method == 'fast':
|
||||
trace.data, time_ax = self.minMax(trace, time_ax)
|
||||
trace.data, time_ax = self.minMax(trace, time_ax)
|
||||
if trace_syn:
|
||||
trace_syn.data, time_ax_syn = self.minMax(trace_syn, time_ax_syn)
|
||||
|
||||
if time_ax not in [None, []]:
|
||||
if len(time_ax) > 0:
|
||||
if not scaleddata:
|
||||
trace.detrend('constant')
|
||||
trace.normalize(np.max(np.abs(trace.data)) * 2)
|
||||
@ -581,23 +646,23 @@ class WaveformWidgetPG(QtGui.QWidget):
|
||||
times = np.array([time for index, time in enumerate(time_ax) if not index % nth_sample])
|
||||
times_syn = np.array([time for index, time in enumerate(time_ax_syn) if not index % nth_sample] if st_syn else [])
|
||||
trace.data = np.array([datum + n for index, datum in enumerate(trace.data) if not index % nth_sample])
|
||||
trace.data_syn = np.array([datum + n for index, datum in enumerate(trace.data_syn)
|
||||
trace_syn.data = np.array([datum + n 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.data_syn))
|
||||
times_syn, trace_syn.data))
|
||||
self.setPlotDict(n, (station, channel, network))
|
||||
self.xlabel = 'seconds since {0}'.format(self.wfstart)
|
||||
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):
|
||||
'''
|
||||
create min/max array for fast plotting (approach based on obspy __plot_min_max function)
|
||||
:returns data, time_ax
|
||||
'''
|
||||
npixel = self.width()
|
||||
npixel = self.orig_parent.width()
|
||||
ndata = len(trace.data)
|
||||
pts_per_pixel = ndata/npixel
|
||||
if pts_per_pixel < 2:
|
||||
@ -1013,6 +1078,14 @@ class PylotCanvas(FigureCanvas):
|
||||
if mapping:
|
||||
plot_positions = self.calcPlotPositions(st_select, compclass)
|
||||
|
||||
gaps = st_select.get_gaps()
|
||||
if gaps:
|
||||
merged = ['{}.{}.{}.{}'.format(*gap[:4]) for gap in gaps]
|
||||
st_select.merge()
|
||||
print('Merged the following stations because of gaps:')
|
||||
for merged_station in merged:
|
||||
print(merged_station)
|
||||
|
||||
# list containing tuples of network, station, channel and plot position (for sorting)
|
||||
nsc = []
|
||||
for plot_pos, trace in enumerate(st_select):
|
||||
@ -1245,9 +1318,10 @@ class PickDlg(QDialog):
|
||||
|
||||
def __init__(self, parent=None, data=None, station=None, network=None, picks=None,
|
||||
autopicks=None, rotate=False, parameter=None, embedded=False, metadata=None,
|
||||
event=None, filteroptions=None, model='iasp91'):
|
||||
event=None, filteroptions=None, model='iasp91', wftype=None):
|
||||
super(PickDlg, self).__init__(parent, 1)
|
||||
self.orig_parent = parent
|
||||
self.setAttribute(Qt.WA_DeleteOnClose)
|
||||
|
||||
# initialize attributes
|
||||
self.parameter = parameter
|
||||
@ -1256,6 +1330,7 @@ class PickDlg(QDialog):
|
||||
self.network = network
|
||||
self.rotate = rotate
|
||||
self.metadata = metadata
|
||||
self.wftype = wftype
|
||||
self.pylot_event = event
|
||||
self.components = 'ZNE'
|
||||
self.currentPhase = None
|
||||
@ -1305,7 +1380,7 @@ class PickDlg(QDialog):
|
||||
self.cur_ylim = None
|
||||
|
||||
# set attribute holding data
|
||||
if data is None:
|
||||
if data is None or not data:
|
||||
try:
|
||||
data = parent.get_data().getWFData().copy()
|
||||
self.data = data.select(station=station)
|
||||
@ -1328,7 +1403,7 @@ class PickDlg(QDialog):
|
||||
|
||||
# fill compare and scale channels
|
||||
self.compareChannel.addItem('-', None)
|
||||
self.scaleChannel.addItem('normalized', None)
|
||||
self.scaleChannel.addItem('individual', None)
|
||||
|
||||
for trace in self.getWFData():
|
||||
channel = trace.stats.channel
|
||||
@ -1345,8 +1420,12 @@ class PickDlg(QDialog):
|
||||
actionS.setChecked(self.getChannelSettingsS(channel))
|
||||
|
||||
# plot data
|
||||
title = self.getStation()
|
||||
if self.wftype is not None:
|
||||
title += ' | ({})'.format(self.wftype)
|
||||
|
||||
self.multicompfig.plotWFData(wfdata=self.getWFData(),
|
||||
title=self.getStation())
|
||||
title=title)
|
||||
|
||||
self.multicompfig.setZoomBorders2content()
|
||||
|
||||
@ -1380,7 +1459,6 @@ class PickDlg(QDialog):
|
||||
self.setWindowTitle('Pickwindow on station: {}'.format(self.getStation()))
|
||||
self.setWindowState(QtCore.Qt.WindowMaximized)
|
||||
|
||||
self.deleteLater()
|
||||
|
||||
def setupUi(self):
|
||||
menuBar = QtGui.QMenuBar(self)
|
||||
@ -1526,7 +1604,7 @@ class PickDlg(QDialog):
|
||||
_dialtoolbar.addWidget(QtGui.QLabel('Compare to channel: '))
|
||||
_dialtoolbar.addWidget(self.compareChannel)
|
||||
_dialtoolbar.addSeparator()
|
||||
_dialtoolbar.addWidget(QtGui.QLabel('Scale by: '))
|
||||
_dialtoolbar.addWidget(QtGui.QLabel('Scaling: '))
|
||||
_dialtoolbar.addWidget(self.scaleChannel)
|
||||
|
||||
# layout the innermost widget
|
||||
@ -1649,7 +1727,7 @@ class PickDlg(QDialog):
|
||||
self.arrivalsText.append(ax.text(time_rel, ylims[0], arrival.name, color='0.5'))
|
||||
|
||||
def drawArrivalsText(self):
|
||||
return self.drawArrivals(True)
|
||||
return self.drawArrivals(textOnly=True)
|
||||
|
||||
def refreshArrivalsText(self, event=None):
|
||||
self.removeArrivalsText()
|
||||
@ -2514,6 +2592,9 @@ class PickDlg(QDialog):
|
||||
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()
|
||||
scale_channel = self.scaleChannel.currentText()
|
||||
@ -2601,6 +2682,7 @@ class PickDlg(QDialog):
|
||||
phase = 'S'
|
||||
filter = True
|
||||
self.plotWFData(phase=phase, filter=filter)
|
||||
self.drawArrivals()
|
||||
|
||||
def resetZoom(self):
|
||||
ax = self.multicompfig.axes[0]
|
||||
@ -2864,7 +2946,7 @@ class AutoPickWidget(MultiEventWidget):
|
||||
def reinitEvents2plot(self):
|
||||
for eventID, eventDict in self.events2plot.items():
|
||||
for widget_key, widget in eventDict.items():
|
||||
widget.setParent(None)
|
||||
del(widget)
|
||||
self.events2plot = {}
|
||||
self.eventbox.clear()
|
||||
self.refresh_plot_tabs()
|
||||
@ -2946,13 +3028,15 @@ class TuneAutopicker(QWidget):
|
||||
:type: PyLoT Mainwindow
|
||||
'''
|
||||
|
||||
def __init__(self, parent):
|
||||
def __init__(self, parent, obspy_dmt=False):
|
||||
QtGui.QWidget.__init__(self, parent, 1)
|
||||
self._style = parent._style
|
||||
self.setWindowTitle('PyLoT - Tune Autopicker')
|
||||
self.parameter = self.parent()._inputs
|
||||
self.fig_dict = self.parent().fig_dict
|
||||
self.data = Data()
|
||||
self.obspy_dmt = obspy_dmt
|
||||
self.wftype = None
|
||||
self.pdlg_widget = None
|
||||
self.pylot_picks = None
|
||||
self.init_main_layouts()
|
||||
@ -3009,8 +3093,45 @@ class TuneAutopicker(QWidget):
|
||||
self.eventBox.activated.connect(self.fill_tabs)
|
||||
self.stationBox.activated.connect(self.fill_tabs)
|
||||
|
||||
def catch_station_ids(self):
|
||||
self.station_ids = {}
|
||||
eventpath = self.get_current_event_fp()
|
||||
self.wftype = 'processed' if self.obspy_dmt else ''
|
||||
wf_path = os.path.join(eventpath, self.wftype)
|
||||
if not os.path.exists(wf_path) and self.obspy_dmt:
|
||||
self.wftype = 'raw'
|
||||
wf_path = os.path.join(eventpath, self.wftype)
|
||||
for filename in os.listdir(wf_path):
|
||||
filename = os.path.join(eventpath, self.wftype, filename)
|
||||
try:
|
||||
st = read(filename, headonly=True)
|
||||
except Exception as e:
|
||||
print('Warning: Could not read file {} as a stream object: {}'.format(filename, e))
|
||||
continue
|
||||
for trace in st:
|
||||
network = trace.stats.network
|
||||
station = trace.stats.station
|
||||
location = trace.stats.location
|
||||
station_id = '{}.{}.{}'.format(network, station, location)
|
||||
if not station_id in self.station_ids:
|
||||
self.station_ids[station_id] = []
|
||||
self.station_ids[station_id].append(filename)
|
||||
|
||||
def fill_stationbox(self):
|
||||
fnames = self.parent().getWFFnames_from_eventbox(eventbox=self.eventBox)
|
||||
self.stationBox.clear()
|
||||
model = self.stationBox.model()
|
||||
|
||||
self.catch_station_ids()
|
||||
st_ids_list = list(self.station_ids.keys())
|
||||
st_ids_list.sort()
|
||||
for station_id in st_ids_list:
|
||||
item = QtGui.QStandardItem(station_id)
|
||||
if station_id.split('.')[1] in self.get_current_event().pylot_picks:
|
||||
item.setBackground(self.parent()._ref_test_colors['ref'])
|
||||
model.appendRow(item)
|
||||
|
||||
def load_wf_data(self):
|
||||
fnames = self.station_ids[self.get_current_station_id()]
|
||||
self.data.setWFData(fnames)
|
||||
wfdat = self.data.getWFData() # all available streams
|
||||
# remove possible underscores in station names
|
||||
@ -3022,21 +3143,6 @@ class TuneAutopicker(QWidget):
|
||||
wfdat = check4rotated(wfdat, self.parent().metadata, verbosity=0)
|
||||
# trim station components to same start value
|
||||
trim_station_components(wfdat, trim_start=True, trim_end=False)
|
||||
self.stationBox.clear()
|
||||
stations = []
|
||||
for trace in self.data.getWFData():
|
||||
station = trace.stats.station
|
||||
network = trace.stats.network
|
||||
ns_tup = (str(network), str(station))
|
||||
if not ns_tup in stations:
|
||||
stations.append(ns_tup)
|
||||
stations.sort()
|
||||
model = self.stationBox.model()
|
||||
for network, station in stations:
|
||||
item = QtGui.QStandardItem(network + '.' + station)
|
||||
if station in self.get_current_event().pylot_picks:
|
||||
item.setBackground(self.parent()._ref_test_colors['ref'])
|
||||
model.appendRow(item)
|
||||
|
||||
def init_figure_tabs(self):
|
||||
self.figure_tabs = QtGui.QTabWidget()
|
||||
@ -3093,10 +3199,14 @@ class TuneAutopicker(QWidget):
|
||||
def get_current_event_autopicks(self, station):
|
||||
event = self.get_current_event()
|
||||
if event.pylot_autopicks:
|
||||
return event.pylot_autopicks[station]
|
||||
if station in event.pylot_autopicks:
|
||||
return event.pylot_autopicks[station]
|
||||
|
||||
def get_current_station(self):
|
||||
return str(self.stationBox.currentText()).split('.')[-1]
|
||||
return str(self.stationBox.currentText()).split('.')[1]
|
||||
|
||||
def get_current_station_id(self):
|
||||
return str(self.stationBox.currentText())
|
||||
|
||||
def gen_tab_widget(self, name, canvas):
|
||||
widget = QtGui.QWidget()
|
||||
@ -3111,17 +3221,19 @@ class TuneAutopicker(QWidget):
|
||||
self.pdlg_widget.setParent(None)
|
||||
self.pdlg_widget = None
|
||||
return
|
||||
self.load_wf_data()
|
||||
station = self.get_current_station()
|
||||
data = self.data.getWFData()
|
||||
wfdata = self.data.getWFData()
|
||||
metadata = self.parent().metadata
|
||||
event = self.get_current_event()
|
||||
filteroptions = self.parent().filteroptions
|
||||
self.pickDlg = PickDlg(self.parent(), data=data.select(station=station),
|
||||
wftype = self.wftype if self.obspy_dmt else ''
|
||||
self.pickDlg = PickDlg(self.parent(), data=wfdata.select(station=station).copy(),
|
||||
station=station, parameter=self.parameter,
|
||||
picks=self.get_current_event_picks(station),
|
||||
autopicks=self.get_current_event_autopicks(station),
|
||||
metadata=metadata, event=event, filteroptions=filteroptions,
|
||||
embedded=True)
|
||||
embedded=True, wftype=wftype)
|
||||
self.pickDlg.update_picks.connect(self.picks_from_pickdlg)
|
||||
self.pickDlg.update_picks.connect(self.fill_eventbox)
|
||||
self.pickDlg.update_picks.connect(self.fill_stationbox)
|
||||
@ -3301,14 +3413,17 @@ class TuneAutopicker(QWidget):
|
||||
if not station:
|
||||
self._warn('No station selected')
|
||||
return
|
||||
wfpath = self.wftype if self.obspy_dmt else ''
|
||||
args = {'parameter': self.parameter,
|
||||
'station': station,
|
||||
'fnames': 'None',
|
||||
'eventid': [self.get_current_event_fp()],
|
||||
'iplot': 2,
|
||||
'fig_dict': self.fig_dict,
|
||||
'locflag': 0,
|
||||
'savexml': False}
|
||||
'savexml': False,
|
||||
'obspyDMT_wfpath': wfpath}
|
||||
event = self.get_current_event()
|
||||
self.parent().saveData(event, event.path, '.xml')
|
||||
for key in self.fig_dict.keys():
|
||||
if not key == 'plot_style':
|
||||
self.fig_dict[key].clear()
|
||||
@ -3364,8 +3479,7 @@ class TuneAutopicker(QWidget):
|
||||
if hasattr(self, 'pdlg_widget'):
|
||||
if self.pdlg_widget:
|
||||
self.pdlg_widget.setParent(None)
|
||||
# TODO: removing widget by parent deletion raises exception when activating stationbox:
|
||||
# RuntimeError: Internal C++ object (PylotCanvas) already deleted.
|
||||
del(self.pdlg_widget)
|
||||
if hasattr(self, 'overview'):
|
||||
self.overview.setParent(None)
|
||||
if hasattr(self, 'p_tabs'):
|
||||
|
@ -179,9 +179,9 @@ background-color:transparent;
|
||||
|
||||
QTabWidget::pane{
|
||||
background-color:rgba(0, 0, 0, 255);
|
||||
border-style:solid;
|
||||
border-color:rgba(245, 245, 245, 255);
|
||||
border-width:1px;
|
||||
margin: 0px, 0px, 0px, 0px;
|
||||
padding: 0px;
|
||||
border-width:0px;
|
||||
}
|
||||
|
||||
QTabWidget::tab{
|
||||
|
@ -178,9 +178,9 @@ background-color:transparent;
|
||||
|
||||
QTabWidget::pane{
|
||||
background-color:rgba(70, 70, 80, 255);
|
||||
border-style:solid;
|
||||
border-color:rgba(70, 70, 80, 255);
|
||||
border-width:1px;
|
||||
margin: 0px, 0px, 0px, 0px;
|
||||
padding: 0px;
|
||||
border-width:0px;
|
||||
}
|
||||
|
||||
QTabWidget::tab{
|
||||
|
Loading…
Reference in New Issue
Block a user