Compare commits
18 Commits
feature/da
...
341db86861
| Author | SHA1 | Date | |
|---|---|---|---|
| 341db86861 | |||
| b5ba62e86f | |||
| 21f4567236 | |||
| 553b935d69 | |||
| 0bdfd96659 | |||
| 79fac36cf5 | |||
| adc3304840 | |||
|
|
417316a8bb | ||
| 889e632198 | |||
| 543f12f1a2 | |||
| 2c2eca37e3 | |||
| 55810b9926 | |||
| 8b4eed3974 | |||
| 710ea57503 | |||
| 8aaad643ec | |||
| bc808b66c2 | |||
| 472e5b3b9e | |||
|
|
503ea419c4 |
40
README.md
40
README.md
@@ -66,27 +66,41 @@ PyLoT has been tested on Mac OSX (10.11), Debian Linux 8 and on Windows 10.
|
|||||||
|
|
||||||
#### Features:
|
#### Features:
|
||||||
|
|
||||||
- event organisation in project files and waveform visualisation
|
- centralize all functionalities of PyLoT and control them from within the main GUI
|
||||||
- consistent manual phase picking through predefined SNR dependant zoom level
|
- handling multiple events inside GUI with project files (save and load work progress)
|
||||||
- consistent automatic phase picking routines using Higher Order Statistics, AIC and Autoregression
|
- GUI based adjustments of pick parameters and I/O
|
||||||
- interactive tuning of auto-pick parameters
|
- interactive tuning of parameters from within the GUI
|
||||||
- uniform uncertainty estimation from waveform's properties for automatic and manual picks
|
- call automatic picking algorithm from within the GUI
|
||||||
- pdf representation and comparison of picks taking the uncertainty intrinsically into account
|
- comparison of automatic with manual picks for multiple events using clear differentiation of manual picks into 'tune' and 'test-set' (beta)
|
||||||
- Richter and moment magnitude estimation
|
- manual picking of different (user defined) phase types
|
||||||
- location determination with external installation of [NonLinLoc](http://alomax.free.fr/nlloc/index.html)
|
- phase onset estimation with ObsPy TauPy
|
||||||
|
- interactive zoom/scale functionalities in all plots (mousewheel, pan, pan-zoom)
|
||||||
|
- array map to visualize stations and control onsets (beta feature, switch to manual picks not implemented)
|
||||||
|
|
||||||
#### Known issues:
|
##### Platform support:
|
||||||
|
- Python 3 support
|
||||||
|
- Windows support
|
||||||
|
|
||||||
- Sometimes an error might occur when using Qt
|
##### Performance:
|
||||||
|
- multiprocessing for automatic picking and restitution of multiple stations
|
||||||
|
- use pyqtgraph library for better performance on main waveform plot
|
||||||
|
|
||||||
We hope to solve these with the next release.
|
##### Visualization:
|
||||||
|
- pick uncertainty (quality classes) visualization with gradients
|
||||||
|
- pick color unification for all plots
|
||||||
|
- new icons and stylesheets
|
||||||
|
|
||||||
|
#### Known Issues:
|
||||||
|
- some Qt related errors might occur at runtime
|
||||||
|
- filter toggle not working in pickDlg
|
||||||
|
- PyLoT data structure requires at least three parent directories for waveform data directory
|
||||||
|
|
||||||
## Staff
|
## Staff
|
||||||
|
|
||||||
Original author(s): L. Kueperkoch, S. Wehling-Benatelli, M. Bischoff (PILOT)
|
Original author(s): L. Kueperkoch, S. Wehling-Benatelli, M. Bischoff (PILOT)
|
||||||
|
|
||||||
Developer(s): S. Wehling-Benatelli, L. Kueperkoch, K. Olbert, M. Bischoff,
|
Developer(s): S. Wehling-Benatelli, L. Kueperkoch, M. Paffrath, K. Olbert,
|
||||||
C. Wollin, M. Rische, M. Paffrath
|
M. Bischoff, C. Wollin, M. Rische
|
||||||
|
|
||||||
Others: A. Bruestle, T. Meier, W. Friederich
|
Others: A. Bruestle, T. Meier, W. Friederich
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import pylot.core.loc.hypodd as hypodd
|
|||||||
import pylot.core.loc.hyposat as hyposat
|
import pylot.core.loc.hyposat as hyposat
|
||||||
import pylot.core.loc.nll as nll
|
import pylot.core.loc.nll as nll
|
||||||
import pylot.core.loc.velest as velest
|
import pylot.core.loc.velest as velest
|
||||||
# from PySide.QtGui import QWidget, QInputDialog
|
# from PySide2.QtWidgets import QWidget, QInputDialog
|
||||||
from pylot.core.analysis.magnitude import MomentMagnitude, LocalMagnitude
|
from pylot.core.analysis.magnitude import MomentMagnitude, LocalMagnitude
|
||||||
from pylot.core.io.data import Data
|
from pylot.core.io.data import Data
|
||||||
from pylot.core.io.inputs import PylotParameter
|
from pylot.core.io.inputs import PylotParameter
|
||||||
|
|||||||
4580
icons_rc_3.py
4580
icons_rc_3.py
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ from obspy.core import read, Stream, UTCDateTime
|
|||||||
from obspy.core.event import Event as ObsPyEvent
|
from obspy.core.event import Event as ObsPyEvent
|
||||||
from obspy.io.sac import SacIOError
|
from obspy.io.sac import SacIOError
|
||||||
|
|
||||||
from PySide.QtGui import QMessageBox
|
from PySide2.QtWidgets import QMessageBox
|
||||||
|
|
||||||
import pylot.core.loc.velest as velest
|
import pylot.core.loc.velest as velest
|
||||||
import pylot.core.loc.focmec as focmec
|
import pylot.core.loc.focmec as focmec
|
||||||
@@ -26,9 +26,9 @@ class Data(object):
|
|||||||
"""
|
"""
|
||||||
Data container with attributes wfdata holding ~obspy.core.stream.
|
Data container with attributes wfdata holding ~obspy.core.stream.
|
||||||
|
|
||||||
:type parent: PySide.QtGui.QWidget object, optional
|
:type parent: PySide2.QtWidgets.QWidget object, optional
|
||||||
:param parent: A PySide.QtGui.QWidget object utilized when
|
:param parent: A PySide2.QtWidgets.QWidget object utilized when
|
||||||
called by a GUI to display a PySide.QtGui.QMessageBox instead of printing
|
called by a GUI to display a PySide2.QtWidgets.QMessageBox instead of printing
|
||||||
to standard out.
|
to standard out.
|
||||||
:type evtdata: ~obspy.core.event.Event object, optional
|
:type evtdata: ~obspy.core.event.Event object, optional
|
||||||
:param evtdata ~obspy.core.event.Event object containing all derived or
|
:param evtdata ~obspy.core.event.Event object containing all derived or
|
||||||
@@ -128,7 +128,7 @@ class Data(object):
|
|||||||
|
|
||||||
def getParent(self):
|
def getParent(self):
|
||||||
"""
|
"""
|
||||||
Get PySide.QtGui.QWidget parent object
|
Get PySide2.QtWidgets.QWidget parent object
|
||||||
"""
|
"""
|
||||||
return self._parent
|
return self._parent
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ import matplotlib.pyplot as plt
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import obspy
|
import obspy
|
||||||
import traceback
|
import traceback
|
||||||
from PySide import QtGui
|
from PySide2 import QtWidgets
|
||||||
from matplotlib.figure import Figure
|
from matplotlib.figure import Figure
|
||||||
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
|
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
|
||||||
from mpl_toolkits.basemap import Basemap
|
from mpl_toolkits.basemap import Basemap
|
||||||
@@ -18,7 +18,7 @@ from pylot.core.pick.utils import get_quality_class
|
|||||||
plt.interactive(False)
|
plt.interactive(False)
|
||||||
|
|
||||||
|
|
||||||
class Array_map(QtGui.QWidget):
|
class Array_map(QtWidgets.QWidget):
|
||||||
def __init__(self, parent, metadata, parameter=None, figure=None, annotate=True, pointsize=25.,
|
def __init__(self, parent, metadata, parameter=None, figure=None, annotate=True, pointsize=25.,
|
||||||
linewidth=1.5, width=5e6, height=2e6):
|
linewidth=1.5, width=5e6, height=2e6):
|
||||||
'''
|
'''
|
||||||
@@ -27,7 +27,7 @@ class Array_map(QtGui.QWidget):
|
|||||||
:param parameter: object of PyLoT parameter class
|
:param parameter: object of PyLoT parameter class
|
||||||
:param figure:
|
:param figure:
|
||||||
'''
|
'''
|
||||||
QtGui.QWidget.__init__(self)
|
QtWidgets.QWidget.__init__(self)
|
||||||
assert (parameter != None or parent != None), 'either parent or parameter has to be set'
|
assert (parameter != None or parent != None), 'either parent or parameter has to be set'
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
self.metadata = metadata
|
self.metadata = metadata
|
||||||
@@ -224,43 +224,43 @@ class Array_map(QtGui.QWidget):
|
|||||||
if not self.figure:
|
if not self.figure:
|
||||||
self.figure = Figure()
|
self.figure = Figure()
|
||||||
|
|
||||||
self.status_label = QtGui.QLabel()
|
self.status_label = QtWidgets.QLabel()
|
||||||
|
|
||||||
self.main_ax = self.figure.add_subplot(111)
|
self.main_ax = self.figure.add_subplot(111)
|
||||||
#self.main_ax.set_facecolor('0.7')
|
#self.main_ax.set_facecolor('0.7')
|
||||||
self.canvas = PylotCanvas(self.figure, parent=self._parent, multicursor=True,
|
self.canvas = PylotCanvas(self.figure, parent=self._parent, multicursor=True,
|
||||||
panZoomX=False, panZoomY=False)
|
panZoomX=False, panZoomY=False)
|
||||||
|
|
||||||
self.main_box = QtGui.QVBoxLayout()
|
self.main_box = QtWidgets.QVBoxLayout()
|
||||||
self.setLayout(self.main_box)
|
self.setLayout(self.main_box)
|
||||||
|
|
||||||
self.top_row = QtGui.QHBoxLayout()
|
self.top_row = QtWidgets.QHBoxLayout()
|
||||||
self.main_box.addLayout(self.top_row, 1)
|
self.main_box.addLayout(self.top_row, 1)
|
||||||
|
|
||||||
self.comboBox_phase = QtGui.QComboBox()
|
self.comboBox_phase = QtWidgets.QComboBox()
|
||||||
self.comboBox_phase.insertItem(0, 'P')
|
self.comboBox_phase.insertItem(0, 'P')
|
||||||
self.comboBox_phase.insertItem(1, 'S')
|
self.comboBox_phase.insertItem(1, 'S')
|
||||||
|
|
||||||
self.comboBox_am = QtGui.QComboBox()
|
self.comboBox_am = QtWidgets.QComboBox()
|
||||||
self.comboBox_am.insertItem(0, 'hybrid (prefer manual)')
|
self.comboBox_am.insertItem(0, 'hybrid (prefer manual)')
|
||||||
self.comboBox_am.insertItem(1, 'manual')
|
self.comboBox_am.insertItem(1, 'manual')
|
||||||
self.comboBox_am.insertItem(2, 'auto')
|
self.comboBox_am.insertItem(2, 'auto')
|
||||||
|
|
||||||
self.annotations_box = QtGui.QCheckBox('Annotate')
|
self.annotations_box = QtWidgets.QCheckBox('Annotate')
|
||||||
self.annotations_box.setChecked(True)
|
self.annotations_box.setChecked(True)
|
||||||
self.auto_refresh_box = QtGui.QCheckBox('Automatic refresh')
|
self.auto_refresh_box = QtWidgets.QCheckBox('Automatic refresh')
|
||||||
self.auto_refresh_box.setChecked(True)
|
self.auto_refresh_box.setChecked(True)
|
||||||
self.refresh_button = QtGui.QPushButton('Refresh')
|
self.refresh_button = QtWidgets.QPushButton('Refresh')
|
||||||
self.cmaps_box = QtGui.QComboBox()
|
self.cmaps_box = QtWidgets.QComboBox()
|
||||||
self.cmaps_box.setMaxVisibleItems(20)
|
self.cmaps_box.setMaxVisibleItems(20)
|
||||||
[self.cmaps_box.addItem(map_name) for map_name in sorted(plt.colormaps())]
|
[self.cmaps_box.addItem(map_name) for map_name in sorted(plt.colormaps())]
|
||||||
# try to set to hsv as default
|
# try to set to hsv as default
|
||||||
self.cmaps_box.setCurrentIndex(self.cmaps_box.findText('hsv'))
|
self.cmaps_box.setCurrentIndex(self.cmaps_box.findText('hsv'))
|
||||||
|
|
||||||
self.top_row.addWidget(QtGui.QLabel('Select a phase: '))
|
self.top_row.addWidget(QtWidgets.QLabel('Select a phase: '))
|
||||||
self.top_row.addWidget(self.comboBox_phase)
|
self.top_row.addWidget(self.comboBox_phase)
|
||||||
self.top_row.setStretch(1, 1) # set stretch of item 1 to 1
|
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(QtWidgets.QLabel('Pick type: '))
|
||||||
self.top_row.addWidget(self.comboBox_am)
|
self.top_row.addWidget(self.comboBox_am)
|
||||||
self.top_row.setStretch(3, 1) # set stretch of item 1 to 1
|
self.top_row.setStretch(3, 1) # set stretch of item 1 to 1
|
||||||
self.top_row.addWidget(self.cmaps_box)
|
self.top_row.addWidget(self.cmaps_box)
|
||||||
@@ -633,6 +633,6 @@ class Array_map(QtGui.QWidget):
|
|||||||
map.ax.figure.canvas.draw()
|
map.ax.figure.canvas.draw()
|
||||||
|
|
||||||
def _warn(self, message):
|
def _warn(self, message):
|
||||||
self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning,
|
self.qmb = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Icon.Warning,
|
||||||
'Warning', message)
|
'Warning', message)
|
||||||
self.qmb.show()
|
self.qmb.show()
|
||||||
|
|||||||
364
pylot/core/util/map_projection.py
Normal file
364
pylot/core/util/map_projection.py
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
import obspy
|
||||||
|
from PySide2 import QtWidgets
|
||||||
|
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
|
||||||
|
import cartopy
|
||||||
|
import cartopy.feature as cpf
|
||||||
|
from pylot.core.util.widgets import PickDlg
|
||||||
|
from scipy.interpolate import griddata
|
||||||
|
|
||||||
|
plt.interactive(False)
|
||||||
|
|
||||||
|
|
||||||
|
class map_projection(QtWidgets.QWidget):
|
||||||
|
def __init__(self, parent, figure=None):
|
||||||
|
'''
|
||||||
|
|
||||||
|
:param: picked, can be False, auto, manual
|
||||||
|
:value: str
|
||||||
|
'''
|
||||||
|
QtWidgets.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()
|
||||||
|
self.init_map()
|
||||||
|
# self.show()
|
||||||
|
|
||||||
|
def init_map(self):
|
||||||
|
self.init_lat_lon_dimensions()
|
||||||
|
self.init_lat_lon_grid()
|
||||||
|
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.main_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 = QtWidgets.QVBoxLayout()
|
||||||
|
self.setLayout(self.main_box)
|
||||||
|
|
||||||
|
self.top_row = QtWidgets.QHBoxLayout()
|
||||||
|
self.main_box.addLayout(self.top_row)
|
||||||
|
|
||||||
|
self.comboBox_phase = QtWidgets.QComboBox()
|
||||||
|
self.comboBox_phase.insertItem(0, 'P')
|
||||||
|
self.comboBox_phase.insertItem(1, 'S')
|
||||||
|
|
||||||
|
self.comboBox_am = QtWidgets.QComboBox()
|
||||||
|
self.comboBox_am.insertItem(0, 'auto')
|
||||||
|
self.comboBox_am.insertItem(1, 'manual')
|
||||||
|
|
||||||
|
self.top_row.addWidget(QtWidgets.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_basemap(self, resolution='l'):
|
||||||
|
ax = self.main_ax(projection=cartopy.crs.PlateCarree())
|
||||||
|
|
||||||
|
ax.add_feature(cpf.LAND)
|
||||||
|
ax.add_feature(cpf.OCEAN)
|
||||||
|
ax.add_feature(cpf.COASTLINE)
|
||||||
|
ax.add_feature(cpf.BORDERS, linestyle=':')
|
||||||
|
ax.add_feature(cpf.LAKES, alpha=0.5)
|
||||||
|
ax.add_feature(cpf.RIVERS)
|
||||||
|
|
||||||
|
ax.set_extent([min(self.lon), max(self.lon), min(self.lat), max(self.lat)])
|
||||||
|
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.main_ax.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.main_ax.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.main_ax.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.main_ax.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.main_ax.scatter(lon[1], lat[1], s=50, facecolor='white',
|
||||||
|
c=self.picks_no_nan[1], latlon=True, zorder=11)
|
||||||
|
else:
|
||||||
|
self.sc_picked = self.main_ax.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.main_ax
|
||||||
|
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 = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Icon.Warning,
|
||||||
|
'Warning', message)
|
||||||
|
self.qmb.show()
|
||||||
@@ -1,11 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import sys, os, traceback
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
from PySide2.QtCore import QThread, Signal, Qt, Slot, QRunnable, QObject
|
||||||
import sys
|
from PySide2.QtWidgets import QDialog, QProgressBar, QLabel, QHBoxLayout, QPushButton
|
||||||
import traceback
|
|
||||||
|
|
||||||
from PySide.QtCore import QThread, Signal, Qt, Slot, QRunnable, QObject
|
|
||||||
from PySide.QtGui import QDialog, QProgressBar, QLabel, QHBoxLayout
|
|
||||||
|
|
||||||
|
|
||||||
class Thread(QThread):
|
class Thread(QThread):
|
||||||
@@ -27,7 +24,7 @@ class Thread(QThread):
|
|||||||
if self.redirect_stdout:
|
if self.redirect_stdout:
|
||||||
sys.stdout = self
|
sys.stdout = self
|
||||||
try:
|
try:
|
||||||
if self.arg is not None:
|
if self.arg:
|
||||||
self.data = self.func(self.arg)
|
self.data = self.func(self.arg)
|
||||||
else:
|
else:
|
||||||
self.data = self.func()
|
self.data = self.func()
|
||||||
@@ -36,20 +33,31 @@ class Thread(QThread):
|
|||||||
self._executed = False
|
self._executed = False
|
||||||
self._executedError = e
|
self._executedError = e
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
exctype, value = sys.exc_info()[:2]
|
exctype, value = sys.exc_info ()[:2]
|
||||||
self._executedErrorInfo = '{} {} {}'. \
|
self._executedErrorInfo = '{} {} {}'.\
|
||||||
format(exctype, value, traceback.format_exc())
|
format(exctype, value, traceback.format_exc())
|
||||||
sys.stdout = sys.__stdout__
|
sys.stdout = sys.__stdout__
|
||||||
|
|
||||||
def showProgressbar(self):
|
def showProgressbar(self):
|
||||||
if self.progressText:
|
if self.progressText:
|
||||||
# # generate widget if not given in init
|
|
||||||
# if not self.pb_widget:
|
|
||||||
# self.pb_widget = ProgressBarWidget(self.parent())
|
|
||||||
# self.pb_widget.setWindowFlags(Qt.SplashScreen)
|
|
||||||
# self.pb_widget.setModal(True)
|
|
||||||
|
|
||||||
self.pb_widget.label.setText(self.progressText)
|
# generate widget if not given in init
|
||||||
|
if not self.pb_widget:
|
||||||
|
self.pb_widget = QDialog(self.parent())
|
||||||
|
self.pb_widget.setWindowFlags(Qt.SplashScreen)
|
||||||
|
self.pb_widget.setModal(True)
|
||||||
|
|
||||||
|
# add button
|
||||||
|
delete_button = QPushButton('X')
|
||||||
|
delete_button.clicked.connect(self.exit)
|
||||||
|
hl = QHBoxLayout()
|
||||||
|
pb = QProgressBar()
|
||||||
|
pb.setRange(0, 0)
|
||||||
|
hl.addWidget(pb)
|
||||||
|
hl.addWidget(QLabel(self.progressText))
|
||||||
|
if self.abortButton:
|
||||||
|
hl.addWidget(delete_button)
|
||||||
|
self.pb_widget.setLayout(hl)
|
||||||
self.pb_widget.show()
|
self.pb_widget.show()
|
||||||
|
|
||||||
def hideProgressbar(self):
|
def hideProgressbar(self):
|
||||||
@@ -67,7 +75,6 @@ class Worker(QRunnable):
|
|||||||
'''
|
'''
|
||||||
Worker class to be run by MultiThread(QThread).
|
Worker class to be run by MultiThread(QThread).
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self, fun, args,
|
def __init__(self, fun, args,
|
||||||
progressText=None,
|
progressText=None,
|
||||||
pb_widget=None,
|
pb_widget=None,
|
||||||
@@ -75,7 +82,7 @@ class Worker(QRunnable):
|
|||||||
super(Worker, self).__init__()
|
super(Worker, self).__init__()
|
||||||
self.fun = fun
|
self.fun = fun
|
||||||
self.args = args
|
self.args = args
|
||||||
# self.kwargs = kwargs
|
#self.kwargs = kwargs
|
||||||
self.signals = WorkerSignals()
|
self.signals = WorkerSignals()
|
||||||
self.progressText = progressText
|
self.progressText = progressText
|
||||||
self.pb_widget = pb_widget
|
self.pb_widget = pb_widget
|
||||||
@@ -89,9 +96,9 @@ class Worker(QRunnable):
|
|||||||
try:
|
try:
|
||||||
result = self.fun(self.args)
|
result = self.fun(self.args)
|
||||||
except:
|
except:
|
||||||
exctype, value = sys.exc_info()[:2]
|
exctype, value = sys.exc_info ()[:2]
|
||||||
print(exctype, value, traceback.format_exc())
|
print(exctype, value, traceback.format_exc())
|
||||||
self.signals.error.emit((exctype, value, traceback.format_exc()))
|
self.signals.error.emit ((exctype, value, traceback.format_exc ()))
|
||||||
else:
|
else:
|
||||||
self.signals.result.emit(result)
|
self.signals.result.emit(result)
|
||||||
finally:
|
finally:
|
||||||
@@ -133,13 +140,13 @@ class MultiThread(QThread):
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.redirect_stdout:
|
if self.redirect_stdout:
|
||||||
sys.stdout = self
|
sys.stdout = self
|
||||||
try:
|
try:
|
||||||
if not self.ncores:
|
if not self.ncores:
|
||||||
self.ncores = multiprocessing.cpu_count()
|
self.ncores = multiprocessing.cpu_count()
|
||||||
pool = multiprocessing.Pool(self.ncores)
|
pool = multiprocessing.Pool(self.ncores)
|
||||||
self.data = pool.map_async(self.func, self.args, callback=self.emitDone)
|
self.data = pool.map_async(self.func, self.args, callback=self.emitDone)
|
||||||
# self.data = pool.apply_async(self.func, self.shotlist, callback=self.emitDone) #emit each time returned
|
#self.data = pool.apply_async(self.func, self.shotlist, callback=self.emitDone) #emit each time returned
|
||||||
pool.close()
|
pool.close()
|
||||||
self._executed = True
|
self._executed = True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user