WIP: Simplify data structure #39
11
PyLoT.py
11
PyLoT.py
@ -1011,13 +1011,12 @@ class MainWindow(QMainWindow):
|
||||
events=events)
|
||||
if not sld.exec_():
|
||||
return
|
||||
fext = sld.comboBox.currentText()
|
||||
# fext = '.xml'
|
||||
filenames = sld.getChecked()
|
||||
for event in events:
|
||||
filename = get_pylot_eventfile_with_extension(event, fext)
|
||||
if filename:
|
||||
self.load_data(filename, draw=False, event=event, overwrite=True)
|
||||
refresh = True
|
||||
for filename in filenames:
|
||||
if os.path.isfile(filename) and event.pylot_id in filename:
|
||||
self.load_data(filename, draw=False, event=event, overwrite=True)
|
||||
refresh = True
|
||||
if not refresh:
|
||||
return
|
||||
if self.get_current_event().pylot_picks:
|
||||
|
@ -7,6 +7,7 @@ Created on Wed Mar 19 11:27:35 2014
|
||||
import copy
|
||||
import datetime
|
||||
import getpass
|
||||
import glob
|
||||
import multiprocessing
|
||||
import os
|
||||
import subprocess
|
||||
@ -16,6 +17,7 @@ import traceback
|
||||
|
||||
import matplotlib
|
||||
import numpy as np
|
||||
from pylot.core.io.phases import getQualitiesfromxml
|
||||
|
||||
matplotlib.use('QT5Agg')
|
||||
|
||||
@ -860,13 +862,26 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
def clearPlotDict(self):
|
||||
self.plotdict = dict()
|
||||
|
||||
def plotWFData(self, wfdata, wfsyn=None, title=None, zoomx=None, zoomy=None,
|
||||
noiselevel=None, scaleddata=False, mapping=True,
|
||||
component='*', nth_sample=1, iniPick=None, verbosity=0,
|
||||
method='normal', gain=1.):
|
||||
def plotWFData(self, wfdata, wfsyn=None, title=None, scaleddata=False, mapping=True,
|
||||
component='*', nth_sample=1, verbosity=0, method='normal', gain=1., shift_syn=0.2):
|
||||
def station_sort(nslc):
|
||||
"""Try to sort after station integer in case of a line array (e.g. active seismics)"""
|
||||
try:
|
||||
rval = sorted(nslc, key=lambda x: int(x.split('.')[1]))
|
||||
return rval
|
||||
except ValueError as e:
|
||||
# this is the standard case for seismological stations
|
||||
pass
|
||||
except Exception as e:
|
||||
print(f'Sorting by station integer failed with unknown exception: {e}')
|
||||
|
||||
# fallback to default sorting
|
||||
return sorted(nslc)
|
||||
|
||||
if not wfdata:
|
||||
print('Nothing to plot.')
|
||||
return
|
||||
|
||||
self.title = title
|
||||
self.clearPlotDict()
|
||||
self.wfstart, self.wfend = full_range(wfdata)
|
||||
@ -884,14 +899,14 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
else:
|
||||
st_select = wfdata
|
||||
|
||||
st_select, gaps = merge_stream(st_select)
|
||||
# st_select, gaps = check_for_gaps_and_merge(st_select) #MP MP commented because probably done twice
|
||||
|
||||
# list containing tuples of network, station, channel (for sorting)
|
||||
nslc = []
|
||||
for trace in st_select:
|
||||
nslc.append(
|
||||
trace.get_id()) # (trace.stats.network, trace.stats.station, trace.stats.location trace.stats.channel))
|
||||
nslc.sort()
|
||||
nslc = station_sort(nslc)
|
||||
nslc.reverse()
|
||||
plots = []
|
||||
|
||||
@ -955,7 +970,7 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
self.ylabel = ''
|
||||
self.setXLims([0, self.wfend - self.wfstart])
|
||||
self.setYLims([0.5, nmax + 0.5])
|
||||
return plots, gaps
|
||||
return plots
|
||||
|
||||
def minMax(self, trace, time_ax):
|
||||
'''
|
||||
@ -977,7 +992,7 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
min_ = data.min(axis=1)
|
||||
max_ = data.max(axis=1)
|
||||
if remaining_samples:
|
||||
extreme_values = np.empty((npixel + 1, 2), dtype=np.float)
|
||||
extreme_values = np.empty((npixel + 1, 2), dtype=float)
|
||||
extreme_values[:-1, 0] = min_
|
||||
extreme_values[:-1, 1] = max_
|
||||
extreme_values[-1, 0] = \
|
||||
@ -985,7 +1000,7 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
extreme_values[-1, 1] = \
|
||||
trace.data[-remaining_samples:].max()
|
||||
else:
|
||||
extreme_values = np.empty((npixel, 2), dtype=np.float)
|
||||
extreme_values = np.empty((npixel, 2), dtype=float)
|
||||
extreme_values[:, 0] = min_
|
||||
extreme_values[:, 1] = max_
|
||||
data = extreme_values.flatten()
|
||||
@ -1555,6 +1570,160 @@ class PylotCanvas(FigureCanvas):
|
||||
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.file_extensions = []
|
||||
self.check_all_state = True
|
||||
self.default_text = default_text
|
||||
self.label = label
|
||||
self.setButtons()
|
||||
self.setupUi()
|
||||
self.connectSignals()
|
||||
self.showPaths()
|
||||
self.refreshSelectionBox()
|
||||
# self.refresh_timer = QTimer(self)
|
||||
# self.refresh_timer.timeout.connect(self.showPaths)
|
||||
# self.refresh_timer.start(10000)
|
||||
|
||||
self.resize(800, 450)
|
||||
|
||||
def setupUi(self):
|
||||
ncol = 4
|
||||
self.main_layout = QtWidgets.QVBoxLayout()
|
||||
self.header_layout = QtWidgets.QHBoxLayout()
|
||||
self.footer_layout = QtWidgets.QHBoxLayout()
|
||||
#
|
||||
self.setLayout(self.main_layout)
|
||||
|
||||
# widgets inside the dialog
|
||||
self.textLabel = QtWidgets.QLabel(self.label)
|
||||
self.comboBox = QtWidgets.QComboBox()
|
||||
self.comboBox.addItem(self.default_text)
|
||||
self.comboBox.setEditable(True)
|
||||
|
||||
# optional search button, currently disabled. List refreshed when text changes
|
||||
self.searchButton = QtWidgets.QPushButton('Search')
|
||||
self.searchButton.setVisible(False)
|
||||
|
||||
# check/uncheck button for table
|
||||
self.checkAllButton = QtWidgets.QPushButton('Check/Uncheck all')
|
||||
|
||||
# table
|
||||
self.tableWidget = QtWidgets.QTableWidget()
|
||||
tableWidget = self.tableWidget
|
||||
tableWidget.setColumnCount(ncol)
|
||||
tableWidget.setRowCount(len(self.events))
|
||||
tableWidget.setHorizontalHeaderLabels(('', 'Event ID', '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.comboBox)
|
||||
self.header_layout.addWidget(self.searchButton)
|
||||
|
||||
self.footer_layout.addWidget(self.checkAllButton)
|
||||
self.footer_layout.addWidget(self.statusText)
|
||||
self.footer_layout.setStretch(0, 0)
|
||||
|
||||
self.main_layout.addLayout(self.header_layout)
|
||||
self.main_layout.addWidget(self.tableWidget)
|
||||
self.main_layout.addLayout(self.footer_layout)
|
||||
self.main_layout.addWidget(self._buttonbox)
|
||||
|
||||
def showPaths(self):
|
||||
self.filepaths = []
|
||||
fext = self.comboBox.currentText()
|
||||
self.tableWidget.clearContents()
|
||||
for index, event in enumerate(self.events):
|
||||
filename = get_pylot_eventfile_with_extension(event, fext)
|
||||
pf_selected_item = QtWidgets.QTableWidgetItem()
|
||||
if filename:
|
||||
pf_selected_item.setCheckState(QtCore.Qt.Checked)
|
||||
#check_state = QtCore.Qt.Checked if filename else QtCore.Qt.Unchecked
|
||||
#pf_selected_item.setCheckState(check_state)
|
||||
self.tableWidget.setItem(index, 0, pf_selected_item)
|
||||
self.tableWidget.setItem(index, 1, QtWidgets.QTableWidgetItem(f'{event.pylot_id}'))
|
||||
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'{os.path.split(filename)[-1]}')
|
||||
fname_item.setData(3, filename)
|
||||
ts_item = QtWidgets.QTableWidgetItem(f'{datetime.datetime.fromtimestamp(ts)}')
|
||||
self.tableWidget.setItem(index, 2, fname_item)
|
||||
self.tableWidget.setItem(index, 3, ts_item)
|
||||
|
||||
self.update_status()
|
||||
|
||||
def refreshSelectionBox(self):
|
||||
fext = self.comboBox.currentText()
|
||||
self.file_extensions = [fext]
|
||||
|
||||
for event in self.events:
|
||||
extensions = get_possible_pylot_eventfile_extensions(event, '*.xml')
|
||||
for ext in extensions:
|
||||
if not ext in self.file_extensions:
|
||||
self.file_extensions.append(ext)
|
||||
|
||||
self.comboBox.clear()
|
||||
for ext in sorted(self.file_extensions):
|
||||
self.comboBox.addItem(ext)
|
||||
|
||||
def setButtons(self):
|
||||
self._buttonbox = QDialogButtonBox(QDialogButtonBox.Ok |
|
||||
QDialogButtonBox.Cancel)
|
||||
|
||||
def toggleCheckAll(self):
|
||||
self.check_all_state = not self.check_all_state
|
||||
self.checkAll(self.check_all_state)
|
||||
|
||||
def checkAll(self, state):
|
||||
state = QtCore.Qt.Checked if state else QtCore.Qt.Unchecked
|
||||
for row_ind in range(self.tableWidget.rowCount()):
|
||||
item = self.tableWidget.item(row_ind, 0)
|
||||
item.setCheckState(state)
|
||||
|
||||
def getChecked(self):
|
||||
filepaths = []
|
||||
for row_ind in range(self.tableWidget.rowCount()):
|
||||
item_check = self.tableWidget.item(row_ind, 0)
|
||||
if item_check.checkState() == QtCore.Qt.Checked:
|
||||
item_fname = self.tableWidget.item(row_ind, 2)
|
||||
filepath = item_fname.data(3)
|
||||
filepaths.append(filepath)
|
||||
return filepaths
|
||||
|
||||
def update_status(self, row=None, col=None):
|
||||
if col is not None and col != 0:
|
||||
return
|
||||
filepaths = self.getChecked()
|
||||
if len(filepaths) > 0:
|
||||
status_text = f'Found {len(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 connectSignals(self):
|
||||
self._buttonbox.accepted.connect(self.accept)
|
||||
self._buttonbox.rejected.connect(self.reject)
|
||||
self.comboBox.editTextChanged.connect(self.showPaths)
|
||||
self.searchButton.clicked.connect(self.showPaths)
|
||||
self.checkAllButton.clicked.connect(self.toggleCheckAll)
|
||||
self.checkAllButton.clicked.connect(self.update_status)
|
||||
self.tableWidget.cellClicked.connect(self.update_status)
|
||||
|
||||
|
||||
|
||||
class SingleTextLineDialog(QtWidgets.QDialog):
|
||||
def __init__(self, parent=None, label='Text: ', default_text='.xml'):
|
||||
super(SingleTextLineDialog, self).__init__(parent)
|
||||
@ -1786,7 +1955,7 @@ class PickDlg(QDialog):
|
||||
|
||||
# init expected picks using obspy Taup
|
||||
try:
|
||||
if self.metadata and model is not None:
|
||||
if self.metadata and model != "None":
|
||||
self.model = TauPyModel(model)
|
||||
self.get_arrivals()
|
||||
self.drawArrivals()
|
||||
@ -2146,7 +2315,7 @@ class PickDlg(QDialog):
|
||||
|
||||
# create action and add to menu
|
||||
# phase name transferred using lambda function
|
||||
slot = lambda phase=phase, phaseID=phaseID: phaseSelect[phaseID](phase)
|
||||
slot = lambda ph=phase, phID=phaseID: phaseSelect[phID](ph)
|
||||
picksAction = createAction(parent=self, text=phase,
|
||||
slot=slot,
|
||||
shortcut=shortcut)
|
||||
@ -2513,7 +2682,9 @@ class PickDlg(QDialog):
|
||||
data.normalize()
|
||||
if not data:
|
||||
QtWidgets.QMessageBox.warning(self, 'No channel to plot',
|
||||
'No channel to plot for phase: {}.'.format(phase))
|
||||
'No channel to plot for phase: {}. '
|
||||
'Make sure to select the correct channels for P and S '
|
||||
'in the menu in the top panel.'.format(phase))
|
||||
self.leave_picking_mode()
|
||||
return
|
||||
|
||||
@ -2653,7 +2824,7 @@ class PickDlg(QDialog):
|
||||
minFMSNR = parameter.get('minFMSNR')
|
||||
quality = get_quality_class(spe, parameter.get('timeerrorsP'))
|
||||
if quality <= minFMweight and snr >= minFMSNR:
|
||||
FM = fmpicker(self.getWFData().select(channel=channel), wfdata, parameter.get('fmpickwin'),
|
||||
FM = fmpicker(self.getWFData().select(channel=channel).copy(), wfdata.copy(), parameter.get('fmpickwin'),
|
||||
pick - stime_diff)
|
||||
|
||||
# save pick times for actual phase
|
||||
@ -3566,8 +3737,9 @@ class TuneAutopicker(QWidget):
|
||||
# wfdat = remove_underscores(wfdat)
|
||||
# rotate misaligned stations to ZNE
|
||||
# check for gaps and doubled channels
|
||||
wfdat, gaps = merge_stream(wfdat)
|
||||
# check4gaps(wfdat)
|
||||
wfdat, _ = check_for_gaps_and_merge(wfdat)
|
||||
# check for nans
|
||||
check_for_nan(wfdat)
|
||||
check4doubled(wfdat)
|
||||
wfdat = check4rotated(wfdat, self.parent().metadata, verbosity=0)
|
||||
# trim station components to same start value
|
||||
@ -3611,14 +3783,14 @@ class TuneAutopicker(QWidget):
|
||||
self.listWidget.scrollToBottom()
|
||||
|
||||
def get_current_event(self):
|
||||
path = self.eventBox.currentText()
|
||||
path = self.get_current_event_fp()
|
||||
return self.parent().project.getEventFromPath(path)
|
||||
|
||||
def get_current_event_name(self):
|
||||
return self.eventBox.currentText().split('/')[-1].split('*')[0]
|
||||
return self.eventBox.currentText().split('/')[-1].rstrip('*')
|
||||
|
||||
def get_current_event_fp(self):
|
||||
return self.eventBox.currentText().split('*')[0]
|
||||
return self.eventBox.currentText().rstrip('*')
|
||||
|
||||
def get_current_event_picks(self, station):
|
||||
event = self.get_current_event()
|
||||
@ -3722,6 +3894,7 @@ class TuneAutopicker(QWidget):
|
||||
st = self.data.getWFData()
|
||||
tr = st.select(station=self.get_current_station())[0]
|
||||
starttime = tr.stats.starttime
|
||||
# create two lists with figure names and subindices (for subplots) to get the correct axes
|
||||
p_axes = [
|
||||
('mainFig', 0),
|
||||
('aicFig', 0),
|
||||
@ -5663,9 +5836,23 @@ class ChooseWaveFormWindow(QWidget):
|
||||
def submit(self):
|
||||
matplotlib.pyplot.close(self.currentSpectro)
|
||||
t = self.chooseBoxTraces.currentText() + " " + self.chooseBoxComponent.currentText()
|
||||
self.currentSpectro = self.traces[
|
||||
self.chooseBoxTraces.currentText()[3:]][self.chooseBoxComponent.currentText()].spectrogram(show=False, title=t)
|
||||
self.currentSpectro.show()
|
||||
#self.currentSpectro = self.traces[
|
||||
# self.chooseBoxTraces.currentText()[3:]][self.chooseBoxComponent.currentText()].spectrogram(show=False, title=t)
|
||||
#self.currentSpectro.show()
|
||||
self.applyFFT()
|
||||
|
||||
def applyFFT(self, trace):
|
||||
tra = self.traces[self.chooseBoxTraces.currentText()[3:]]['Z']
|
||||
transformed = abs(np.fft.rfft(tra.data))
|
||||
print ( transformed )
|
||||
matplotlib.pyplot.plot ( transformed )
|
||||
matplotlib.pyplot.show()
|
||||
|
||||
def applyFFTs(self, tra):
|
||||
transformed = abs(np.fft.rfft(tra.data))
|
||||
print ( transformed )
|
||||
matplotlib.pyplot.plot ( transformed )
|
||||
matplotlib.pyplot.show()
|
||||
|
||||
def submitN(self):
|
||||
matplotlib.pyplot.close(self.currentSpectro)
|
||||
@ -5681,13 +5868,6 @@ class ChooseWaveFormWindow(QWidget):
|
||||
self.chooseBoxTraces.currentText()[3:]]['E'].spectrogram(show=False, title=t)
|
||||
self.currentSpectro.show()
|
||||
|
||||
def submitZ(self):
|
||||
matplotlib.pyplot.close(self.currentSpectro)
|
||||
t = self.chooseBoxTraces.currentText() + " " + self.chooseBoxComponent.currentText()
|
||||
self.currentSpectro = self.traces[
|
||||
self.chooseBoxTraces.currentText()[3:]]['Z'].spectrogram(show=False, title=t)
|
||||
self.currentSpectro.show()
|
||||
|
||||
# Creates a QComboBox and adds all traces provided
|
||||
def createComboBoxTraces(self):
|
||||
if len(self.wFs) <= 0:
|
||||
@ -5714,7 +5894,87 @@ class ChooseWaveFormWindow(QWidget):
|
||||
pass
|
||||
|
||||
|
||||
class SpectrogramTab(QWidget):
|
||||
def __init__(self, traces, wfdata, parent=None):
|
||||
super(SpectrogramTab, self).__init__(parent)
|
||||
self.setupUi()
|
||||
self.traces = traces
|
||||
self.wfdata = wfdata
|
||||
|
||||
def setupUi(self):
|
||||
pass
|
||||
def makeSpecFig(self, direction = 'Z', height = 0, width = 0, parent = None):
|
||||
|
||||
i = 0
|
||||
grams = []
|
||||
figure, axis = matplotlib.pyplot.subplots(len(self.traces), sharex=True)
|
||||
|
||||
start, end = full_range(self.wfdata)
|
||||
|
||||
if height != 0 and width != 0:
|
||||
figure.figsize = (width, height)
|
||||
figure.set_figwidth = width
|
||||
figure.set_figheight = height
|
||||
|
||||
#figure.tight_layout()
|
||||
|
||||
for t in self.traces:
|
||||
tra = self.traces[t][direction]
|
||||
#print(start, end)
|
||||
|
||||
# Set Title
|
||||
if i == 0:
|
||||
if direction == 'Z':
|
||||
figure.suptitle("section: vertical components")
|
||||
elif direction == 'E':
|
||||
figure.suptitle("section: east-west components")
|
||||
elif direction == 'N':
|
||||
figure.suptitle("section: north-south components")
|
||||
axis[i].vlines(0, axis[i].get_ylim()[0], axis[i].get_ylim()[1],
|
||||
colors='m', linestyles='dashed',
|
||||
linewidth=2)
|
||||
|
||||
# Different axis settings for visual improvements
|
||||
# axis[i].set_xlim(left=0, right=end - start)
|
||||
# axis[i].spines['top'].set_visible(False)
|
||||
# axis[i].spines['right'].set_visible(False)
|
||||
# # axis[i].spines['left'].set_visible(False)
|
||||
|
||||
# axis[i].tick_params(axis='x', which='both', bottom=False, top=False, labelbottom=False)
|
||||
# if not (len(self.traces) == i - 1):
|
||||
# axis[i].spines['bottom'].set_visible(False)
|
||||
# axis[i].set_yticks([])
|
||||
# axis[i].set_ylabel(t, loc='center', rotation='horizontal')
|
||||
|
||||
#ax.axhline(n, color="0.5", lw=0.5)
|
||||
|
||||
|
||||
grams.append(tra.spectrogram(show=False, axes=axis[i]))
|
||||
i+=1
|
||||
|
||||
#figure.setXLims([0, end - start])
|
||||
figure.set_tight_layout(True)
|
||||
fC = FigureCanvas(figure)
|
||||
return fC
|
||||
|
||||
#for t in self.traces:
|
||||
# tra = self.traces[t]['Z']
|
||||
# transformed = abs(np.fft.rfft(tra.data))
|
||||
# axis[i].plot(transformed, label=t)
|
||||
# # axis[i].tick_params(labelbottom=False)
|
||||
# axis[i].spines['top'].set_visible(False)
|
||||
# axis[i].spines['right'].set_visible(False)
|
||||
# axis[i].spines['left'].set_visible(False)
|
||||
# if not (len(self.traces) == i - 1):
|
||||
# axis[i].spines['bottom'].set_visible(False)
|
||||
# axis[i].set_yticks([])
|
||||
# axis[i].set_ylabel(t, loc='center', rotation='horizontal')
|
||||
# # axis[i].axis('off')
|
||||
# i += 1
|
||||
# # self.applyFFTs(t)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
||||
doctest.testmod()
|
||||
|
Loading…
Reference in New Issue
Block a user