Merge branch 'develop' into correlation_picker

This commit is contained in:
Marcel Paffrath 2024-08-27 17:46:21 +02:00
commit 5d90904838
16 changed files with 252 additions and 198 deletions

39
.mailmap Normal file
View File

@ -0,0 +1,39 @@
Darius Arnold <Darius.Arnold@ruhr-uni-bochum.de> <Darius_A@web.de>
Darius Arnold <Darius.Arnold@ruhr-uni-bochum.de> <darius.arnold@rub.de>
Darius Arnold <Darius.Arnold@ruhr-uni-bochum.de> <darius.arnold@ruhr-uni-bochum.de>
Darius Arnold <Darius.Arnold@ruhr-uni-bochum.de> <mail@dariusarnold.de>
Dennis Wlecklik <dennisw@minos02.geophysik.ruhr-uni-bochum.de>
Jeldrik Gaal <jeldrikgaal@gmail.com>
Kaan Coekerim <kaan.coekerim@ruhr-uni-bochum.de>
Kaan Coekerim <kaan.coekerim@ruhr-uni-bochum.de> <kaan.coekerim@rub.de>
Ludger Kueperkoch <kueperkoch@igem-energie.de> <kueperkoch@bestec-for-nature.com>
Ludger Kueperkoch <kueperkoch@igem-energie.de> <ludger@quake2.(none)>
Ludger Kueperkoch <kueperkoch@igem-energie.de> <ludger@sauron.bestec-for-nature>
Marc S. Boxberg <marc.boxberg@rub.de>
Marcel Paffrath <marcel.paffrath@ruhr-uni-bochum.de> <marcel.paffrath@rub.de>
Marcel Paffrath <marcel.paffrath@ruhr-uni-bochum.de> <marcel@minos01.geophysik.ruhr-uni-bochum.de>
Marcel Paffrath <marcel.paffrath@ruhr-uni-bochum.de> <marcel@minos02.geophysik.ruhr-uni-bochum.de>
Marcel Paffrath <marcel.paffrath@ruhr-uni-bochum.de> <marcel@minos25.geophysik.ruhr-uni-bochum.de>
Marcel Paffrath <marcel.paffrath@ruhr-uni-bochum.de> <marcel@email.com>
Sally Zimmermann <sally.zimmermann@ruhr-uni-bochum.de>
Sebastian Wehling-Benatelli <sebastian.wehling-benatelli@cgi.com> <sebastianw@minos01.geophysik.ruhr-uni-bochum.de>
Sebastian Wehling-Benatelli <sebastian.wehling-benatelli@cgi.com> <sebastianw@minos02.geophysik.ruhr-uni-bochum.de>
Sebastian Wehling-Benatelli <sebastian.wehling-benatelli@cgi.com> <sebastianw@minos22.geophysik.ruhr-uni-bochum.de>
Sebastian Wehling-Benatelli <sebastian.wehling-benatelli@cgi.com> <sebastian.wehling-benatelli@scisys.de>
Sebastian Wehling-Benatelli <sebastian.wehling-benatelli@cgi.com> <sebastian.wehling@rub.de>
Sebastian Wehling-Benatelli <sebastian.wehling-benatelli@cgi.com> <sebastian.wehling@rub.de>
Sebastian Wehling-Benatelli <sebastian.wehling-benatelli@cgi.com> <DarkBeQst@users.noreply.github.com>
Thomas Moeller <thomas.moeller@rub.de>
Ann-Christin Koch <ann-christin.koch@ruhr-uni-bochum.de> <Ann-Christin.Koch@ruhr-uni-bochum.de>
Sebastian Priebe <sebastian.priebe@rub.de>

101
PyLoT.py
View File

