# -*- coding: utf-8 -*- """ Created on Wed Mar 19 11:27:35 2014 @author: sebastianw """ import os import getpass import warnings import copy import datetime import numpy as np from matplotlib.figure import Figure from pylot.core.util.utils import find_horizontals try: from matplotlib.backends.backend_qt4agg import FigureCanvas except ImportError: from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT from matplotlib.widgets import MultiCursor from PySide import QtCore, QtGui from PySide.QtGui import QAction, QApplication, QCheckBox, QComboBox, \ QDateTimeEdit, QDialog, QDialogButtonBox, QDoubleSpinBox, QGroupBox, \ QGridLayout, QIcon, QKeySequence, QLabel, QLineEdit, QMessageBox, \ QPixmap, QSpinBox, QTabWidget, QToolBar, QVBoxLayout, QWidget, \ QPushButton, QFileDialog, QInputDialog, QKeySequence from PySide.QtCore import QSettings, Qt, QUrl, Signal, Slot from PySide.QtWebKit import QWebView from obspy import Stream, UTCDateTime from pylot.core.io.data import Data from pylot.core.io.inputs import FilterOptions, AutoPickParameter from pylot.core.pick.utils import getSNR, earllatepicker, getnoisewin, \ getResolutionWindow from pylot.core.pick.compare import Comparison from pylot.core.util.defaults import OUTPUTFORMATS, FILTERDEFAULTS, LOCTOOLS, \ COMPPOSITION_MAP from pylot.core.util.utils import prepTimeAxis, full_range, scaleWFData, \ demeanTrace, isSorted, findComboBoxIndex, clims from autoPyLoT import autoPyLoT from pylot.core.util.thread import Thread import icons_rc def getDataType(parent): type = QInputDialog().getItem(parent, "Select phases type", "Type:", ["manual", "automatic"]) if type[0].startswith('auto'): type = 'auto' else: type = type[0] return type def plot_pdf(_axes, x, y, annotation, bbox_props, xlabel=None, ylabel=None, title=None): # try method or data try: _axes.plot(x, y()) # y provided as method except: _axes.plot(x, y) # y provided as data if title: _axes.set_title(title) if xlabel: _axes.set_xlabel(xlabel) if ylabel: _axes.set_ylabel(ylabel) _anno = _axes.annotate(annotation, xy=(.05, .5), xycoords='axes fraction') _anno.set_bbox(bbox_props) return _axes def createAction(parent, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False): """ :rtype : ~PySide.QtGui.QAction """ action = QAction(text, parent) if icon is not None: action.setIcon(icon) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) if slot is not None: action.triggered.connect(slot) if checkable: action.setCheckable(True) return action class ComparisonDialog(QDialog): def __init__(self, c, parent=None): self._data = c self._stats = c.stations self._canvas = PlotWidget(self) self._widgets = dict(stationsComboBox=None, phasesComboBox=None, histCheckBox=None) self._phases = 'PS' self._plotprops = dict(station=self.stations[0], phase=self.phases[0]) super(ComparisonDialog, self).__init__(parent) self.setupUI() self.plotcomparison() def setupUI(self): _outerlayout = QVBoxLayout(self) _innerlayout = QVBoxLayout() _stats_combobox = QComboBox(self) _stats_combobox.setObjectName('stationsComboBox') _stats_combobox.setEditable(True) _stats_combobox.setInsertPolicy(QComboBox.NoInsert) _stats_combobox.addItems(sorted(self.stations)) _stats_combobox.editTextChanged.connect(self.prepareplot) self.widgets = _stats_combobox _phases_combobox = QComboBox(self) _phases_combobox.setObjectName('phasesComboBox') _phases_combobox.addItems(['P', 'S']) _phases_combobox.currentIndexChanged.connect(self.prepareplot) self.widgets = _phases_combobox _hist_checkbox = QCheckBox('Show histograms', self) _hist_checkbox.setObjectName('histCheckBox') _hist_checkbox.stateChanged.connect(self.plothist) self.widgets = _hist_checkbox _toolbar = QToolBar(self) _toolbar.addWidget(_stats_combobox) _toolbar.addWidget(_phases_combobox) _toolbar.addWidget(_hist_checkbox) _buttonbox = QDialogButtonBox(QDialogButtonBox.Close) _innerlayout.addWidget(self.canvas) _innerlayout.addWidget(_buttonbox) _outerlayout.addWidget(_toolbar) _outerlayout.addLayout(_innerlayout) _buttonbox.rejected.connect(self.reject) # finally layout the entire dialog self.setLayout(_outerlayout) @property def canvas(self): return self._canvas @canvas.setter def canvas(self, canvas_obj): self._canvas = canvas_obj @property def stations(self): return self._stats @stations.setter def stations(self, stations): self._stats = stations @property def phases(self): return self._phases @phases.setter def phases(self, value): self._phases = value @property def plotprops(self): return self._plotprops @plotprops.setter def plotprops(self, values): try: key, value = values if key not in self.plotprops.keys(): raise KeyError("'key' {0} not found in " "ComparisonDialog.plotprops keys.".format(key)) except ValueError: raise ValueError("Pass an iterable with two items") else: self._plotprops[key] = value @property def data(self): return self._data @data.setter def data(self, data): assert not isinstance(data, Comparison) self.stations = data.stations self._data = data @property def widgets(self): return self._widgets @widgets.setter def widgets(self, widget): name = widget.objectName() if name in self.widgets.keys(): self._widgets[name] = widget def clf(self): self.canvas.figure.clf() def hasvalue(self, sender): text = sender.currentText() index = sender.findText(text.upper()) return index def prepareplot(self): try: _widget = self.sender() name = _widget.objectName() text = _widget.currentText().upper() index = self.hasvalue(_widget) if name == 'stationsComboBox' and index is not -1: _widget.setCurrentIndex(index) self.plotprops = ('station', text) elif name == 'phasesComboBox': self.plotprops = ('phase', text) except ValueError: raise ValueError('No sender widget given!') finally: self.plotcomparison() def plotcomparison(self): from matplotlib import gridspec _gs = gridspec.GridSpec(3, 2) self.clf() _axes = self.canvas.figure.add_subplot(_gs[0:2, :]) _ax1 = self.canvas.figure.add_subplot(_gs[2, 0]) _ax2 = self.canvas.figure.add_subplot(_gs[2, 1]) #_axes.cla() station = self.plotprops['station'] phase = self.plotprops['phase'] pdf = self.data.comparison[station][phase] x, y, std, exp = pdf.axis, pdf.data, pdf.standard_deviation(), \ pdf.expectation() annotation = "%s difference on %s\n" \ "expectation: %7.4f s\n" \ "std: %7.4f s" % (phase, station, exp, std) bbox_props = dict(boxstyle='round', facecolor='lightgrey', alpha=.7) plot_pdf(_axes, x, y, annotation, bbox_props, 'time difference [s]', 'propability density [-]', phase) pdf_a = copy.deepcopy(self.data.get('auto')[station][phase]) pdf_m = copy.deepcopy(self.data.get('manu')[station][phase]) xauto, yauto, stdauto, expauto, alim = pdf_a.axis, pdf_a.data(), \ pdf_a.standard_deviation(), \ pdf_a.expectation(), \ pdf_a.limits() xmanu, ymanu, stdmanu, expmanu, mlim = pdf_m.axis, pdf_m.data(), \ pdf_m.standard_deviation(), \ pdf_m.expectation(), \ pdf_m.limits() # find common limits lims = clims(alim, mlim) # relative x axis x0 = lims[0] xmanu -= x0 xauto -= x0 lims = [lim - x0 for lim in lims] x0 = UTCDateTime(x0) # set annotation text mannotation = "probability density of manual pick\n" \ "expectation: %7.4f s\n" \ "std: %7.4f s" % (expmanu-x0.timestamp, stdmanu) aannotation = "probability density of automatic pick\n" \ "expectation: %7.4f s\n" \ "std: %7.4f s" % (expauto-x0.timestamp, stdauto) _ax1 = plot_pdf(_ax1, xmanu, ymanu, mannotation, bbox_props=bbox_props, xlabel='seconds since ' '{0}'.format(x0), ylabel='probability density [-]') _ax1.set_xlim(lims) _ax2 = plot_pdf(_ax2, xauto, yauto, aannotation, bbox_props=bbox_props, xlabel='seconds since ' '{0}'.format(x0)) _ax2.set_xlim(lims) _gs.update(wspace=0.5, hspace=0.5) self.canvas.draw() def plothist(self): name = self.sender().objectName() if self.widgets[name].isChecked(): for wname, widget in self.widgets.items(): if wname != name: self.widgets[wname].setEnabled(False) self.canvas.figure.clf() _axPstd, _axPexp = self.canvas.figure.add_subplot(221), self.canvas.figure.add_subplot(223) _axSstd, _axSexp = self.canvas.figure.add_subplot(222), self.canvas.figure.add_subplot(224) axes_dict = dict(P=dict(std=_axPstd, exp=_axPexp), S=dict(std=_axSstd, exp=_axSexp)) bbox_props = dict(boxstyle='round', facecolor='lightgrey', alpha=.7) for phase in self.phases: std = self.data.get_std_array(phase) std = std[np.isfinite(std)] stdxlims = [0., 1.2 * max(std)] exp = self.data.get_expectation_array(phase) exp = exp[np.isfinite(exp)] eps_exp = 0.05 * (max(exp) - min(exp)) expxlims = [min(exp) - eps_exp, max(exp) + eps_exp] axes_dict[phase]['std'].hist(std, range=stdxlims, bins=20, normed=False) axes_dict[phase]['exp'].hist(exp, range=expxlims, bins=20, normed=False) std_annotation = "Distribution curve for {phase} differences'\n" \ "standard deviations (all stations)\n" \ "number of samples: {nsamples}".format(phase=phase, nsamples=len(std)) _anno_std = axes_dict[phase]['std'].annotate(std_annotation, xy=(.05, .8), xycoords='axes fraction') _anno_std.set_bbox(bbox_props) exp_annotation = "Distribution curve for {phase} differences'\n" \ "expectations (all stations)\n" \ "number of samples: {nsamples}".format(phase=phase, nsamples=len(exp)) _anno_exp = axes_dict[phase]['exp'].annotate(exp_annotation, xy=(.05, .8), xycoords='axes fraction') _anno_exp.set_bbox(bbox_props) axes_dict[phase]['exp'].set_xlabel('expectation [s]') axes_dict[phase]['std'].set_xlabel('standard deviation [s]') for ax in axes_dict['P'].values(): ax.set_ylabel('frequency [-]') self.canvas.draw() else: for wname, widget in self.widgets.items(): if wname != name: self.widgets[wname].setEnabled(True) self.canvas.figure.clf() self.plotcomparison() class PlotWidget(FigureCanvas): def __init__(self, parent=None, xlabel='x', ylabel='y', title='Title'): self._parent = parent self._fig = Figure() self._xl = xlabel self._yl = ylabel self._title = title super(PlotWidget, self).__init__(self.figure) @property def figure(self): return self._fig @figure.setter def figure(self, fig): self._fig = fig @property def xlabel(self): return self._xl @xlabel.setter def xlabel(self, label): self._xl = label @property def ylabel(self): return self._yl @ylabel.setter def ylabel(self, label): self._yl = label @property def title(self): return self._title @title.setter def title(self, title): self._title = title @property def parent(self): return self._parent class WaveformWidget(FigureCanvas): def __init__(self, parent=None, xlabel='x', ylabel='y', title='Title'): self._parent = None self.setParent(parent) self.figure = Figure() self.figure.set_facecolor((.92, .92, .92)) # attribute plotdict is a dictionary connecting position and a name self.plotdict = dict() # create axes self.axes = self.figure.add_subplot(111) # clear axes each time plot is called self.axes.hold(True) # initialize super class super(WaveformWidget, self).__init__(self.figure) # add an cursor for station selection self.multiCursor = MultiCursor(self.figure.canvas, (self.axes,), horizOn=True, color='m', lw=1) # update labels of the entire widget self.updateWidget(xlabel, ylabel, title) def getPlotDict(self): return self.plotdict def setPlotDict(self, key, value): self.plotdict[key] = value def clearPlotDict(self): self.plotdict = dict() def getParent(self): return self._parent def setParent(self, parent): self._parent = parent def plotWFData(self, wfdata, title=None, zoomx=None, zoomy=None, noiselevel=None, scaleddata=False, mapping=True): self.getAxes().cla() self.clearPlotDict() wfstart, wfend = full_range(wfdata) nmax = 0 for n, trace in enumerate(wfdata): channel = trace.stats.channel station = trace.stats.station if mapping: comp = channel[-1] n = COMPPOSITION_MAP[comp] if n > nmax: nmax = n msg = 'plotting %s channel of station %s' % (channel, station) print(msg) stime = trace.stats.starttime - wfstart time_ax = prepTimeAxis(stime, trace) if time_ax is not None: if not scaleddata: trace.detrend('constant') trace.normalize(np.max(np.abs(trace.data)) * 2) self.getAxes().plot(time_ax, trace.data + n, 'k') if noiselevel is not None: for level in noiselevel: self.getAxes().plot([time_ax[0], time_ax[-1]], [level, level], '--k') self.setPlotDict(n, (station, channel)) xlabel = 'seconds since {0}'.format(wfstart) ylabel = '' self.updateWidget(xlabel, ylabel, title) self.setXLims([0, wfend - wfstart]) self.setYLims([-0.5, nmax + 0.5]) if zoomx is not None: self.setXLims(zoomx) if zoomy is not None: self.setYLims(zoomy) self.draw() def getAxes(self): return self.axes def getXLims(self): return self.getAxes().get_xlim() def getYLims(self): return self.getAxes().get_ylim() def setXLims(self, lims): self.getAxes().set_xlim(lims) def setYLims(self, lims): self.getAxes().set_ylim(lims) def setYTickLabels(self, pos, labels): self.getAxes().set_yticks(pos) self.getAxes().set_yticklabels(labels) self.draw() def updateXLabel(self, text): self.getAxes().set_xlabel(text) self.draw() def updateYLabel(self, text): self.getAxes().set_ylabel(text) self.draw() def updateTitle(self, text): self.getAxes().set_title(text) self.draw() def updateWidget(self, xlabel, ylabel, title): self.updateXLabel(xlabel) self.updateYLabel(ylabel) self.updateTitle(title) def insertLabel(self, pos, text): pos = pos / max(self.getAxes().ylim) axann = self.getAxes().annotate(text, xy=(.03, pos), xycoords='axes fraction') axann.set_bbox(dict(facecolor='lightgrey', alpha=.6)) class PickDlg(QDialog): update_picks = QtCore.Signal(dict) def __init__(self, parent=None, data=None, station=None, picks=None, autopicks=None, rotate=False, parameter=None, embedded=False): super(PickDlg, self).__init__(parent) # initialize attributes self.parameter = parameter self._embedded = embedded self.station = station self.rotate = rotate self.components = 'ZNE' self.currentPhase = None settings = QSettings() pylot_user = getpass.getuser() self._user = settings.value('user/Login', pylot_user) if picks: self.picks = picks self._init_picks = copy.deepcopy(picks) else: self.picks = {} self._init_picks = {} if autopicks: self.autopicks = autopicks self._init_autopicks = copy.deepcopy(autopicks) else: self.autopicks = {} self._init_autopicks = {} self.filteroptions = FILTERDEFAULTS self.pick_block = False # initialize panning attributes self.press = None self.xpress = None self.ypress = None self.cur_xlim = None self.cur_ylim = None # set attribute holding data if data is None: try: data = parent.get_data().getWFData().copy() self.data = data.select(station=station) except AttributeError as e: errmsg = 'You either have to put in a data or an appropriate ' \ 'parent (PyLoT MainWindow) object: {0}'.format(e) raise Exception(errmsg) else: self.data = data self.stime, self.etime = full_range(self.getWFData()) # initialize plotting widget self.multicompfig = WaveformWidget(self) # setup ui self.setupUi() # plot data self.getPlotWidget().plotWFData(wfdata=self.getWFData(), title=self.getStation()) xlims = self.getPlotWidget().getXLims() ylims = self.getPlotWidget().getYLims() self.limits = {'x': xlims, 'y': ylims} self.updateCurrentLimits() # set plot labels self.setPlotLabels() # draw picks if present self.drawAllPicks() # connect button press event to an action self.cidpress = self.connectPressEvent(self.panPress) self.cidmotion = self.connectMotionEvent(self.panMotion) self.cidrelease = self.connectReleaseEvent(self.panRelease) self.cidscroll = self.connectScrollEvent(self.scrollZoom) def setupUi(self): # create matplotlib toolbar to inherit functionality self.figToolBar = NavigationToolbar2QT(self.getPlotWidget(), self) self.figToolBar.hide() # create icons filter_icon = QIcon() filter_icon.addPixmap(QPixmap(':/icons/filter.png')) zoom_icon = QIcon() zoom_icon.addPixmap(QPixmap(':/icons/zoom_in.png')) home_icon = QIcon() home_icon.addPixmap(QPixmap(':/icons/zoom_0.png')) del_icon = QIcon() del_icon.addPixmap(QPixmap(':/icons/delete.png')) # create actions self.filterAction = createAction(parent=self, text='Filter', slot=self.filterWFData, icon=filter_icon, tip='Toggle filtered/original' ' waveforms') self.zoomAction = createAction(parent=self, text='Zoom', slot=self.zoom, icon=zoom_icon, tip='Zoom into waveform', checkable=True) self.resetZoomAction = createAction(parent=self, text='Home', slot=self.resetZoom, icon=home_icon, tip='Reset zoom to original limits') self.resetPicksAction = createAction(parent=self, text='Delete Picks', slot=self.delPicks, icon=del_icon, tip='Delete current picks.') # create other widget elements phaseitems = [None] + FILTERDEFAULTS.keys() # create buttons for P and S filter and picking self.p_button = QPushButton('P', self) self.s_button = QPushButton('S', self) self.p_button.setCheckable(True) self.s_button.setCheckable(True) # button shortcuts (1 for P-button, 2 for S-button) self.p_button.setShortcut(QKeySequence('1')) self.s_button.setShortcut(QKeySequence('2')) # set button tooltips self.p_button.setToolTip('Hotkey: "1"') self.s_button.setToolTip('Hotkey: "2"') # create accept/reject button self.accept_button = QPushButton('&Accept Picks') self.reject_button = QPushButton('&Reject Picks') self.disable_ar_buttons() # layout the outermost appearance of the Pick Dialog _outerlayout = QVBoxLayout() _dialtoolbar = QToolBar() # fill toolbar with content _dialtoolbar.addAction(self.filterAction) _dialtoolbar.addWidget(self.p_button) _dialtoolbar.addWidget(self.s_button) _dialtoolbar.addAction(self.zoomAction) _dialtoolbar.addSeparator() _dialtoolbar.addAction(self.resetZoomAction) _dialtoolbar.addSeparator() _dialtoolbar.addAction(self.resetPicksAction) if self._embedded: _dialtoolbar.addWidget(self.accept_button) _dialtoolbar.addWidget(self.reject_button) # layout the innermost widget _innerlayout = QVBoxLayout() _innerlayout.addWidget(self.multicompfig) # add button box to the dialog _buttonbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) # merge widgets and layouts to establish the dialog if not self._embedded: _innerlayout.addWidget(_buttonbox) _outerlayout.addWidget(_dialtoolbar) _outerlayout.addLayout(_innerlayout) # connect widget element signals with slots (methods to the dialog # object self.p_button.clicked.connect(self.p_clicked) self.s_button.clicked.connect(self.s_clicked) self.accept_button.clicked.connect(self.accept) self.reject_button.clicked.connect(self.reject) self.accept_button.clicked.connect(self.disable_ar_buttons) self.reject_button.clicked.connect(self.disable_ar_buttons) _buttonbox.accepted.connect(self.accept) _buttonbox.rejected.connect(self.reject) # finally layout the entire dialog self.setLayout(_outerlayout) self.resize(1280, 720) def disconnectPressEvent(self): widget = self.getPlotWidget() widget.mpl_disconnect(self.cidpress) self.cidpress = None def connectPressEvent(self, slot): widget = self.getPlotWidget() return widget.mpl_connect('button_press_event', slot) def disconnectScrollEvent(self): widget = self.getPlotWidget() widget.mpl_disconnect(self.cidscroll) self.cidscroll = None def connectScrollEvent(self, slot): widget = self.getPlotWidget() return widget.mpl_connect('scroll_event', slot) def disconnectMotionEvent(self): widget = self.getPlotWidget() widget.mpl_disconnect(self.cidmotion) self.cidmotion = None def connectMotionEvent(self, slot): widget = self.getPlotWidget() return widget.mpl_connect('motion_notify_event', slot) def disconnectReleaseEvent(self): widget = self.getPlotWidget() widget.mpl_disconnect(self.cidrelease) self.cidrelease = None def connectReleaseEvent(self, slot): widget = self.getPlotWidget() return widget.mpl_connect('button_release_event', slot) def disable_ar_buttons(self): self.enable_ar_buttons(False) def enable_ar_buttons(self, bool=True): self.accept_button.setEnabled(bool) self.reject_button.setEnabled(bool) def p_clicked(self): if self.p_button.isChecked(): self.s_button.setEnabled(False) self.init_p_pick() else: self.leave_picking_mode() def s_clicked(self): if self.s_button.isChecked(): self.p_button.setEnabled(False) self.init_s_pick() else: self.leave_picking_mode() def init_p_pick(self): self.set_button_color(self.p_button, 'yellow') self.updateCurrentLimits() self.activatePicking() self.currentPhase = 'P' def init_s_pick(self): self.set_button_color(self.s_button, 'yellow') self.updateCurrentLimits() self.activatePicking() self.currentPhase = 'S' def set_button_color(self, button, color = None): button.setStyleSheet("background-color: {}".format(color)) def leave_picking_mode(self): self.currentPhase = None self.set_button_color(self.p_button) self.set_button_color(self.s_button) self.p_button.setEnabled(True) self.s_button.setEnabled(True) self.p_button.setChecked(False) self.s_button.setChecked(False) self.getPlotWidget().plotWFData(wfdata=self.getWFData(), title=self.getStation()) self.drawAllPicks() self.setPlotLabels() self.resetZoomAction.trigger() self.deactivatePicking() def activatePicking(self): if self.zoomAction.isChecked(): self.zoomAction.trigger() self.disconnectReleaseEvent() self.disconnectScrollEvent() self.disconnectMotionEvent() self.disconnectPressEvent() self.cidpress = self.connectPressEvent(self.setIniPick) self.filterWFData() self.pick_block = self.togglePickBlocker() def deactivatePicking(self): self.disconnectPressEvent() self.cidpress = self.connectPressEvent(self.panPress) self.cidmotion = self.connectMotionEvent(self.panMotion) self.cidrelease = self.connectReleaseEvent(self.panRelease) self.cidscroll = self.connectScrollEvent(self.scrollZoom) def getParameter(self): return self.parameter def getStartTime(self): return self.stime def getEndTime(self): return self.etime def getComponents(self): return self.components def getStation(self): return self.station def getPlotWidget(self): return self.multicompfig def getChannelID(self, key): return self.getPlotWidget().getPlotDict()[int(key)][1] def getTraceID(self, channels): plotDict = self.getPlotWidget().getPlotDict() traceIDs = [] for channel in channels: channel = channel.upper() for traceID, channelID in plotDict.items(): if channelID[1].upper().endswith(channel): traceIDs.append(traceID) return traceIDs def getUser(self): return self._user def getFilterOptions(self, phase): options = self.filteroptions[phase] return FilterOptions(**options) def getXLims(self): return self.cur_xlim def getYLims(self): return self.cur_ylim def setXLims(self, limits): self.cur_xlim = limits def setYLims(self, limits): self.cur_ylim = limits def getGlobalLimits(self, axis): return self.limits[axis] def updateCurrentLimits(self): self.setXLims(self.getPlotWidget().getXLims()) self.setYLims(self.getPlotWidget().getYLims()) def getWFData(self): return self.data def selectWFData(self, channel): component = channel[-1].upper() wfdata = Stream() def selectTrace(tr, components): if tr.stats.channel[-1].upper() in components: return tr if component == 'E' or component == 'N': for trace in self.getWFData(): trace = selectTrace(trace, 'NE') if trace: wfdata.append(trace) elif component == '1' or component == '2': for trace in self.getWFData(): trace = selectTrace(trace, '12') if trace: wfdata.append(trace) else: wfdata = self.getWFData().select(component=component) return wfdata def getPicks(self, picktype='manual'): if picktype == 'manual': return self.picks elif picktype == 'auto': return self.autopicks else: raise TypeError('Unknown picktype {0}'.format(picktype)) def resetPicks(self): self.picks = {} def delPicks(self): self.resetPicks() self.resetPlot() def setIniPick(self, gui_event): trace_number = round(gui_event.ydata) channel = self.getChannelID(trace_number) wfdata = self.selectWFData(channel) self.disconnectScrollEvent() self.disconnectPressEvent() self.disconnectReleaseEvent() self.disconnectMotionEvent() self.cidpress = self.connectPressEvent(self.setPick) print(self.currentPhase) if self.currentPhase == 'P': self.set_button_color(self.p_button, 'green') self.setIniPickP(gui_event, wfdata, trace_number) elif self.currentPhase == 'S': self.set_button_color(self.s_button, 'green') self.setIniPickS(gui_event, wfdata) self.zoomAction.setEnabled(False) # reset labels self.setPlotLabels() self.draw() def setIniPickP(self, gui_event, wfdata, trace_number): parameter = self.parameter ini_pick = gui_event.xdata nfac = parameter.get('nfacP') twins = parameter.get('tsnrz') noise_win = twins[0] gap_win = twins[1] signal_win = twins[2] itrace = int(trace_number) while itrace > len(wfdata) - 1: itrace -= 1 # copy data for plotting data = self.getWFData().copy() # filter data and trace on which is picked prior to determination of SNR phase = self.currentPhase filteroptions = self.getFilterOptions(phase).parseFilterOptions() if filteroptions: data.filter(**filteroptions) wfdata.filter(**filteroptions) result = getSNR(wfdata, (noise_win, gap_win, signal_win), ini_pick, itrace) snr = result[0] noiselevel = result[2] * nfac x_res = getResolutionWindow(snr) # remove mean noise level from waveforms for trace in data: t = prepTimeAxis(trace.stats.starttime - self.getStartTime(), trace) inoise = getnoisewin(t, ini_pick, noise_win, gap_win) trace = demeanTrace(trace=trace, window=inoise) self.setXLims([ini_pick - x_res, ini_pick + x_res]) self.setYLims(np.array([-noiselevel * 2.5, noiselevel * 2.5]) + trace_number) self.getPlotWidget().plotWFData(wfdata=data, title=self.getStation() + ' picking mode', zoomx=self.getXLims(), zoomy=self.getYLims(), noiselevel=(trace_number + noiselevel, trace_number - noiselevel)) def setIniPickS(self, gui_event, wfdata): parameter = self.parameter ini_pick = gui_event.xdata nfac = parameter.get('nfacS') twins = parameter.get('tsnrh') noise_win = twins[0] gap_win = twins[1] signal_win = twins[2] # copy data for plotting data = self.getWFData().copy() # filter data and trace on which is picked prior to determination of SNR phase = self.currentPhase filteroptions = self.getFilterOptions(phase).parseFilterOptions() if filteroptions: data.filter(**filteroptions) wfdata.filter(**filteroptions) # determine SNR and noiselevel result = getSNR(wfdata, (noise_win, gap_win, signal_win), ini_pick) snr = result[0] noiselevel = result[2] * nfac # prepare plotting of data for trace in data: t = prepTimeAxis(trace.stats.starttime - self.getStartTime(), trace) inoise = getnoisewin(t, ini_pick, noise_win, gap_win) trace = demeanTrace(trace, inoise) # scale waveform for plotting horiz_comp = find_horizontals(data) data = scaleWFData(data, noiselevel * 2.5, horiz_comp) x_res = getResolutionWindow(snr) self.setXLims(tuple([ini_pick - x_res, ini_pick + x_res])) traces = self.getTraceID(horiz_comp) traces.sort() self.setYLims(tuple(np.array([-0.5, +0.5]) + np.array(traces))) noiselevels = [trace + 1 / (2.5 * 2) for trace in traces] + \ [trace - 1 / (2.5 * 2) for trace in traces] self.getPlotWidget().plotWFData(wfdata=data, title=self.getStation() + ' picking mode', zoomx=self.getXLims(), zoomy=self.getYLims(), noiselevel=noiselevels, scaleddata=True) def setPick(self, gui_event): parameter = self.parameter # get axes limits self.updateCurrentLimits() # setting pick pick = gui_event.xdata # get pick time relative to the traces timeaxis not to the global channel = self.getChannelID(round(gui_event.ydata)) # get name of phase actually picked phase = self.currentPhase # get filter parameter for the phase to be picked filteroptions = self.getFilterOptions(phase).parseFilterOptions() # copy and filter data for earliest and latest possible picks wfdata = self.getWFData().copy().select(channel=channel) if filteroptions: wfdata.filter(**filteroptions) # get earliest and latest possible pick and symmetric pick error if wfdata[0].stats.channel[2] == 'Z' or wfdata[0].stats.channel[2] == '3': nfac = parameter.get('nfacP') TSNR = parameter.get('tsnrz') else: nfac = parameter.get('nfacS') TSNR = parameter.get('tsnrh') [epp, lpp, spe] = earllatepicker(wfdata, nfac, (TSNR[0], TSNR[1], TSNR[2]), pick) # return absolute time values for phases stime = self.getStartTime() epp = stime + epp mpp = stime + pick lpp = stime + lpp # save pick times for actual phase phasepicks = dict(epp=epp, lpp=lpp, mpp=mpp, spe=spe, picker='manual', channel=channel, network=wfdata[0].stats.network) try: oldphasepick = self.picks[phase] except KeyError: self.picks[phase] = phasepicks else: self.picks[phase] = phasepicks oepp = oldphasepick['epp'] ompp = oldphasepick['mpp'] olpp = oldphasepick['lpp'] msg = """Warning old phase information for phase {phase} has been altered.\n New phase times:\n earliest possible pick: {epp}\n most probable pick: {mpp}\n latest possible pick: {lpp}\n \n Old phase times (overwritten):\n earliest possible pick: {oepp}\n most probable pick: {ompp}\n latest possible pick: {olpp}\n""".format(phase=phase, epp=epp, mpp=pick, lpp=lpp, oepp=oepp, ompp=ompp, olpp=olpp) self.disconnectPressEvent() self.enable_ar_buttons() self.zoomAction.setEnabled(True) self.pick_block = self.togglePickBlocker() self.leave_picking_mode() def drawAllPicks(self): self.drawPicks(picktype='manual') self.drawPicks(picktype='auto') def drawPicks(self, phase=None, picktype='manual'): # plotting picks ax = self.getPlotWidget().axes ylims = self.getGlobalLimits('y') phase_col = { 'P': ('c', 'c--', 'b-', 'bv', 'b^', 'b'), 'S': ('m', 'm--', 'r-', 'rv', 'r^', 'r') } if self.getPicks(picktype): if phase is not None and type(self.getPicks(picktype)[phase]) is dict: picks = self.getPicks(picktype)[phase] colors = phase_col[phase[0].upper()] elif phase is None: for phase in self.getPicks(picktype): self.drawPicks(phase, picktype) return else: return else: return mpp = picks['mpp'] - self.getStartTime() epp = picks['epp'] - self.getStartTime() lpp = picks['lpp'] - self.getStartTime() spe = picks['spe'] if picktype == 'manual': ax.fill_between([epp, lpp], ylims[0], ylims[1], alpha=.25, color=colors[0]) if spe: ax.plot([mpp - spe, mpp - spe], ylims, colors[1], [mpp, mpp], ylims, colors[2], [mpp + spe, mpp + spe], ylims, colors[1]) elif picktype == 'auto': ax.plot(mpp, ylims[1], colors[3], mpp, ylims[0], colors[4]) ax.vlines(mpp, ylims[0], ylims[1], colors[5], linestyles='dotted') else: raise TypeError('Unknown picktype {0}'.format(picktype)) def panPress(self, gui_event): ax = self.getPlotWidget().axes if gui_event.inaxes != ax: return self.cur_xlim = ax.get_xlim() self.cur_ylim = ax.get_ylim() self.press = gui_event.xdata, gui_event.ydata self.xpress, self.ypress = self.press def panRelease(self, gui_event): ax = self.getPlotWidget().axes self.press = None ax.figure.canvas.draw() def panMotion(self, gui_event): if self.press is None: return ax = self.getPlotWidget().axes if gui_event.inaxes != ax: return dx = gui_event.xdata - self.xpress dy = gui_event.ydata - self.ypress self.cur_xlim -= dx self.cur_ylim -= dy ax.set_xlim(self.cur_xlim) ax.set_ylim(self.cur_ylim) ax.figure.canvas.draw() def togglePickBlocker(self): return not self.pick_block def filterWFData(self): if self.pick_block: return self.updateCurrentLimits() data = self.getWFData().copy() old_title = self.getPlotWidget().getAxes().get_title() title = None phase = self.currentPhase filtoptions = None if phase: filtoptions = self.getFilterOptions(phase).parseFilterOptions() if self.filterAction.isChecked(): if not phase: filtoptions = FilterOptionsDialog.getFilterObject() filtoptions = filtoptions.parseFilterOptions() if filtoptions is not None: data.filter(**filtoptions) if not old_title.endswith(')'): title = old_title + ' (filtered)' elif not old_title.endswith(' (filtered)') and not old_title.endswith(', filtered)'): title = old_title[:-1] + ', filtered)' else: if old_title.endswith(' (filtered)'): title = old_title.replace(' (filtered)', '') elif old_title.endswith(', filtered)'): title = old_title.replace(', filtered)', ')') if title is None: title = old_title self.getPlotWidget().plotWFData(wfdata=data, title=title, zoomx=self.getXLims(), zoomy=self.getYLims()) self.setPlotLabels() self.drawAllPicks() self.draw() def resetPlot(self): self.updateCurrentLimits() data = self.getWFData().copy() title = self.getPlotWidget().getAxes().get_title() self.getPlotWidget().plotWFData(wfdata=data, title=title, zoomx=self.getXLims(), zoomy=self.getYLims()) self.setPlotLabels() self.drawAllPicks() self.draw() def setPlotLabels(self): # get channel labels pos = self.getPlotWidget().getPlotDict().keys() labels = [self.getPlotWidget().getPlotDict()[key][1] for key in pos] # set channel labels self.getPlotWidget().setYTickLabels(pos, labels) self.getPlotWidget().setXLims(self.getXLims()) self.getPlotWidget().setYLims(self.getYLims()) def zoom(self): if self.zoomAction.isChecked() and self.pick_block: self.zoomAction.setChecked(False) elif self.zoomAction.isChecked(): self.disconnectPressEvent() self.disconnectMotionEvent() self.disconnectReleaseEvent() self.disconnectScrollEvent() self.figToolBar.zoom() else: self.figToolBar.zoom() self.cidpress = self.connectPressEvent(self.panPress) self.cidmotion = self.connectMotionEvent(self.panMotion) self.cidrelease = self.connectReleaseEvent(self.panRelease) self.cidscroll = self.connectScrollEvent(self.scrollZoom) def scrollZoom(self, gui_event, factor=2.): self.updateCurrentLimits() if gui_event.button == 'up': scale_factor = 1 / factor elif gui_event.button == 'down': # deal with zoom out scale_factor = factor else: # deal with something that should never happen scale_factor = 1 print(gui_event.button) new_xlim = gui_event.xdata - \ scale_factor * (gui_event.xdata - self.getXLims()) new_ylim = gui_event.ydata - \ scale_factor * (gui_event.ydata - self.getYLims()) new_xlim.sort() global_x = self.getGlobalLimits('x') global_y = self.getGlobalLimits('y') new_xlim[0] = max(new_xlim[0], global_x[0]) new_xlim[1] = min(new_xlim[1], global_x[1]) new_ylim.sort() new_ylim[0] = max(new_ylim[0], global_y[0]) new_ylim[1] = min(new_ylim[1], global_y[1]) self.getPlotWidget().setXLims(new_xlim) self.getPlotWidget().setYLims(new_ylim) self.draw() def resetZoom(self): self.getPlotWidget().setXLims(self.getGlobalLimits('x')) self.getPlotWidget().setYLims(self.getGlobalLimits('y')) self.draw() def draw(self): self.getPlotWidget().draw() def apply(self): picks = self.getPicks() self.update_picks.emit(picks) for pick in picks: print(pick, picks[pick]) def discard(self): picks = self._init_picks self.picks = picks self.update_picks.emit(picks) for pick in picks: print(pick, picks[pick]) def reject(self): self.discard() if not self._embedded: QDialog.reject(self) else: self.resetPlot() self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Information, 'Denied', 'New picks rejected!') self.qmb.show() def accept(self): self.apply() if not self._embedded: QDialog.accept(self) else: self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Information, 'Accepted', 'New picks applied!') self.qmb.show() class TuneAutopicker(QWidget): update = QtCore.Signal(str) ''' QWidget used to modifiy and test picking parameters for autopicking algorithm. :param: parent :type: QtPyLoT Mainwindow ''' def __init__(self, parent): QtGui.QWidget.__init__(self, parent, 1) self.parent = parent self.setParent(parent) self.setWindowTitle('PyLoT - Tune Autopicker') self.parameter = parent._inputs self.fig_dict = parent.fig_dict self.data = Data() self.init_main_layouts() self.init_eventlist() self.init_figure_tabs() self.init_stationlist() self.init_pbwidget() self.connect_signals() self.add_parameters() self.add_buttons() self.add_log() self.set_stretch() self.resize(1280, 720) #self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal) #self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) def init_main_layouts(self): self.main_layout = QtGui.QVBoxLayout() self.tune_layout = QtGui.QHBoxLayout() self.trace_layout = QtGui.QHBoxLayout() self.parameter_layout = QtGui.QVBoxLayout() self.main_layout.addLayout(self.trace_layout) self.main_layout.addLayout(self.tune_layout) self.setLayout(self.main_layout) def init_eventlist(self): self.eventBox = self.parent.createEventBox() self.eventBox.setMaxVisibleItems(20) self.fill_eventbox() self.eventBox.setCurrentIndex(0) self.trace_layout.addWidget(self.eventBox) def init_stationlist(self): self.stationBox = QtGui.QComboBox() self.trace_layout.addWidget(self.stationBox) self.fill_stationbox() self.figure_tabs.setCurrentIndex(0) def connect_signals(self): self.eventBox.activated.connect(self.fill_stationbox) self.eventBox.activated.connect(self.update_eventID) self.eventBox.activated.connect(self.fill_tabs) self.stationBox.activated.connect(self.fill_tabs) def fill_stationbox(self): fnames = self.parent.getWFFnames_from_eventbox(eventbox=self.eventBox) self.data.setWFData(fnames) self.stationBox.clear() stations = [] for trace in self.data.getWFData(): station = trace.stats.station if not station in stations: stations.append(str(station)) stations.sort() model = self.stationBox.model() for station in stations: item = QtGui.QStandardItem(str(station)) if station in self.get_current_event().picks: item.setBackground(QtGui.QColor(200, 210, 230, 255)) model.appendRow(item) def init_figure_tabs(self): self.figure_tabs = QtGui.QTabWidget() self.fill_figure_tabs() def init_pbwidget(self): self.pb_widget = QtGui.QWidget() def init_tab_names(self): self.ptb_names = ['aicFig', 'slength', 'checkZ4s', 'refPpick', 'el_Ppick', 'fm_picker'] self.stb_names = ['aicARHfig', 'refSpick', 'el_S1pick', 'el_S2pick'] def add_parameters(self): self.parameters = AutoPickParaBox(self.parameter) self.parameters.set_tune_mode(True) self.update_eventID() self.parameter_layout.addWidget(self.parameters) self.parameter_layout.addWidget(self.pb_widget) self.tune_layout.insertLayout(1, self.parameter_layout) def add_buttons(self): self.pick_button = QtGui.QPushButton('Pick Trace') self.pick_button.clicked.connect(self.call_picker) self.close_button = QtGui.QPushButton('Close') self.close_button.clicked.connect(self.hide) self.trace_layout.addWidget(self.pick_button) self.trace_layout.setStretch(0, 1) self.parameter_layout.addWidget(self.close_button) def add_log(self): self.listWidget = QtGui.QListWidget() self.figure_tabs.insertTab(4, self.listWidget, 'log') def add_log_item(self, text): self.listWidget.addItem(text) self.listWidget.scrollToBottom() def get_current_event(self): index = self.eventBox.currentIndex() return self.eventBox.itemData(index) def get_current_event_name(self): return self.eventBox.currentText().split('/')[-1] def get_current_event_fp(self): return self.eventBox.currentText() def get_current_event_picks(self, station): event = self.get_current_event() if station in event.picks.keys(): return event.picks[station] def get_current_event_autopicks(self, station): event = self.get_current_event() if event.autopicks: return event.autopicks[station] def get_current_station(self): return str(self.stationBox.currentText()) def gen_tab_widget(self, name, canvas): widget = QtGui.QWidget() v_layout = QtGui.QVBoxLayout() v_layout.addWidget(canvas) v_layout.addWidget(NavigationToolbar2QT(canvas, self)) widget.setLayout(v_layout) return widget def gen_pick_dlg(self): station = self.get_current_station() data = self.data.getWFData() pickDlg = PickDlg(self, data=data.select(station=station), station=station, parameter=self.parameter, picks=self.get_current_event_picks(station), autopicks=self.get_current_event_autopicks(station), embedded=True) pickDlg.update_picks.connect(self.picks_from_pickdlg) pickDlg.update_picks.connect(self.fill_eventbox) pickDlg.update_picks.connect(self.fill_stationbox) self.pickDlg = QtGui.QWidget() hl = QtGui.QHBoxLayout() self.pickDlg.setLayout(hl) hl.addWidget(pickDlg) def picks_from_pickdlg(self, picks=None): station = self.get_current_station() self.get_current_event().setPick(station, picks) def plot_manual_picks_to_figs(self): picks = self.get_current_event_picks(self.get_current_station()) if not picks: return st = self.data.getWFData() tr = st.select(station=self.get_current_station())[0] starttime = tr.stats.starttime p_axes=[ ('mainFig', 0), ('aicFig', 0), ('slength', 0), ('refPpick', 0), ('el_Ppick', 0), ('fm_picker', 0), ('fm_picker', 1)] s_axes=[ ('mainFig', 1), ('mainFig', 2), ('aicARHfig', 0), ('refSpick', 0), ('el_S1pick', 0), ('el_S2pick', 0)] for p_ax in p_axes: axes = self.parent.fig_dict[p_ax[0]].axes if not axes: continue ax = axes[p_ax[1]] self.plot_manual_Ppick_to_ax(ax, (picks['P']['mpp'] - starttime)) for s_ax in s_axes: axes = self.parent.fig_dict[s_ax[0]].axes if not axes: continue ax = axes[s_ax[1]] self.plot_manual_Spick_to_ax(ax, (picks['S']['mpp'] - starttime)) def plot_manual_Ppick_to_ax(self, ax, pick): y_top = 0.9*ax.get_ylim()[1] y_bot = 0.9*ax.get_ylim()[0] ax.vlines(pick, y_bot, y_top, color='cyan', linewidth=2, label='manual P Onset') ax.plot([pick-0.5, pick+0.5], [y_bot, y_bot], linewidth=2, color='cyan') ax.plot([pick-0.5, pick+0.5], [y_top, y_top], linewidth=2, color='cyan') ax.legend() def plot_manual_Spick_to_ax(self, ax, pick): y_top = 0.9*ax.get_ylim()[1] y_bot = 0.9*ax.get_ylim()[0] ax.vlines(pick, y_bot, y_top, color='magenta', linewidth=2, label='manual S Onset') ax.plot([pick-0.5, pick+0.5], [y_bot, y_bot], linewidth=2, color='magenta') ax.plot([pick-0.5, pick+0.5], [y_top, y_top], linewidth=2, color='magenta') ax.legend() def fill_tabs(self, event=None, picked=False): self.clear_all() canvas_dict = self.parent.canvas_dict self.gen_pick_dlg() self.overview = self.gen_tab_widget('Overview', canvas_dict['mainFig']) id0 = self.figure_tabs.insertTab(0, self.pickDlg, 'Traces Plot') id1 = self.figure_tabs.insertTab(1, self.overview, 'Overview') id2 = self.figure_tabs.insertTab(2, self.p_tabs, 'P') id3 = self.figure_tabs.insertTab(3, self.s_tabs, 'S') if picked: self.fill_p_tabs(canvas_dict) self.fill_s_tabs(canvas_dict) self.toggle_autopickTabs(bool(self.fig_dict['mainFig'].axes)) self.plot_manual_picks_to_figs() else: self.disable_autopickTabs() try: main_fig.tight_layout() except: pass self.figure_tabs.setCurrentIndex(0) def fill_p_tabs(self, canvas_dict): for name in self.ptb_names: id = self.p_tabs.addTab(self.gen_tab_widget(name, canvas_dict[name]), name) self.p_tabs.setTabEnabled(id, bool(self.fig_dict[name].axes)) try: self.fig_dict[name].tight_layout() except: pass def fill_s_tabs(self, canvas_dict): for name in self.stb_names: id = self.s_tabs.addTab(self.gen_tab_widget(name, canvas_dict[name]), name) self.s_tabs.setTabEnabled(id, bool(self.fig_dict[name].axes)) try: self.fig_dict[name].tight_layout() except: pass def fill_figure_tabs(self): self.clear_all() self.p_tabs = QtGui.QTabWidget() self.s_tabs = QtGui.QTabWidget() self.tune_layout.insertWidget(0, self.figure_tabs) self.init_tab_names() def fill_eventbox(self): self.parent.fill_eventbox(self.eventBox, 'ref') self.parent.fill_eventbox(self.parent.eventBox) def update_eventID(self): self.parameters.boxes['eventID'].setText( self.get_current_event_name()) self.figure_tabs.setCurrentIndex(0) def call_picker(self): self.parameter = self.params_from_gui() station = self.get_current_station() if not station: self._warn('No station selected') return args = {'parameter': self.parameter, 'station': station, 'fnames': 'None', 'iplot': 2, 'fig_dict': self.fig_dict, 'locflag': 0} for key in self.fig_dict.keys(): self.fig_dict[key].clear() self.ap_thread = Thread(self, autoPyLoT, arg=args, progressText='Picking trace...', pb_widget=self.pb_widget, redirect_stdout=True) self.enable(False) self.ap_thread.message.connect(self.add_log_item) self.ap_thread.finished.connect(self.finish_picker) self.figure_tabs.setCurrentIndex(4) self.ap_thread.start() #picks = autoPyLoT(self.parameter, fnames='None', iplot=2, fig_dict=self.fig_dict) def finish_picker(self): self.enable(True) if not self.ap_thread._executed: self._warn('Could not execute picker:\n{}'.format( self.ap_thread._executedError)) return self.picks = self.ap_thread.data if not self.picks: self._warn('No picks found. See terminal output.') return #renew tabs #self.fill_figure_tabs() self.set_stretch() self.update.emit('Update') self.figure_tabs.setCurrentIndex(1) def enable(self, bool): self.pick_button.setEnabled(bool) self.parameters.setEnabled(bool) self.eventBox.setEnabled(bool) self.stationBox.setEnabled(bool) self.overview.setEnabled(bool) self.p_tabs.setEnabled(bool) self.s_tabs.setEnabled(bool) def params_from_gui(self): parameters = self.parameters.params_from_gui() if self.parent: self.parent._inputs = parameters return parameters def set_stretch(self): self.tune_layout.setStretch(0, 3) self.tune_layout.setStretch(1, 1) def clear_all(self): if hasattr(self, 'pickDlg'): self.pickDlg.setParent(None) del(self.pickDlg) if hasattr(self, 'overview'): self.overview.setParent(None) if hasattr(self, 'p_tabs'): self.p_tabs.clear() self.p_tabs.setParent(None) if hasattr(self, 's_tabs'): self.s_tabs.clear() self.s_tabs.setParent(None) def disable_autopickTabs(self): self.toggle_autopickTabs(False) def toggle_autopickTabs(self, bool): self.figure_tabs.setTabEnabled(1, bool) self.figure_tabs.setTabEnabled(2, bool) self.figure_tabs.setTabEnabled(3, bool) def _warn(self, message): self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning, 'Warning', message) self.qmb.show() class AutoPickParaBox(QtGui.QWidget): def __init__(self, parameter, parent=None): ''' Generate Widget containing parameters for automatic picking algorithm. :param: parameter :type: AutoPickParameter (object) ''' QtGui.QWidget.__init__(self, parent) self.parameter = parameter self.tabs = QtGui.QTabWidget() self.layout = QtGui.QVBoxLayout() self._init_buttons() self.layout.addWidget(self.tabs) self.boxes = {} self._init_sublayouts() self.setLayout(self.layout) self.add_main_parameters_tab() self.add_special_pick_parameters_tab() self.params_to_gui() self._toggle_advanced_settings() def _init_sublayouts(self): self._main_layout = QtGui.QVBoxLayout() self._advanced_layout = QtGui.QVBoxLayout() self._create_advanced_cb() def _init_buttons(self): self._buttons_layout = QtGui.QHBoxLayout() self.loadButton = QtGui.QPushButton('&Load settings') self.saveButton = QtGui.QPushButton('&Save settings') self.defaultsButton = QtGui.QPushButton('&Defaults') self._buttons_layout.addWidget(self.loadButton) self._buttons_layout.addWidget(self.saveButton) self._buttons_layout.addWidget(self.defaultsButton) self.layout.addLayout(self._buttons_layout) self.loadButton.clicked.connect(self.openFile) self.saveButton.clicked.connect(self.saveFile) self.defaultsButton.clicked.connect(self.restoreDefaults) def _create_advanced_cb(self): self._advanced_cb = QtGui.QCheckBox('Enable Advanced Settings') self._advanced_layout.addWidget(self._advanced_cb) self._advanced_cb.toggled.connect(self._toggle_advanced_settings) def _toggle_advanced_settings(self): if self._advanced_cb.isChecked(): self._enable_advanced(True) else: self._enable_advanced(False) def _enable_advanced(self, enable): for lst in self.parameter.get_special_para_names().values(): for param in lst: box = self.boxes[param] if type(box) is not list: box.setEnabled(enable) else: for b in box: b.setEnabled(enable) def set_tune_mode(self, bool): keys = ['rootpath', 'datapath', 'database', 'eventID', 'invdir', 'nllocbin', 'nllocroot', 'phasefile', 'ctrfile', 'ttpatter', 'outpatter'] for key in keys: self.boxes[key].setEnabled(not(bool)) def init_boxes(self, parameter_names): grid = QtGui.QGridLayout() for index1, name in enumerate(parameter_names): text = name + ' [?]' label = QtGui.QLabel(text) default_item = self.parameter.get_defaults()[name] tooltip = default_item['tooltip'] tooltip += ' | type: {}'.format(default_item['type']) if not type(default_item['type']) == tuple: typ = default_item['type'] box = self.create_box(typ, tooltip) self.boxes[name] = box elif type(default_item['type']) == tuple: boxes = [] values = self.parameter[name] for index2, val in enumerate(values): typ = default_item['type'][index2] boxes.append(self.create_box(typ, tooltip)) box = self.create_multi_box(boxes) self.boxes[name] = boxes label.setToolTip(tooltip) grid.addWidget(label, index1, 1) grid.addWidget(box, index1, 2) return grid def create_box(self, typ, tooltip): if typ == str: box = QtGui.QLineEdit() elif typ == float: box = QtGui.QDoubleSpinBox() elif typ == int: box = QtGui.QSpinBox() elif typ == bool: box = QtGui.QCheckBox() else: raise TypeError('Unrecognized type {}'.format(typ)) return box def create_multi_box(self, boxes): box = QtGui.QWidget() hl = QtGui.QHBoxLayout() for b in boxes: hl.addWidget(b) box.setLayout(hl) return box def add_tab(self, layout, name): widget = QtGui.QWidget() scrollA = QtGui.QScrollArea() scrollA.setWidgetResizable(True) scrollA.setWidget(widget) widget.setLayout(layout) self.tabs.addTab(scrollA, name) def add_main_parameters_tab(self): self.add_to_layout(self._main_layout, 'Directories', self.parameter.get_main_para_names()['dirs']) self.add_to_layout(self._main_layout, 'NLLoc', self.parameter.get_main_para_names()['nlloc']) self.add_to_layout(self._main_layout, 'Seismic Moment', self.parameter.get_main_para_names()['smoment']) self.add_to_layout(self._main_layout, 'Focal Mechanism', self.parameter.get_main_para_names()['pick'], False) self.add_tab(self._main_layout, 'Main Settings') def add_special_pick_parameters_tab(self): self.add_to_layout(self._advanced_layout, 'Z-component', self.parameter.get_special_para_names()['z']) self.add_to_layout(self._advanced_layout, 'H-components', self.parameter.get_special_para_names()['h']) self.add_to_layout(self._advanced_layout, 'First-motion picker', self.parameter.get_special_para_names()['fm']) self.add_to_layout(self._advanced_layout, 'Quality assessment', self.parameter.get_special_para_names()['quality'], False) self.add_tab(self._advanced_layout, 'Advanced Settings') def gen_h_seperator(self): seperator = QtGui.QFrame() seperator.setFrameShape(QtGui.QFrame.HLine) return seperator def gen_headline(self, text): label=QtGui.QLabel(text) font=QtGui.QFont() font.setBold(True) label.setFont(font) return label def add_to_layout(self, layout, name, items, seperator=True): layout.addWidget(self.gen_headline(name)) layout.addLayout(self.init_boxes(items)) if seperator: layout.addWidget(self.gen_h_seperator()) def params_from_gui(self): for param in self.parameter.get_all_para_names(): box = self.boxes[param] value = self.getValue(box) self.parameter.checkValue(param, value) self.parameter.setParamKV(param, value) return self.parameter def params_to_gui(self, tuneMode=False): for param in self.parameter.get_all_para_names(): if param == 'eventID': if tuneMode: continue box = self.boxes[param] value = self.parameter[param] #self.parameter.checkValue(param, value) self.setValue(box, value) def setValue(self, box, value): if type(box) == QtGui.QLineEdit: box.setText(value) elif type(box) == QtGui.QSpinBox or type(box) == QtGui.QDoubleSpinBox: box.setMaximum(100*value) box.setValue(value) elif type(box) == QtGui.QCheckBox: if value == 'True': value = True if value == 'False': value = False box.setChecked(value) elif type(box) == list: for index, b in enumerate(box): self.setValue(b, value[index]) def getValue(self, box): if type(box) == QtGui.QLineEdit: value = str(box.text()) elif type(box) == QtGui.QSpinBox or type(box) == QtGui.QDoubleSpinBox: value = box.value() elif type(box) == QtGui.QCheckBox: value = box.isChecked() elif type(box) == list: value = [] for b in box: value.append(self.getValue(b)) value = tuple(value) return value def openFile(self): fd = QtGui.QFileDialog() fname = fd.getOpenFileName(self, 'Browse for settings file.', '*.in') if fname[0]: try: self.parameter.from_file(fname[0]) self.params_to_gui(tuneMode=True) except Exception as e: self._warn('Could not open file {}:\n{}'.format(fname[0], e)) return def saveFile(self): fd = QtGui.QFileDialog() fname = fd.getSaveFileName(self, 'Browse for settings file.', '*.in') if fname[0]: try: self.params_from_gui() self.parameter.export2File(fname[0]) except Exception as e: self._warn('Could not save file {}:\n{}'.format(fname[0], e)) return def restoreDefaults(self): try: self.parameter.reset_defaults() self.params_to_gui(tuneMode=True) except Exception as e: self._warn('Could not restore defaults:\n{}'.format(e)) return def _warn(self, message): self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning, 'Warning', message) self.qmb.show() class PropertiesDlg(QDialog): def __init__(self, parent=None, infile=None): super(PropertiesDlg, self).__init__(parent) self.infile = infile self.setWindowTitle("PyLoT Properties") self.tabWidget = QTabWidget() self.tabWidget.addTab(InputsTab(self), "Inputs") self.tabWidget.addTab(OutputsTab(self), "Outputs") self.tabWidget.addTab(PhasesTab(self), "Phases") self.tabWidget.addTab(GraphicsTab(self), "Graphics") #self.tabWidget.addTab(LocalisationTab(self), "Loc. Tools") self.tabWidget.addTab(LocalisationTab(self), "NonLinLoc") self.tabWidget.addTab(ParametersTab(self, infile), "Picking Parameters") self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Apply | QDialogButtonBox.Close | QDialogButtonBox.RestoreDefaults) layout = QVBoxLayout() layout.addWidget(self.tabWidget) layout.addWidget(self.buttonBox) self.setLayout(layout) self.setFixedWidth(700) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.buttonBox.button(QDialogButtonBox.Apply).clicked.connect(self.apply) self.buttonBox.button(QDialogButtonBox.RestoreDefaults).clicked.connect(self.restore) def getinfile(self): return self.infile def accept(self, *args, **kwargs): self.apply() QDialog.accept(self) def apply(self): for widint in range(self.tabWidget.count()): curwid = self.tabWidget.widget(widint) values = curwid.getValues() if values is not None: self.setValues(values) def restore(self): for widint in range(self.tabWidget.count()): curwid = self.tabWidget.widget(widint) values = curwid.resetValues(self.getinfile()) if values is not None: self.setValues(values) @staticmethod def setValues(tabValues): settings = QSettings() for setting, value in tabValues.items(): settings.setValue(setting, value) settings.sync() class PropTab(QWidget): def __init__(self, parent=None): super(PropTab, self).__init__(parent) def getValues(self): return None def resetValues(self, infile=None): return None class InputsTab(PropTab): def __init__(self, parent, infile=None): super(InputsTab, self).__init__(parent) settings = QSettings() pylot_user = getpass.getuser() fulluser = settings.value("user/FullName") login = settings.value("user/Login") fullNameLabel = QLabel("Full name for user '{0}': ".format(pylot_user)) # get the full name of the actual user self.fullNameEdit = QLineEdit() try: self.fullNameEdit.setText(fulluser) except TypeError as e: self.fullNameEdit.setText(fulluser[0]) # information about data structure dataroot = settings.value("data/dataRoot") curstructure = settings.value("data/Structure") dataDirLabel = QLabel("data root directory: ") self.dataDirEdit = QLineEdit() self.dataDirEdit.setText(dataroot) self.dataDirEdit.selectAll() structureLabel = QLabel("data structure: ") self.structureSelect = QComboBox() from pylot.core.util.structure import DATASTRUCTURE self.structureSelect.addItems(DATASTRUCTURE.keys()) dsind = findComboBoxIndex(self.structureSelect, curstructure) self.structureSelect.setCurrentIndex(dsind) layout = QGridLayout() layout.addWidget(dataDirLabel, 0, 0) layout.addWidget(self.dataDirEdit, 0, 1) layout.addWidget(fullNameLabel, 1, 0) layout.addWidget(self.fullNameEdit, 1, 1) layout.addWidget(structureLabel, 2, 0) layout.addWidget(self.structureSelect, 2, 1) self.setLayout(layout) def getValues(self): values = {"data/dataRoot": self.dataDirEdit.text(), "user/FullName": self.fullNameEdit.text(), "data/Structure": self.structureSelect.currentText()} return values def resetValues(self, infile): para = AutoPickParameter(infile) datstruct = para.get('datastructure') if datstruct == 'SeisComp': index = 0 else: index = 2 datapath = para.get('datapath') rootpath = para.get('rootpath') database = para.get('database') path = os.path.join(os.path.expanduser('~'), rootpath, datapath, database) values = {"data/dataRoot": self.dataDirEdit.setText("%s" % path), "user/FullName": self.fullNameEdit.text(), "data/Structure": self.structureSelect.setCurrentIndex(index)} return values class OutputsTab(PropTab): def __init__(self, parent=None, infile=None): super(OutputsTab, self).__init__(parent) settings = QSettings() curval = settings.value("output/Format", None) eventOutputLabel = QLabel("event ouput format") self.eventOutputComboBox = QComboBox() eventoutputformats = OUTPUTFORMATS.keys() self.eventOutputComboBox.addItems(eventoutputformats) ind = findComboBoxIndex(self.eventOutputComboBox, curval) self.eventOutputComboBox.setCurrentIndex(ind) layout = QGridLayout() layout.addWidget(eventOutputLabel, 0, 0) layout.addWidget(self.eventOutputComboBox, 0, 1) self.setLayout(layout) def getValues(self): values = {"output/Format": self.eventOutputComboBox.currentText()} return values def resetValues(self, infile): values = {"output/Format": self.eventOutputComboBox.setCurrentIndex(1)} return values class PhasesTab(PropTab): def __init__(self, parent=None): super(PhasesTab, self).__init__(parent) pass class GraphicsTab(PropTab): def __init__(self, parent=None): super(GraphicsTab, self).__init__(parent) pass class LocalisationTab(PropTab): def __init__(self, parent=None, infile=None): super(LocalisationTab, self).__init__(parent) settings = QSettings() curtool = settings.value("loc/tool", None) #loctoollabel = QLabel("location tool") self.locToolComboBox = QComboBox() #loctools = LOCTOOLS.keys() #self.locToolComboBox.addItems(loctools) #toolind = findComboBoxIndex(self.locToolComboBox, curtool) #self.locToolComboBox.setCurrentIndex(toolind) curroot = settings.value("{0}/rootPath".format(curtool), None) curbin = settings.value("{0}/binPath".format(curtool), None) self.rootlabel = QLabel("root directory") self.binlabel = QLabel("bin directory") self.rootedit = QLineEdit('') self.binedit = QLineEdit('') if curroot is not None: self.rootedit.setText(curroot) if curbin is not None: self.binedit.setText(curbin) rootBrowse = QPushButton('...', self) rootBrowse.clicked.connect(lambda: self.selectDirectory(self.rootedit)) binBrowse = QPushButton('...', self) binBrowse.clicked.connect(lambda: self.selectDirectory(self.binedit)) #self.locToolComboBox.currentIndexChanged.connect(self.updateUi) self.updateUi() layout = QGridLayout() #layout.addWidget(loctoollabel, 0, 0) #layout.addWidget(self.locToolComboBox, 0, 1) layout.addWidget(self.rootlabel, 1, 0) layout.addWidget(self.rootedit, 1, 1) layout.addWidget(rootBrowse, 1, 2) layout.addWidget(self.binlabel, 2, 0) layout.addWidget(self.binedit, 2, 1) layout.addWidget(binBrowse, 2, 2) self.setLayout(layout) def updateUi(self): curtool = self.locToolComboBox.currentText() #if curtool is not None: self.rootlabel.setText("{0} root directory".format(curtool)) self.binlabel.setText("{0} bin directory".format(curtool)) def selectDirectory(self, edit): selected_directory = QFileDialog.getExistingDirectory() # check if string is empty if selected_directory: edit.setText(selected_directory) def getValues(self): loctool = self.locToolComboBox.currentText() values = {"{0}/rootPath".format(loctool): self.rootedit.text(), "{0}/binPath".format(loctool): self.binedit.text()} #"loc/tool": loctool} return values def resetValues(self, infile): para = AutoPickParameter(infile) nllocroot = para.get('nllocroot') nllocbin = para.get('nllocbin') loctool = self.locToolComboBox.setCurrentIndex(3) values = {"nll/rootPath": self.rootedit.setText("%s" % nllocroot), "nll/binPath": self.binedit.setText("%s" % nllocbin)} class ParametersTab(PropTab): def __init__(self, parent=None, infile=None): super(ParametersTab, self).__init__(parent) self.commonpicksettings = QPushButton("&Common Settings autoPyLoT") self.specialpicksettings = QPushButton("Special Settings autoPyLoT") self.CFsettings = QPushButton("Special Settings for Calculating CF's") self.FMsettings = QPushButton("Settings for First-Motion Picker") self.qsettings = QPushButton("Quality Assessment") self.sourcepara = QPushButton("Settings for Source Parameter Estimation") self.parent = parent self.infile = infile layout = QGridLayout() layout.addWidget(self.commonpicksettings, 0, 0) layout.addWidget(self.specialpicksettings, 1, 0) layout.addWidget(self.CFsettings, 2, 0) layout.addWidget(self.FMsettings, 0, 1) layout.addWidget(self.qsettings, 1, 1) layout.addWidget(self.sourcepara, 2, 1) self.setLayout(layout) self.commonpicksettings.clicked.connect(self.ButtonCommonPickSettings) def ButtonCommonPickSettings(self):#, event=None): # get parameters from pylot.in-file para = AutoPickParameter(self.infile) pstart = para.get('pstart') pstop = para.get('pstop') sstart = para.get('sstart') sstop = para.get('sstop') bpz1 = para.get('bpz1') bpz2 = para.get('bpz2') bph1 = para.get('bph1') bph2 = para.get('bph2') settings = QSettings() self.widget = QWidget(self.parent, 1) self.widget.setWindowTitle("Common Settings autoPyLoT") self.pCFcalcwinLabel = QLabel("Start/end time (relative to waveform onset) for calculating CF from waveform for P-pick [s]") self.pCFcalcwinEdit = QLineEdit() self.pCFcalcwinEdit.setText("%6.1f %6.1f" % (pstart, pstop)) self.sCFcalcwinLabel = QLabel("Start/end time (relative to P onset) for calculating CF from waveform for S-pick [s]") self.sCFcalcwinEdit = QLineEdit() self.sCFcalcwinEdit.setText("%6.1f %6.1f" % (sstart, sstop)) self.bpP1Label = QLabel("1st Bandpass P-Pick, lower/upper corner frequency [Hz]") self.bpP2Label = QLabel("2nd Bandpass P-Pick, lower/upper corner frequency [Hz]") self.bpS1Label = QLabel("1st Bandpass S-Pick, lower/upper corner frequency [Hz]") self.bpS2Label = QLabel("2nd Bandpass S-Pick, lower/upper corner frequency [Hz]") self.bpP1Edit = QLineEdit() self.bpP1Edit.setText("%4.1f %4.1f" % (bpz1[0], bpz1[1])) self.bpP2Edit = QLineEdit() self.bpP2Edit.setText("%4.1f %4.1f" % (bpz2[0], bpz2[1])) self.bpS1Edit = QLineEdit() self.bpS1Edit.setText("%4.1f %4.1f" % (bph1[0], bph1[1])) self.bpS2Edit = QLineEdit() self.bpS2Edit.setText("%4.1f %4.1f" % (bph2[0], bph2[1])) self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Apply | QDialogButtonBox.Close) layout = QGridLayout() layout.addWidget(self.pCFcalcwinLabel, 0, 0) layout.addWidget(self.pCFcalcwinEdit, 0, 1) layout.addWidget(self.sCFcalcwinLabel, 1, 0) layout.addWidget(self.sCFcalcwinEdit, 1, 1) layout.addWidget(self.bpP1Label, 2, 0) layout.addWidget(self.bpP1Edit, 2, 1) layout.addWidget(self.bpP2Label, 3, 0) layout.addWidget(self.bpP2Edit, 3, 1) layout.addWidget(self.bpS1Label, 4, 0) layout.addWidget(self.bpS1Edit, 4, 1) layout.addWidget(self.bpS2Label, 5, 0) layout.addWidget(self.bpS2Edit, 5, 1) layout.addWidget(self.buttonBox) self.widget.setLayout(layout) self.widget.show() self.raise_() self.widget.activateWindow() class NewEventDlg(QDialog): def __init__(self, parent=None, titleString="Create a new event"): """ QDialog object utilized to create a new event manually. """ super(NewEventDlg, self).__init__() self.setupUI() now = datetime.datetime.now() self.eventTimeEdit.setDateTime(now) # event dates in the future are forbidden self.eventTimeEdit.setMaximumDateTime(now) self.latEdit.setText("51.0000") self.lonEdit.setText("7.0000") self.depEdit.setText("10.0") self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) def getValues(self): return {'origintime': self.eventTimeEdit.dateTime().toPython(), 'latitude': self.latEdit.text(), 'longitude': self.lonEdit.text(), 'depth': self.depEdit.text()} def setupUI(self): # create widget objects timeLabel = QLabel() timeLabel.setText("Select time: ") self.eventTimeEdit = QDateTimeEdit() latLabel = QLabel() latLabel.setText("Latitude: ") self.latEdit = QLineEdit() lonLabel = QLabel() lonLabel.setText("Longitude: ") self.lonEdit = QLineEdit() depLabel = QLabel() depLabel.setText("Depth: ") self.depEdit = QLineEdit() self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) grid = QGridLayout() grid.addWidget(timeLabel, 0, 0) grid.addWidget(self.eventTimeEdit, 0, 1) grid.addWidget(latLabel, 1, 0) grid.addWidget(self.latEdit, 1, 1) grid.addWidget(lonLabel, 2, 0) grid.addWidget(self.lonEdit, 2, 1) grid.addWidget(depLabel, 3, 0) grid.addWidget(self.depEdit, 3, 1) grid.addWidget(self.buttonBox, 4, 1) self.setLayout(grid) class FilterOptionsDialog(QDialog): def __init__(self, parent=None, titleString="Filter options", filterOptions=None): """ PyLoT widget FilterOptionsDialog is a QDialog object. It is an UI to adjust parameters for filtering seismic data. """ super(FilterOptionsDialog, self).__init__() if parent is not None and parent.getFilterOptions(): self.filterOptions = parent.getFilterOptions() elif filterOptions is not None: self.filterOptions = FilterOptions(filterOptions) else: self.filterOptions = FilterOptions() _enable = True if self.getFilterOptions().getFilterType() is None: _enable = False self.freqminLabel = QLabel() self.freqminLabel.setText("minimum:") self.freqminSpinBox = QDoubleSpinBox() self.freqminSpinBox.setRange(5e-7, 1e6) self.freqminSpinBox.setDecimals(2) self.freqminSpinBox.setSuffix(' Hz') self.freqminSpinBox.setEnabled(_enable) self.freqmaxLabel = QLabel() self.freqmaxLabel.setText("maximum:") self.freqmaxSpinBox = QDoubleSpinBox() self.freqmaxSpinBox.setRange(5e-7, 1e6) self.freqmaxSpinBox.setDecimals(2) self.freqmaxSpinBox.setSuffix(' Hz') if _enable: self.freqminSpinBox.setValue(self.getFilterOptions().getFreq()[0]) if self.getFilterOptions().getFilterType() in ['bandpass', 'bandstop']: self.freqmaxSpinBox.setValue( self.getFilterOptions().getFreq()[1]) else: try: self.freqmaxSpinBox.setValue(self.getFilterOptions().getFreq()) self.freqminSpinBox.setValue(self.getFilterOptions().getFreq()) except TypeError as e: print(e) self.freqmaxSpinBox.setValue(1.) self.freqminSpinBox.setValue(.1) typeOptions = [None, "bandpass", "bandstop", "lowpass", "highpass"] self.orderLabel = QLabel() self.orderLabel.setText("Order:") self.orderSpinBox = QSpinBox() self.orderSpinBox.setRange(2, 10) self.orderSpinBox.setEnabled(_enable) self.selectTypeLabel = QLabel() self.selectTypeLabel.setText("Select filter type:") self.selectTypeCombo = QComboBox() self.selectTypeCombo.addItems(typeOptions) self.selectTypeCombo.setCurrentIndex(typeOptions.index(self.getFilterOptions().getFilterType())) self.selectTypeLayout = QVBoxLayout() self.selectTypeLayout.addWidget(self.orderLabel) self.selectTypeLayout.addWidget(self.orderSpinBox) self.selectTypeLayout.addWidget(self.selectTypeLabel) self.selectTypeLayout.addWidget(self.selectTypeCombo) self.freqGroupBox = QGroupBox("Frequency range") self.freqGroupLayout = QGridLayout() self.freqGroupLayout.addWidget(self.freqminLabel, 0, 0) self.freqGroupLayout.addWidget(self.freqminSpinBox, 0, 1) self.freqGroupLayout.addWidget(self.freqmaxLabel, 1, 0) self.freqGroupLayout.addWidget(self.freqmaxSpinBox, 1, 1) self.freqGroupBox.setLayout(self.freqGroupLayout) self.freqmaxSpinBox.setEnabled(_enable) self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) grid = QGridLayout() grid.addWidget(self.freqGroupBox, 0, 2, 1, 2) grid.addLayout(self.selectTypeLayout, 1, 2, 1, 2) grid.addWidget(self.buttonBox, 2, 2, 1, 2) self.setLayout(grid) self.freqminSpinBox.valueChanged.connect(self.updateUi) self.freqmaxSpinBox.valueChanged.connect(self.updateUi) self.orderSpinBox.valueChanged.connect(self.updateUi) self.selectTypeCombo.currentIndexChanged.connect(self.updateUi) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) def updateUi(self): type = self.selectTypeCombo.currentText() _enable = type in ['bandpass', 'bandstop'] freq = [self.freqminSpinBox.value(), self.freqmaxSpinBox.value()] self.freqmaxLabel.setEnabled(_enable) self.freqmaxSpinBox.setEnabled(_enable) if not _enable: self.freqminLabel.setText("cutoff:") self.freqmaxSpinBox.setValue(freq[0]) freq.remove(freq[1]) else: self.freqminLabel.setText("minimum:") if not isSorted(freq): QMessageBox.warning(self, "Value error", "Maximum frequency must be at least the " "same value as minimum frequency (notch)!") self.freqmaxSpinBox.setValue(freq[0]) self.freqmaxSpinBox.selectAll() self.freqmaxSpinBox.setFocus() return self.getFilterOptions().setFilterType(type) self.getFilterOptions().setFreq(freq) self.getFilterOptions().setOrder(self.orderSpinBox.value()) def getFilterOptions(self): return self.filterOptions @staticmethod def getFilterObject(): dlg = FilterOptionsDialog() if dlg.exec_(): return dlg.getFilterOptions() return None def accept(self): self.updateUi() QDialog.accept(self) class LoadDataDlg(QDialog): def __init__(self, parent=None): super(LoadDataDlg, self).__init__(parent) pass class HelpForm(QDialog): def __init__(self, page=QUrl('https://ariadne.geophysik.rub.de/trac/PyLoT'), parent=None): super(HelpForm, self).__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) self.setAttribute(Qt.WA_GroupLeader) backAction = QAction(QIcon(":/back.png"), "&Back", self) backAction.setShortcut(QKeySequence.Back) homeAction = QAction(QIcon(":/home.png"), "&Home", self) homeAction.setShortcut("Home") self.pageLabel = QLabel() toolBar = QToolBar() toolBar.addAction(backAction) toolBar.addAction(homeAction) toolBar.addWidget(self.pageLabel) self.webBrowser = QWebView() self.webBrowser.load(page) layout = QVBoxLayout() layout.addWidget(toolBar) layout.addWidget(self.webBrowser, 1) self.setLayout(layout) self.connect(backAction, Signal("triggered()"), self.webBrowser, Slot("backward()")) self.connect(homeAction, Signal("triggered()"), self.webBrowser, Slot("home()")) self.connect(self.webBrowser, Signal("sourceChanged(QUrl)"), self.updatePageTitle) self.resize(400, 600) self.setWindowTitle("{0} Help".format(QApplication.applicationName())) def updatePageTitle(self): self.pageLabel.setText(self.webBrowser.documentTitle()) if __name__ == '__main__': import doctest doctest.testmod()