Compare commits
5 Commits
78f2dbcab2
...
e1a0fde619
Author | SHA1 | Date | |
---|---|---|---|
e1a0fde619 | |||
48d196df11 | |||
6cc9cb4a96 | |||
5eab686445 | |||
b12e7937ac |
19
PyLoT.py
19
PyLoT.py
@ -76,7 +76,7 @@ from pylot.core.util.utils import fnConstructor, getLogin, \
|
|||||||
full_range, readFilterInformation, pick_color_plt, \
|
full_range, readFilterInformation, pick_color_plt, \
|
||||||
pick_linestyle_plt, identifyPhaseID, excludeQualityClasses, \
|
pick_linestyle_plt, identifyPhaseID, excludeQualityClasses, \
|
||||||
transform_colors_mpl, transform_colors_mpl_str, getAutoFilteroptions, check_all_obspy, \
|
transform_colors_mpl, transform_colors_mpl_str, getAutoFilteroptions, check_all_obspy, \
|
||||||
check_all_pylot, get_bool, get_None
|
check_all_pylot, get_bool, get_None, get_pylot_eventfile_with_extension
|
||||||
from pylot.core.util.gui import make_pen
|
from pylot.core.util.gui import make_pen
|
||||||
from pylot.core.util.event import Event
|
from pylot.core.util.event import Event
|
||||||
from pylot.core.io.location import create_creation_info, create_event
|
from pylot.core.io.location import create_creation_info, create_event
|
||||||
@ -84,7 +84,7 @@ from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \
|
|||||||
PylotCanvas, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \
|
PylotCanvas, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \
|
||||||
ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \
|
ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \
|
||||||
CompareEventsWidget, ProgressBarWidget, AddMetadataWidget, SingleTextLineDialog, LogWidget, PickQualitiesFromXml, \
|
CompareEventsWidget, ProgressBarWidget, AddMetadataWidget, SingleTextLineDialog, LogWidget, PickQualitiesFromXml, \
|
||||||
SourceSpecWindow, ChooseWaveFormWindow, SpectrogramTab
|
SourceSpecWindow, ChooseWaveFormWindow, SpectrogramTab, SearchFileByExtensionDialog
|
||||||
from pylot.core.util.array_map import Array_map
|
from pylot.core.util.array_map import Array_map
|
||||||
from pylot.core.util.structure import DATASTRUCTURE
|
from pylot.core.util.structure import DATASTRUCTURE
|
||||||
from pylot.core.util.thread import Thread, Worker
|
from pylot.core.util.thread import Thread, Worker
|
||||||
@ -1006,16 +1006,15 @@ class MainWindow(QMainWindow):
|
|||||||
return
|
return
|
||||||
refresh = False
|
refresh = False
|
||||||
events = self.project.eventlist
|
events = self.project.eventlist
|
||||||
sld = SingleTextLineDialog(label='Specify file extension: ', default_text='.xml')
|
sld = SearchFileByExtensionDialog(label='Specify file extension: ', default_text='.xml',
|
||||||
|
events=events)
|
||||||
if not sld.exec_():
|
if not sld.exec_():
|
||||||
return
|
return
|
||||||
fext = sld.lineEdit.text()
|
fext = sld.lineEdit.text()
|
||||||
# fext = '.xml'
|
# fext = '.xml'
|
||||||
for event in events:
|
for event in events:
|
||||||
path = event.path
|
filename = get_pylot_eventfile_with_extension(event, fext)
|
||||||
eventname = path.split('/')[-1] # or event.pylot_id
|
if filename:
|
||||||
filename = os.path.join(path, 'PyLoT_' + eventname + fext)
|
|
||||||
if os.path.isfile(filename):
|
|
||||||
self.load_data(filename, draw=False, event=event, overwrite=True)
|
self.load_data(filename, draw=False, event=event, overwrite=True)
|
||||||
refresh = True
|
refresh = True
|
||||||
if not refresh:
|
if not refresh:
|
||||||
@ -1887,6 +1886,7 @@ class MainWindow(QMainWindow):
|
|||||||
# which will read in data input twice. Therefore current tab is changed to 0
|
# which will read in data input twice. Therefore current tab is changed to 0
|
||||||
# in loadProject before calling this function.
|
# in loadProject before calling this function.
|
||||||
self.fill_eventbox()
|
self.fill_eventbox()
|
||||||
|
#print(f'{self.get_current_event()=}')
|
||||||
plotted = False
|
plotted = False
|
||||||
if self.tabs.currentIndex() == 2:
|
if self.tabs.currentIndex() == 2:
|
||||||
self.init_event_table()
|
self.init_event_table()
|
||||||
@ -1921,7 +1921,6 @@ class MainWindow(QMainWindow):
|
|||||||
self.spectro_layout.addWidget(newSpectroWidget)
|
self.spectro_layout.addWidget(newSpectroWidget)
|
||||||
self.spectroWidget = newSpectroWidget
|
self.spectroWidget = newSpectroWidget
|
||||||
|
|
||||||
|
|
||||||
def newWF(self, event=None, plot=True):
|
def newWF(self, event=None, plot=True):
|
||||||
'''
|
'''
|
||||||
Load new data and plot if necessary.
|
Load new data and plot if necessary.
|
||||||
@ -1972,6 +1971,8 @@ class MainWindow(QMainWindow):
|
|||||||
# ans = False
|
# ans = False
|
||||||
|
|
||||||
settings = QSettings()
|
settings = QSettings()
|
||||||
|
# process application events to wait for event items to appear in event box
|
||||||
|
QApplication.processEvents()
|
||||||
curr_event = self.get_current_event()
|
curr_event = self.get_current_event()
|
||||||
if not curr_event:
|
if not curr_event:
|
||||||
print('Could not find current event. Try reload?')
|
print('Could not find current event. Try reload?')
|
||||||
@ -3633,7 +3634,7 @@ class MainWindow(QMainWindow):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def update_status(self, message, duration=5000):
|
def update_status(self, message, duration=10000):
|
||||||
self.statusBar().showMessage(message, duration)
|
self.statusBar().showMessage(message, duration)
|
||||||
if self.get_data() is not None:
|
if self.get_data() is not None:
|
||||||
if not self.get_current_event() or not self.project.location:
|
if not self.get_current_event() or not self.project.location:
|
||||||
|
@ -13,6 +13,7 @@ import obspy
|
|||||||
from PySide2 import QtWidgets
|
from PySide2 import QtWidgets
|
||||||
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
||||||
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
|
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
|
||||||
|
from pylot.core.util.utils import identifyPhaseID
|
||||||
from scipy.interpolate import griddata
|
from scipy.interpolate import griddata
|
||||||
|
|
||||||
from pylot.core.pick.utils import get_quality_class
|
from pylot.core.pick.utils import get_quality_class
|
||||||
@ -279,9 +280,12 @@ class Array_map(QtWidgets.QWidget):
|
|||||||
self.canvas.axes.figure.canvas.draw_idle()
|
self.canvas.axes.figure.canvas.draw_idle()
|
||||||
|
|
||||||
def onpick(self, event):
|
def onpick(self, event):
|
||||||
|
btn_msg = {1: ' in selection. Aborted', 2: ' to delete a pick on. Aborted', 3: ' to display info.'}
|
||||||
ind = event.ind
|
ind = event.ind
|
||||||
button = event.mouseevent.button
|
button = event.mouseevent.button
|
||||||
if ind == []:
|
msg_reason = None
|
||||||
|
if len(ind) > 1:
|
||||||
|
self._parent.update_status(f'Found more than one station {btn_msg.get(button)}')
|
||||||
return
|
return
|
||||||
if button == 1:
|
if button == 1:
|
||||||
self.openPickDlg(ind)
|
self.openPickDlg(ind)
|
||||||
@ -384,7 +388,14 @@ class Array_map(QtWidgets.QWidget):
|
|||||||
try:
|
try:
|
||||||
station_name = st_id.split('.')[-1]
|
station_name = st_id.split('.')[-1]
|
||||||
# current_picks_dict: auto or manual
|
# current_picks_dict: auto or manual
|
||||||
pick = self.current_picks_dict()[station_name][phase]
|
station_picks = self.current_picks_dict().get(station_name)
|
||||||
|
if not station_picks:
|
||||||
|
continue
|
||||||
|
for phase_hint, pick in station_picks.items():
|
||||||
|
if identifyPhaseID(phase_hint) == phase:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
continue
|
||||||
if pick['picker'] == 'auto':
|
if pick['picker'] == 'auto':
|
||||||
if not pick['spe']:
|
if not pick['spe']:
|
||||||
continue
|
continue
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import glob
|
import glob
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -189,7 +190,11 @@ class Metadata(object):
|
|||||||
metadata = self.get_metadata(seed_id, time)
|
metadata = self.get_metadata(seed_id, time)
|
||||||
if not metadata:
|
if not metadata:
|
||||||
return
|
return
|
||||||
return metadata['data'].get_coordinates(seed_id, time)
|
try:
|
||||||
|
return metadata['data'].get_coordinates(seed_id, time)
|
||||||
|
# no specific exception defined in obspy inventory
|
||||||
|
except Exception as e:
|
||||||
|
logging.warning(f'Could not get metadata for {seed_id}')
|
||||||
|
|
||||||
def get_all_coordinates(self):
|
def get_all_coordinates(self):
|
||||||
def stat_info_from_parser(parser):
|
def stat_info_from_parser(parser):
|
||||||
|
@ -42,7 +42,7 @@ def main(project_file_path, manual=False, auto=True, file_format='png', f_ext=''
|
|||||||
for item in input_list:
|
for item in input_list:
|
||||||
array_map_worker(item)
|
array_map_worker(item)
|
||||||
else:
|
else:
|
||||||
pool = multiprocessing.Pool(ncores)
|
pool = multiprocessing.Pool(ncores, maxtasksperchild=1000)
|
||||||
pool.map(array_map_worker, input_list)
|
pool.map(array_map_worker, input_list)
|
||||||
pool.close()
|
pool.close()
|
||||||
pool.join()
|
pool.join()
|
||||||
|
@ -160,7 +160,7 @@ class MultiThread(QThread):
|
|||||||
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, maxtasksperchild=1000)
|
||||||
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()
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import re
|
import re
|
||||||
@ -119,7 +120,7 @@ def gen_Pool(ncores=0):
|
|||||||
|
|
||||||
print('gen_Pool: Generated multiprocessing Pool with {} cores\n'.format(ncores))
|
print('gen_Pool: Generated multiprocessing Pool with {} cores\n'.format(ncores))
|
||||||
|
|
||||||
pool = multiprocessing.Pool(ncores)
|
pool = multiprocessing.Pool(ncores, maxtasksperchild=100)
|
||||||
return pool
|
return pool
|
||||||
|
|
||||||
|
|
||||||
@ -899,6 +900,18 @@ def check_for_nan(data, nan_value=0.):
|
|||||||
np.nan_to_num(trace.data, copy=False, nan=nan_value)
|
np.nan_to_num(trace.data, copy=False, nan=nan_value)
|
||||||
|
|
||||||
|
|
||||||
|
def get_pylot_eventfile_with_extension(event, fext):
|
||||||
|
if hasattr(event, 'path'):
|
||||||
|
eventpath = event.path
|
||||||
|
else:
|
||||||
|
logging.warning('No attribute path found for event.')
|
||||||
|
return
|
||||||
|
eventname = eventpath.split('/')[-1] # or event.pylot_id
|
||||||
|
filename = os.path.join(eventpath, 'PyLoT_' + eventname + fext)
|
||||||
|
if os.path.isfile(filename):
|
||||||
|
return filename
|
||||||
|
|
||||||
|
|
||||||
def get_stations(data):
|
def get_stations(data):
|
||||||
"""
|
"""
|
||||||
Get list of all station names in data stream
|
Get list of all station names in data stream
|
||||||
|
@ -36,7 +36,7 @@ from PySide2.QtWidgets import QAction, QApplication, QCheckBox, QComboBox, \
|
|||||||
QGridLayout, QLabel, QLineEdit, QMessageBox, \
|
QGridLayout, QLabel, QLineEdit, QMessageBox, \
|
||||||
QTabWidget, QToolBar, QVBoxLayout, QHBoxLayout, QWidget, \
|
QTabWidget, QToolBar, QVBoxLayout, QHBoxLayout, QWidget, \
|
||||||
QPushButton, QFileDialog, QInputDialog
|
QPushButton, QFileDialog, QInputDialog
|
||||||
from PySide2.QtCore import QSettings, Qt, QUrl, Signal
|
from PySide2.QtCore import QSettings, Qt, QUrl, Signal, QTimer
|
||||||
from PySide2.QtWebEngineWidgets import QWebEngineView as QWebView
|
from PySide2.QtWebEngineWidgets import QWebEngineView as QWebView
|
||||||
from obspy import Stream, Trace, UTCDateTime
|
from obspy import Stream, Trace, UTCDateTime
|
||||||
from obspy.core.util import AttribDict
|
from obspy.core.util import AttribDict
|
||||||
@ -54,7 +54,7 @@ from pylot.core.util.utils import prepTimeAxis, full_range, demeanTrace, isSorte
|
|||||||
check4rotated, check4doubled, check_for_gaps_and_merge, check_for_nan, identifyPhase, \
|
check4rotated, check4doubled, check_for_gaps_and_merge, check_for_nan, identifyPhase, \
|
||||||
loopIdentifyPhase, trim_station_components, transformFilteroptions2String, \
|
loopIdentifyPhase, trim_station_components, transformFilteroptions2String, \
|
||||||
identifyPhaseID, get_bool, get_None, pick_color, getAutoFilteroptions, SetChannelComponents, \
|
identifyPhaseID, get_bool, get_None, pick_color, getAutoFilteroptions, SetChannelComponents, \
|
||||||
station_id_remove_channel
|
station_id_remove_channel, get_pylot_eventfile_with_extension
|
||||||
from autoPyLoT import autoPyLoT
|
from autoPyLoT import autoPyLoT
|
||||||
from pylot.core.util.thread import Thread
|
from pylot.core.util.thread import Thread
|
||||||
from pylot.core.util.dataprocessing import Metadata
|
from pylot.core.util.dataprocessing import Metadata
|
||||||
@ -1568,6 +1568,96 @@ class PylotCanvas(FigureCanvas):
|
|||||||
self.draw()
|
self.draw()
|
||||||
|
|
||||||
|
|
||||||
|
class SearchFileByExtensionDialog(QtWidgets.QDialog):
|
||||||
|
def __init__(self, parent=None, label='Text: ', default_text='.xml', events=None):
|
||||||
|
super(SearchFileByExtensionDialog, self).__init__(parent)
|
||||||
|
self.events = events
|
||||||
|
self.filepaths = []
|
||||||
|
self.default_text = default_text
|
||||||
|
self.label = label
|
||||||
|
self.setButtons()
|
||||||
|
self.setupUi()
|
||||||
|
self.connectSignals()
|
||||||
|
self.showPaths()
|
||||||
|
self.refresh_timer = QTimer(self)
|
||||||
|
self.refresh_timer.timeout.connect(self.showPaths)
|
||||||
|
self.refresh_timer.start(10000)
|
||||||
|
|
||||||
|
self.resize(800, 450)
|
||||||
|
|
||||||
|
|
||||||
|
def setupUi(self):
|
||||||
|
self.main_layout = QtWidgets.QVBoxLayout()
|
||||||
|
self.header_layout = QtWidgets.QHBoxLayout()
|
||||||
|
#
|
||||||
|
self.setLayout(self.main_layout)
|
||||||
|
|
||||||
|
# widgets inside the dialog
|
||||||
|
self.textLabel = QtWidgets.QLabel(self.label)
|
||||||
|
self.lineEdit = QtWidgets.QLineEdit(self.default_text)
|
||||||
|
|
||||||
|
# optional search button, currently disabled. List refreshed when text changes
|
||||||
|
self.searchButton = QtWidgets.QPushButton('Search')
|
||||||
|
self.searchButton.setVisible(False)
|
||||||
|
|
||||||
|
self.tableWidget = QtWidgets.QTableWidget()
|
||||||
|
tableWidget = self.tableWidget
|
||||||
|
tableWidget.setColumnCount(2)
|
||||||
|
tableWidget.setRowCount(len(self.events))
|
||||||
|
tableWidget.setHorizontalHeaderLabels(('Filename', 'Last modified'))
|
||||||
|
tableWidget.setEditTriggers(tableWidget.NoEditTriggers)
|
||||||
|
tableWidget.setSortingEnabled(True)
|
||||||
|
header = tableWidget.horizontalHeader()
|
||||||
|
header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
|
||||||
|
header.setStretchLastSection(True)
|
||||||
|
|
||||||
|
self.statusText = QtWidgets.QLabel()
|
||||||
|
|
||||||
|
self.header_layout.addWidget(self.textLabel)
|
||||||
|
self.header_layout.addWidget(self.lineEdit)
|
||||||
|
self.header_layout.addWidget(self.searchButton)
|
||||||
|
|
||||||
|
self.main_layout.addLayout(self.header_layout)
|
||||||
|
self.main_layout.addWidget(self.tableWidget)
|
||||||
|
self.main_layout.addWidget(self.statusText)
|
||||||
|
self.main_layout.addWidget(self._buttonbox)
|
||||||
|
|
||||||
|
def showPaths(self):
|
||||||
|
self.filepaths = []
|
||||||
|
fext = self.lineEdit.text()
|
||||||
|
self.tableWidget.clearContents()
|
||||||
|
for index, event in enumerate(self.events):
|
||||||
|
filename = get_pylot_eventfile_with_extension(event, fext)
|
||||||
|
if filename:
|
||||||
|
self.filepaths.append(filename)
|
||||||
|
ts = int(os.path.getmtime(filename))
|
||||||
|
|
||||||
|
# create QTableWidgetItems of filepath and last modification time
|
||||||
|
fname_item = QtWidgets.QTableWidgetItem(f'{filename}')
|
||||||
|
ts_item = QtWidgets.QTableWidgetItem(f'{datetime.datetime.fromtimestamp(ts)}')
|
||||||
|
self.tableWidget.setItem(index, 0, fname_item)
|
||||||
|
self.tableWidget.setItem(index, 1, ts_item)
|
||||||
|
|
||||||
|
# TODO: Idea -> only refresh if table contents changed. Use selection to load only a subset of files
|
||||||
|
if len(self.filepaths) > 0:
|
||||||
|
status_text = f'Found {len(self.filepaths)} eventfiles. Do you want to load them?'
|
||||||
|
else:
|
||||||
|
status_text = 'Did not find any files for specified file mask.'
|
||||||
|
self.statusText.setText(status_text)
|
||||||
|
|
||||||
|
|
||||||
|
def setButtons(self):
|
||||||
|
self._buttonbox = QDialogButtonBox(QDialogButtonBox.Ok |
|
||||||
|
QDialogButtonBox.Cancel)
|
||||||
|
|
||||||
|
def connectSignals(self):
|
||||||
|
self._buttonbox.accepted.connect(self.accept)
|
||||||
|
self._buttonbox.rejected.connect(self.reject)
|
||||||
|
self.lineEdit.textChanged.connect(self.showPaths)
|
||||||
|
self.searchButton.clicked.connect(self.showPaths)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SingleTextLineDialog(QtWidgets.QDialog):
|
class SingleTextLineDialog(QtWidgets.QDialog):
|
||||||
def __init__(self, parent=None, label='Text: ', default_text='.xml'):
|
def __init__(self, parent=None, label='Text: ', default_text='.xml'):
|
||||||
super(SingleTextLineDialog, self).__init__(parent)
|
super(SingleTextLineDialog, self).__init__(parent)
|
||||||
|
Loading…
Reference in New Issue
Block a user