@ -83,7 +83,7 @@ from pylot.core.util.event import Event
from pylot.core.io.location import create_creation_info, create_event
from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \
PylotCanvas, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \
ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \
ComparisonWidget, TuneAutopicker, PylotParameterWidget, AutoPickDlg, CanvasWidget, AutoPickWidget, \
CompareEventsWidget, ProgressBarWidget, AddMetadataWidget, SingleTextLineDialog, LogWidget, PickQualitiesFromXml, \
SpectrogramTab, SearchFileByExtensionDialog
from pylot.core.util.array_map import Array_map
@ -136,7 +136,7 @@ class MainWindow(QMainWindow):
self.project.parameter = self._inputs
self.tap = None
self.apw = None
self.paraBox = None
self.parameterWidget = None
self.array_map = None
self._metadata = Metadata(verbosity=0)
self._eventChanged = [False, False]
@ -188,7 +188,6 @@ class MainWindow(QMainWindow):
self.table_headers = ['', 'Event', 'Time', 'Lat', 'Lon', 'Depth', 'Ml', 'Mw', '[N] MP', '[N] AP', 'Tuning Set',
'Test Set', 'Notes']
# TODO: refactor rootpath to datapath
while True:
try:
if settings.value("user/FullName", None) is None:
@ -686,10 +685,9 @@ class MainWindow(QMainWindow):
# add scroll area used in case number of traces gets too high
self.wf_scroll_area = QtWidgets.QScrollArea(self)
self.wf_scroll_area.setVisible(False)
self.no_data_label = QLabel('No Data')
self.no_data_label = QLabel('No Data. If data were already loaded, try to select the event again in the eventbox.')
self.no_data_label.setStyleSheet('color: red')
self.no_data_label.setAlignment(Qt.AlignCenter)
# create central matplotlib figure canvas widget
self.init_wfWidget()
@ -1032,6 +1030,21 @@ class MainWindow(QMainWindow):
fname = self.filename_from_action(action)
if not fname:
return
qmb = QMessageBox(self, icon=QMessageBox.Question,
text='Do you want to overwrite this data?',)
overwrite_button = qmb.addButton('Overwrite', QMessageBox.YesRole)
merge_button = qmb.addButton('Merge', QMessageBox.NoRole)
qmb.exec_()
if qmb.clickedButton() == overwrite_button:
merge_strategy = 'Overwrite'
elif qmb.clickedButton() == merge_button:
merge_strategy = 'Merge'
else:
return
if not event:
event = self.get_current_event()
data = Data(self, event)
@ -1196,7 +1209,7 @@ class MainWindow(QMainWindow):
with open(eventlist_file, 'r') as infile:
eventlist_subset = [os.path.join(basepath, filename.split('\n')[0]) for filename in
infile.readlines()]
msg = 'Found file "eventlist.txt" in database path. WILL ONLY USE SELECTED EVENTS out of {} events ' \
msg = 'Found file "eventlist.txt" in datapath. WILL ONLY USE SELECTED EVENTS out of {} events ' \
'contained in this subset'
print(msg.format(len(eventlist_subset)))
eventlist = [eventname for eventname in eventlist if eventname in eventlist_subset]
@ -1221,49 +1234,34 @@ class MainWindow(QMainWindow):
# get path from first event in list and split them
path = eventlist[0]
try:
system_name = platform.system()
if system_name in ["Linux", "Darwin"]:
dirs = {
'database': path.split('/')[-2],
'datapath': os.path.split(path)[0], # path.split('/')[-3],
'rootpath': '/' + os.path.join(*path.split('/')[:-3])
}
elif system_name == "Windows":
rootpath = path.split('/')[:-3]
rootpath[0] += '/'
dirs = {
# TODO: Arrange path to meet Win standards
'database': path.split('/')[-2],
'datapath': path.split('/')[-3],
'rootpath': os.path.join(*rootpath)
}
datapath = os.path.split(path)[0]
dirs = {
'datapath': datapath,
}
except Exception as e:
dirs = {
'database': '',
'datapath': '',
'rootpath': ''
}
print('Warning: Could not automatically init folder structure. ({})'.format(e))
settings = QSettings()
settings.setValue("data/dataRoot", dirs['datapath']) # d irs['rootpath'])
settings.setValue("data/dataRoot", dirs['datapath'])
settings.sync()
if not self.project.eventlist:
# init parameter object
self.setParameter(show=False)
# hide all parameter (show all needed parameter later)
self.paraBox.hide_parameter()
self.parameterWidget.hide_parameter()
for directory in dirs.keys():
# set parameter
box = self.paraBox.boxes[directory]
self.paraBox.setValue(box, dirs[directory])
box = self.parameterWidget.boxes[directory]
self.parameterWidget.setValue(box, dirs[directory])
# show needed parameter in box
self.paraBox.show_parameter(directory)
dirs_box = self.paraBox.get_groupbox_dialog('Directories')
self.parameterWidget.show_parameter(directory)
dirs_box = self.parameterWidget.get_groupbox_dialog('Directories')
if not dirs_box.exec_():
return
self.project.rootpath = dirs['rootpath']
self.project.datapath = dirs['datapath']
else:
if hasattr(self.project, 'datapath'):
@ -1272,7 +1270,6 @@ class MainWindow(QMainWindow):
'Datapath missmatch to current project!')
return
else:
self.project.rootpath = dirs['rootpath']
self.project.datapath = dirs['datapath']
self.project.add_eventlist(eventlist)
@ -1360,11 +1357,10 @@ class MainWindow(QMainWindow):
return True
def modify_project_path(self, new_rootpath):
# TODO: change root to datapath
self.project.rootpath = new_rootpath
self.project.datapath = new_rootpath
for event in self.project.eventlist:
event.rootpath = new_rootpath
event.path = os.path.join(event.rootpath, event.datapath, event.database, event.pylot_id)
event.datapath = new_rootpath
event.path = os.path.join(event.datapath, event.pylot_id)
event.path = event.path.replace('\\', '/')
event.path = event.path.replace('//', '/')
@ -1558,7 +1554,7 @@ class MainWindow(QMainWindow):
self.set_fname(self.get_data().getEventFileName(), type)
return self.get_fnames(type)
def saveData(self, event=None, directory=None, outformats=['.xml', '.cnv', '.obs', '_focmec.in', '.pha']):
def saveData(self, event=None, directory=None, outformats=None):
'''
Save event data to directory with specified output formats.
:param event: PyLoT Event, if not set current event will be used
@ -1566,6 +1562,8 @@ class MainWindow(QMainWindow):
:param outformats: str/list of output formats
:return:
'''
if outformats is None:
outformats = ['.xml', '.cnv', '.obs', '_focmec.in', '.pha']
if not event:
event = self.get_current_event()
if not type(outformats) == list:
@ -1701,7 +1699,7 @@ class MainWindow(QMainWindow):
# WIP JG
def eventlistXml(self):
path = self._inputs['rootpath'] + '/' + self._inputs['datapath'] + '/' + self._inputs['database']
path = self._inputs['datapath']
outpath = self.project.location[:self.project.location.rfind('/')]
geteventlistfromxml(path, outpath)
return
@ -2428,7 +2426,7 @@ class MainWindow(QMainWindow):
filterS = filteroptions['S']
minP, maxP = filterP.getFreq()
minS, maxS = filterS.getFreq()
self.paraBox.params_to_gui()
self.parameterWidget.params_to_gui()
def getFilterOptions(self):
return self.filteroptions
@ -3176,8 +3174,8 @@ class MainWindow(QMainWindow):
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')
obsdir = os.path.join(self._inputs['datapath'], 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')
@ -3734,6 +3732,7 @@ class MainWindow(QMainWindow):
if self.project.parameter:
# do this step to update default parameter on older PyLoT projects
self.project.parameter.reinit_default_parameters()
PylotParameter.check_deprecated_parameters(self.project.parameter)
self._inputs = self.project.parameter
self.updateFilteroptions()
@ -3851,13 +3850,13 @@ class MainWindow(QMainWindow):
def setParameter(self, checked=0, show=True):
if checked: pass # dummy argument to receive trigger signal (checked) if called by QAction
if not self.paraBox:
self.paraBox = PylotParaBox(self._inputs, parent=self, windowflag=Qt.Window)
self.paraBox.accepted.connect(self._setDirty)
self.paraBox.accepted.connect(self.filterOptionsFromParameter)
if not self.parameterWidget:
self.parameterWidget = PylotParameterWidget(self._inputs, parent=self, windowflag=Qt.Window)
self.parameterWidget.accepted.connect(self._setDirty)
self.parameterWidget.accepted.connect(self.filterOptionsFromParameter)
if show:
self.paraBox.params_to_gui()
self.paraBox.show()
self.parameterWidget.params_to_gui()
self.parameterWidget.show()
def deleteAllAutopicks(self):
qmb = QMessageBox(self, icon=QMessageBox.Question,
@ -3904,16 +3903,18 @@ class Project(object):
Pickable class containing information of a PyLoT project, like event lists and file locations.
'''
# TODO: remove rootpath
def __init__(self):
self.eventlist = []
self.location = None
self.rootpath = None
self.datapath = None
self.dirty = False
self.parameter = None
self._table = None
@property
def rootpath(self):
return self.datapath
def add_eventlist(self, eventlist):
'''
Add events from an eventlist containing paths to event directories.
@ -3923,8 +3924,6 @@ class Project(object):
return
for item in eventlist:
event = Event(item)
event.rootpath = self.parameter['rootpath']
event.database = self.parameter['database']
event.datapath = self.parameter['datapath']
if not event.path in self.getPaths():
self.eventlist.append(event)

View File

@ -136,11 +136,9 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
if parameter.hasParam('datastructure'):
# getting information on data structure
datastructure = DATASTRUCTURE[parameter.get('datastructure')]()
dsfields = {'root': parameter.get('rootpath'),
'dpath': parameter.get('datapath'),
'dbase': parameter.get('database')}
dsfields = {'dpath': parameter.get('datapath'),}
exf = ['root', 'dpath', 'dbase']
exf = ['dpath']
if parameter['eventID'] != '*' and fnames == 'None':
dsfields['eventID'] = parameter['eventID']
@ -206,12 +204,10 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
locflag = 2
else:
# started in tune or interactive mode
datapath = os.path.join(parameter['rootpath'],
parameter['datapath'])
datapath = parameter['datapath']
events = []
for eventID in eventid:
events.append(os.path.join(datapath,
parameter['database'],
eventID))
if not events:

View File

@ -203,8 +203,6 @@ The meaning of the header entries is:
PyLoT GUI starts with an empty project. To add events, use the add event data button. Select one or multiple folders
containing events.
[//]: <> (TODO: explain _Directories: Root path, Data path, Database path_)
### Saving projects
Save the current project from the menu with File->Save project or File->Save project as. PyLoT uses ``.plp`` files to

View File

@ -4,10 +4,8 @@
%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)
#datapath# %data path
#eventID# %event ID for single event processing (* for all events found in datapath)
#invdir# %full path to inventory or dataless-seed file
PILOT #datastructure# %choose data structure
True #apverbose# %choose 'True' or 'False' for terminal output

View File

@ -4,10 +4,8 @@
%Parameters are optimized for %extent data sets!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#main settings#
/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/EVENT_DATA/LOCAL/2018.02_Insheim #datapath# %data path
e0006.038.18 #eventID# %event ID for single event processing (* for all events found in datapath)
/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

View File

@ -4,10 +4,8 @@
%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)
#datapath# %data path
#eventID# %event ID for single event processing (* for all events found in datapath)
#invdir# %full path to inventory or dataless-seed file
PILOT #datastructure# %choose data structure
True #apverbose# %choose 'True' or 'False' for terminal output

View File

@ -6,24 +6,14 @@ import numpy as np
Default parameters used for picking
"""
defaults = {'rootpath': {'type': str,
'tooltip': 'project path',
'value': '',
'namestring': 'Root path'},
'datapath': {'type': str,
'tooltip': 'data path',
defaults = {'datapath': {'type': str,
'tooltip': 'path to eventfolders',
'value': '',
'namestring': 'Data path'},
'database': {'type': str,
'tooltip': 'name of data base',
'value': '',
'namestring': 'Database path'},
'eventID': {'type': str,
'tooltip': 'event ID for single event processing (* for all events found in database)',
'value': '',
'tooltip': 'event ID for single event processing (* for all events found in datapath)',
'value': '*',
'namestring': 'Event ID'},
'extent': {'type': str,
@ -522,9 +512,7 @@ defaults = {'rootpath': {'type': str,
settings_main = {
'dirs': [
'rootpath',
'datapath',
'database',
'eventID',
'invdir',
'datastructure',

View File

@ -1,5 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
import os
from pylot.core.io import default_parameters
from pylot.core.util.errors import ParameterError
@ -88,10 +90,10 @@ class PylotParameter(object):
return bool(self.__parameter)
def __getitem__(self, key):
try:
if key in self.__parameter:
return self.__parameter[key]
except:
return None
else:
logging.warning(f'{key} not found in PylotParameter')
def __setitem__(self, key, value):
try:
@ -418,6 +420,28 @@ class PylotParameter(object):
line = value + name + ttip
fid.write(line)
@staticmethod
def check_deprecated_parameters(parameters):
if parameters.hasParam('database') and parameters.hasParam('rootpath'):
parameters['datapath'] = os.path.join(parameters['rootpath'], parameters['datapath'],
parameters['database'])
logging.warning(
f'Parameters database and rootpath are deprecated. '
f'Tried to merge them to now path: {parameters["datapath"]}.'
)
remove_keys = []
for key in parameters:
if not key in default_parameters.defaults.keys():
remove_keys.append(key)
logging.warning(f'Removing deprecated parameter: {key}')
for key in remove_keys:
del parameters[key]
parameters._settings_main = default_parameters.settings_main
parameters._settings_special_pick = default_parameters.settings_special_pick
class FilterOptions(object):
'''

View File

@ -512,7 +512,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
fid = open("%s" % filename, 'w')
# write header
fid.write('# EQEVENT: %s Label: EQ%s Loc: X 0.00 Y 0.00 Z 10.00 OT 0.00 \n' %
(parameter.get('database'), parameter.get('eventID')))
(parameter.get('datapath'), parameter.get('eventID')))
arrivals = chooseArrivals(arrivals) # MP MP what is chooseArrivals? It is not defined anywhere
for key in arrivals:
# P onsets
@ -665,7 +665,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
print("Writing phases to %s for HYPOSAT" % filename)
fid = open("%s" % filename, 'w')
# write header
fid.write('%s, event %s \n' % (parameter.get('database'), parameter.get('eventID')))
fid.write('%s, event %s \n' % (parameter.get('datapath'), parameter.get('eventID')))
arrivals = chooseArrivals(arrivals) # MP MP what is chooseArrivals? It is not defined anywhere
for key in arrivals:
# P onsets

View File

@ -5,12 +5,13 @@ import traceback
import cartopy.crs as ccrs
import cartopy.feature as cf
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
import matplotlib
import matplotlib.patheffects as PathEffects
import matplotlib.pyplot as plt
import numpy as np
import obspy
from PySide2 import QtWidgets
from PySide2 import QtWidgets, QtGui
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
from pylot.core.util.utils import identifyPhaseID
@ -24,10 +25,10 @@ matplotlib.use('Qt5Agg')
class MplCanvas(FigureCanvas):
def __init__(self, parent=None, extern_axes=None, width=5, height=4, dpi=100):
def __init__(self, extern_axes=None, projection=None, width=15, height=5, dpi=100):
if extern_axes is None:
self.fig = plt.figure(figsize=(width, height), dpi=dpi)
self.axes = self.fig.add_subplot(111)
self.axes = self.fig.add_subplot(111, projection=projection)
else:
self.fig = extern_axes.figure
self.axes = extern_axes
@ -63,20 +64,25 @@ class Array_map(QtWidgets.QWidget):
self.highlighted_stations = []
# call functions to draw everything
self.projection = ccrs.PlateCarree()
self.init_graphics()
self.ax = self.canvas.axes
self.ax.set_adjustable('datalim')
self.init_stations()
self.init_crtpyMap()
self.init_map()
# set original map limits to fall back on when home button is pressed
self.org_xlim = self.canvas.axes.get_xlim()
self.org_ylim = self.canvas.axes.get_ylim()
self.org_xlim = self.ax.get_xlim()
self.org_ylim = self.ax.get_ylim()
# initial map without event
self.canvas.axes.set_xlim(self.org_xlim[0], self.org_xlim[1])
self.canvas.axes.set_ylim(self.org_ylim[0], self.org_ylim[1])
self.ax.set_xlim(self.org_xlim[0], self.org_xlim[1])
self.ax.set_ylim(self.org_ylim[0], self.org_ylim[1])
self._style = None if not hasattr(parent, '_style') else parent._style
def init_map(self):
self.init_colormap()
self.connectSignals()
@ -89,11 +95,11 @@ class Array_map(QtWidgets.QWidget):
# initialize figure elements
if self.extern_plot_axes is None:
self.canvas = MplCanvas(self)
self.plotWidget = FigureCanvas(self.canvas.fig)
self.canvas = MplCanvas(projection=self.projection)
else:
self.canvas = MplCanvas(self, extern_axes=self.extern_plot_axes)
self.plotWidget = FigureCanvas(self.canvas.fig)
self.canvas = MplCanvas(extern_axes=self.extern_plot_axes)
self.plotWidget = self.canvas
# initialize GUI elements
self.status_label = QtWidgets.QLabel()
@ -105,7 +111,7 @@ class Array_map(QtWidgets.QWidget):
self.setLayout(self.main_box)
self.top_row = QtWidgets.QHBoxLayout()
self.main_box.addLayout(self.top_row, 1)
self.main_box.addLayout(self.top_row, 0)
self.comboBox_phase = QtWidgets.QComboBox()
self.comboBox_phase.insertItem(0, 'P')
@ -138,10 +144,10 @@ class Array_map(QtWidgets.QWidget):
self.top_row.addWidget(self.auto_refresh_box)
self.top_row.addWidget(self.refresh_button)
self.main_box.addWidget(self.plotWidget, 1)
self.main_box.addWidget(self.plotWidget, 10)
self.bot_row = QtWidgets.QHBoxLayout()
self.main_box.addLayout(self.bot_row, 0.3)
self.main_box.addLayout(self.bot_row, 0)
self.bot_row.addWidget(QtWidgets.QLabel(''), 5)
self.bot_row.addWidget(self.map_reset_button, 2)
self.bot_row.addWidget(self.go2eq_button, 2)
@ -153,14 +159,12 @@ class Array_map(QtWidgets.QWidget):
self.init_lat_lon_grid()
def init_crtpyMap(self):
self.canvas.axes.cla()
self.canvas.axes = plt.axes(projection=ccrs.PlateCarree())
self.canvas.axes.add_feature(cf.LAND)
self.canvas.axes.add_feature(cf.OCEAN)
self.canvas.axes.add_feature(cf.COASTLINE, linewidth=1, edgecolor='gray')
self.canvas.axes.add_feature(cf.BORDERS, alpha=0.7)
self.canvas.axes.add_feature(cf.LAKES, alpha=0.7)
self.canvas.axes.add_feature(cf.RIVERS, linewidth=1)
self.ax.add_feature(cf.LAND)
self.ax.add_feature(cf.OCEAN)
self.ax.add_feature(cf.COASTLINE, linewidth=1, edgecolor='gray')
self.ax.add_feature(cf.BORDERS, alpha=0.7)
self.ax.add_feature(cf.LAKES, alpha=0.7)
self.ax.add_feature(cf.RIVERS, linewidth=1)
# parallels and meridians
self.add_merid_paral()
@ -168,12 +172,8 @@ class Array_map(QtWidgets.QWidget):
self.canvas.fig.tight_layout()
def add_merid_paral(self):
self.gridlines = self.canvas.axes.gridlines(draw_labels=False, alpha=0.6, color='gray',
linewidth=self.linewidth / 2, zorder=7)
# TODO: current cartopy version does not support label removal. Devs are working on it.
# Should be fixed in coming cartopy versions
# self.gridlines.xformatter = LONGITUDE_FORMATTER
# self.gridlines.yformatter = LATITUDE_FORMATTER
self.gridlines = self.ax.gridlines(draw_labels=False, alpha=0.6, color='gray',
linewidth=self.linewidth / 2, zorder=7, crs=ccrs.PlateCarree())
def remove_merid_paral(self):
if len(self.gridlines.xline_artists):
@ -181,24 +181,24 @@ class Array_map(QtWidgets.QWidget):
self.gridlines.yline_artists[0].remove()
def org_map_view(self):
self.canvas.axes.set_xlim(self.org_xlim[0], self.org_xlim[1])
self.canvas.axes.set_ylim(self.org_ylim[0], self.org_ylim[1])
self.ax.set_xlim(self.org_xlim[0], self.org_xlim[1])
self.ax.set_ylim(self.org_ylim[0], self.org_ylim[1])
# parallels and meridians
self.remove_merid_paral()
self.add_merid_paral()
#self.remove_merid_paral()
#self.add_merid_paral()
self.canvas.axes.figure.canvas.draw_idle()
self.canvas.draw_idle()
def go2eq(self):
if self.eventLoc:
lats, lons = self.eventLoc
self.canvas.axes.set_xlim(lons - 10, lons + 10)
self.canvas.axes.set_ylim(lats - 5, lats + 5)
self.ax.set_xlim(lons - 10, lons + 10)
self.ax.set_ylim(lats - 5, lats + 5)
# parallels and meridians
self.remove_merid_paral()
self.add_merid_paral()
#self.remove_merid_paral()
#self.add_merid_paral()
self.canvas.axes.figure.canvas.draw_idle()
self.canvas.draw_idle()
else:
self.status_label.setText('No event information available')
@ -220,21 +220,32 @@ class Array_map(QtWidgets.QWidget):
# set mouse events -----------------------------------------------------
def mouse_moved(self, event):
if not event.inaxes == self.canvas.axes:
if not event.inaxes == self.ax:
return
else:
cont, inds = self.sc.contains(event)
lat = event.ydata
lon = event.xdata
self.status_label.setText('Latitude: {:3.5f}, Longitude: {:3.5f}'.format(lat, lon))
text = f'Longitude: {lon:3.3f}, Latitude: {lat:3.3f}'
if cont:
indices = inds['ind']
text += ' | Station: ' if len(indices) == 1 else ' | Stations: '
text += ' - '.join([self._station_onpick_ids[index] for index in indices[:5]])
if len(indices) > 5:
text += '...'
self.status_label.setText(text)
def mouse_scroll(self, event):
if not event.inaxes == self.canvas.axes:
if not event.inaxes == self.ax:
return
zoom = {'up': 1. / 2., 'down': 2.}
if event.button in zoom:
xlim = self.canvas.axes.get_xlim()
ylim = self.canvas.axes.get_ylim()
xlim = self.ax.get_xlim()
ylim = self.ax.get_ylim()
x, y = event.xdata, event.ydata
@ -246,24 +257,24 @@ class Array_map(QtWidgets.QWidget):
yb = y - 0.5 * ydiff
yt = y + 0.5 * ydiff
self.canvas.axes.set_xlim(xl, xr)
self.canvas.axes.set_ylim(yb, yt)
self.ax.set_xlim(xl, xr)
self.ax.set_ylim(yb, yt)
# parallels and meridians
self.remove_merid_paral()
self.add_merid_paral()
#self.remove_merid_paral()
#self.add_merid_paral()
self.canvas.axes.figure.canvas.draw_idle()
self.ax.figure.canvas.draw_idle()
def mouseLeftPress(self, event):
if not event.inaxes == self.canvas.axes:
if not event.inaxes == self.ax:
return
self.map_x = event.xdata
self.map_y = event.ydata
self.map_xlim = self.canvas.axes.get_xlim()
self.map_ylim = self.canvas.axes.get_ylim()
self.map_xlim = self.ax.get_xlim()
self.map_ylim = self.ax.get_ylim()
def mouseLeftRelease(self, event):
if not event.inaxes == self.canvas.axes:
if not event.inaxes == self.ax:
return
new_x = event.xdata
new_y = event.ydata
@ -271,13 +282,13 @@ class Array_map(QtWidgets.QWidget):
dx = new_x - self.map_x
dy = new_y - self.map_y
self.canvas.axes.set_xlim((self.map_xlim[0] - dx, self.map_xlim[1] - dx))
self.canvas.axes.set_ylim(self.map_ylim[0] - dy, self.map_ylim[1] - dy)
self.ax.set_xlim((self.map_xlim[0] - dx, self.map_xlim[1] - dx))
self.ax.set_ylim(self.map_ylim[0] - dy, self.map_ylim[1] - dy)
# parallels and meridians
self.remove_merid_paral()
self.add_merid_paral()
#self.remove_merid_paral()
#self.add_merid_paral()
self.canvas.axes.figure.canvas.draw_idle()
self.ax.figure.canvas.draw_idle()
def onpick(self, event):
btn_msg = {1: ' in selection. Aborted', 2: ' to delete a pick on. Aborted', 3: ' to display info.'}
@ -421,6 +432,9 @@ class Array_map(QtWidgets.QWidget):
picks_rel[st_id] = pick
return picks_rel
def get_picks_rel_mean_corr(picks):
return get_picks_rel(picks, func=np.nanmean)
self.picks, self.uncertainties = get_picks(self.stations_dict)
self.picks_rel = get_picks_rel(self.picks)
@ -469,12 +483,19 @@ class Array_map(QtWidgets.QWidget):
stat_dict = self.stations_dict['{}.{}'.format(network, station)]
lat = stat_dict['latitude']
lon = stat_dict['longitude']
self.highlighted_stations.append(self.canvas.axes.scatter(lon, lat, s=self.pointsize, edgecolors=color,
facecolors='none', zorder=12,
transform=ccrs.PlateCarree(), label='deleted'))
self.highlighted_stations.append(self.ax.scatter(lon, lat, s=self.pointsize, edgecolors=color,
facecolors='none', zorder=12,
transform=ccrs.PlateCarree(), label='deleted'))
def openPickDlg(self, ind):
wfdata = self._parent.get_data().getWFData()
try:
wfdata = self._parent.get_data().getWFData()
except AttributeError:
QtWidgets.QMessageBox.warning(
self, "PyLoT Warning",
"No waveform data found. Check if they were already loaded in Waveform plot tab."
)
return
wfdata_comp = self._parent.get_data().getAltWFdata()
for index in ind:
network, station = self._station_onpick_ids[index].split('.')[:2]
@ -520,9 +541,9 @@ class Array_map(QtWidgets.QWidget):
def draw_contour_filled(self, nlevel=50):
levels = np.linspace(self.get_min_from_picks(), self.get_max_from_picks(), nlevel)
self.contourf = self.canvas.axes.contourf(self.longrid, self.latgrid, self.picksgrid_active, levels,
linewidths=self.linewidth * 5, transform=ccrs.PlateCarree(),
alpha=0.4, zorder=8, cmap=self.get_colormap())
self.contourf = self.ax.contourf(self.longrid, self.latgrid, self.picksgrid_active, levels,
linewidths=self.linewidth * 5, transform=ccrs.PlateCarree(),
alpha=0.4, zorder=8, cmap=self.get_colormap())
def get_colormap(self):
return plt.get_cmap(self.cmaps_box.currentText())
@ -530,18 +551,18 @@ class Array_map(QtWidgets.QWidget):
def scatter_all_stations(self):
stations, lats, lons = self.get_st_lat_lon_for_plot()
self.sc = self.canvas.axes.scatter(lons, lats, s=self.pointsize * 3, facecolor='none', marker='.',
zorder=10, picker=True, edgecolor='0.5', label='Not Picked',
transform=ccrs.PlateCarree())
self.sc = self.ax.scatter(lons, lats, s=self.pointsize * 3, facecolor='none', marker='.',
zorder=10, picker=True, edgecolor='0.5', label='Not Picked',
transform=ccrs.PlateCarree())
self.cid = self.plotWidget.mpl_connect('pick_event', self.onpick)
self._station_onpick_ids = stations
if self.eventLoc:
lats, lons = self.eventLoc
self.sc_event = self.canvas.axes.scatter(lons, lats, s=5 * self.pointsize, facecolor='red', zorder=11,
label='Event (might be outside map region)', marker='*',
edgecolors='black',
transform=ccrs.PlateCarree())
self.sc_event = self.ax.scatter(lons, lats, s=5 * self.pointsize, facecolor='red', zorder=11,
label='Event (might be outside map region)', marker='*',
edgecolors='black',
transform=ccrs.PlateCarree())
def scatter_picked_stations(self):
picks, uncertainties, lats, lons = self.get_picks_lat_lon()
@ -554,8 +575,8 @@ class Array_map(QtWidgets.QWidget):
for uncertainty in uncertainties])
cmap = self.get_colormap()
self.sc_picked = self.canvas.axes.scatter(lons, lats, s=sizes, edgecolors='white', cmap=cmap,
c=picks, zorder=11, label='Picked', transform=ccrs.PlateCarree())
self.sc_picked = self.ax.scatter(lons, lats, s=sizes, edgecolors='white', cmap=cmap,
c=picks, zorder=11, label='Picked', transform=ccrs.PlateCarree())
def annotate_ax(self):
self.annotations = []
@ -573,20 +594,20 @@ class Array_map(QtWidgets.QWidget):
if st in self.marked_stations:
color = 'red'
self.annotations.append(
self.canvas.axes.annotate(' %s' % st, xy=(x + 0.003, y + 0.003), fontsize=self.pointsize / 4.,
fontweight='semibold', color=color, alpha=0.8,
transform=ccrs.PlateCarree(), zorder=14,
path_effects=[PathEffects.withStroke(
linewidth=self.pointsize / 15., foreground='k')]))
self.ax.annotate(f'{st}', xy=(x + 0.003, y + 0.003), fontsize=self.pointsize / 4.,
fontweight='semibold', color=color, alpha=0.8,
transform=ccrs.PlateCarree(), zorder=14,
path_effects=[PathEffects.withStroke(
linewidth=self.pointsize / 15., foreground='k')]))
self.legend = self.canvas.axes.legend(loc=1, framealpha=1)
self.legend = self.ax.legend(loc=1, framealpha=1)
self.legend.set_zorder(100)
self.legend.get_frame().set_facecolor((1, 1, 1, 0.95))
def add_cbar(self, label):
self.cbax_bg = inset_axes(self.canvas.axes, width="6%", height="75%", loc=5)
cbax = inset_axes(self.canvas.axes, width='2%', height='70%', loc=5)
cbar = self.canvas.axes.figure.colorbar(self.sc_picked, cax=cbax)
self.cbax_bg = inset_axes(self.ax, width="6%", height="75%", loc=5)
cbax = inset_axes(self.ax, width='2%', height='70%', loc=5)
cbar = self.ax.figure.colorbar(self.sc_picked, cax=cbax)
cbar.set_label(label)
cbax.yaxis.tick_left()
cbax.yaxis.set_label_position('left')

View File

@ -22,14 +22,11 @@ class Event(ObsPyEvent):
:param path: path to event directory
:type path: str
"""
# TODO: remove rootpath and database
self.pylot_id = path.split('/')[-1]
# initialize super class
super(Event, self).__init__(resource_id=ResourceIdentifier('smi:local/' + self.pylot_id))
self.path = path
self.database = path.split('/')[-2]
self.datapath = os.path.split(path)[0] # path.split('/')[-3]
self.rootpath = '/' + os.path.join(*path.split('/')[:-3])
self.pylot_autopicks = {}
self.pylot_picks = {}
self.notes = ''

View File

@ -1084,8 +1084,9 @@ def check4rotated(data, metadata=None, verbosity=1):
azimuths.append(metadata.get_coordinates(tr_id, t_start)['azimuth'])
dips.append(metadata.get_coordinates(tr_id, t_start)['dip'])
except (KeyError, TypeError) as err:
logging.error(f"{type(err)=} occurred: {err=} Rotating not possible, not all azimuth and dip information "
f"available in metadata. Stream remains unchanged.")
logging.warning(f"Rotating not possible, not all azimuth and dip information "
f"available in metadata. Stream remains unchanged.")
logging.debug(f"Rotating not possible, {err=}, {type(err)=}")
return wfs_in
except Exception as err:
print(f"Unexpected {err=}, {type(err)=}")

View File

@ -8,6 +8,7 @@ import copy
import datetime
import getpass
import glob
import logging
import multiprocessing
import os
import subprocess
@ -3836,7 +3837,7 @@ class TuneAutopicker(QWidget):
self.stb_names = ['aicARHfig', 'refSpick', 'el_S1pick', 'el_S2pick']
def add_parameters(self):
self.paraBox = PylotParaBox(self.parameter, parent=self, windowflag=Qt.Widget)
self.paraBox = PylotParameterWidget(self.parameter, parent=self, windowflag=Qt.Widget)
self.paraBox.set_tune_mode(True)
self.update_eventID()
self.parameter_layout.addWidget(self.paraBox)
@ -4203,7 +4204,7 @@ class TuneAutopicker(QWidget):
self.qmb.show()
class PylotParaBox(QtWidgets.QWidget):
class PylotParameterWidget(QtWidgets.QWidget):
accepted = QtCore.Signal(str)
rejected = QtCore.Signal(str)
@ -4317,6 +4318,11 @@ class PylotParaBox(QtWidgets.QWidget):
grid = QtWidgets.QGridLayout()
for index1, name in enumerate(parameter_names):
if name in ['rootpath', 'database']:
logging.warning(
f'Deprecated parameter loaded: {name}. Check if datapath is still correct in parameter widget.'
)
continue
default_item = self.parameter.get_defaults()[name]
tooltip = default_item['tooltip']
tooltip += ' | type: {}'.format(default_item['type'])
@ -4886,7 +4892,7 @@ class PropTab(QWidget):
def getValues(self):
return None
def resetValues(self, infile=None):
def resetValues(self, infile):
return None
@ -4983,12 +4989,7 @@ class InputsTab(PropTab):
else:
index = 2
datapath = para.get('datapath') if not para.get('datapath') is None else ''
rootpath = para.get('rootpath') if not para.get('rootpath') is None else ''
database = para.get('database') if not para.get('database') is None else ''
if isinstance(database, int):
database = str(database)
path = os.path.join(os.path.expanduser('~'), rootpath, datapath, database)
values = {"data/dataRoot": self.dataDirEdit.setText("%s" % path),
values = {"data/dataRoot": self.dataDirEdit.setText("%s" % datapath),
"user/FullName": self.fullNameEdit.text(),
"data/Structure": self.structureSelect.setCurrentIndex(index),
"tstart": self.tstartBox.setValue(0),

View File

@ -4,10 +4,8 @@
%Parameters are optimized for %extent data sets!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#main settings#
/home/darius #rootpath# %project path
alparray #datapath# %data path
waveforms_used #database# %name of data base
e0093.173.16 #eventID# %event ID for single event processing (* for all events found in database)
/home/darius/alparray/waveforms_used #datapath# %data path
e0093.173.16 #eventID# %event ID for single event processing (* for all events found in datapath)
/home/darius/alparray/metadata #invdir# %full path to inventory or dataless-seed file
PILOT #datastructure# %choose data structure
True #apverbose# %choose 'True' or 'False' for terminal output

View File

@ -4,10 +4,8 @@
%Parameters are optimized for %extent data sets!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#main settings#
/home/darius #rootpath# %project path
alparray #datapath# %data path
waveforms_used #database# %name of data base
e0093.173.16 #eventID# %event ID for single event processing (* for all events found in database)
/home/darius/alparray/waveforms_used #datapath# %data path
e0093.173.16 #eventID# %event ID for single event processing (* for all events found in datapath)
/home/darius/alparray/metadata #invdir# %full path to inventory or dataless-seed file
PILOT #datastructure# %choose data structure
True #apverbose# %choose 'True' or 'False' for terminal output