From de89fc83ce1dbd358de9c487545d4cf3403241b6 Mon Sep 17 00:00:00 2001 From: Sebastianw Wehling-Benatelli Date: Thu, 2 Jun 2016 09:39:01 +0200 Subject: [PATCH 1/2] moved widget to utils widgets for consistency and reusability additionally the filter for PHASES and LOC files has been modified to avoid false selection --- QtPyLoT.py | 33 +++++++++++---------------------- pylot/core/util/widgets.py | 15 ++++++++++++++- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 9337fc53..5b0f5f31 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -53,7 +53,7 @@ from pylot.core.util.utils import fnConstructor, getLogin, \ getGlobalTimes from pylot.core.io.location import create_creation_info, create_event from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \ - MPLWidget, PropertiesDlg, HelpForm, createAction, PickDlg + MPLWidget, PropertiesDlg, HelpForm, createAction, PickDlg, getDataType from pylot.core.util.structure import DATASTRUCTURE from pylot.core.util.thread import AutoPickThread from pylot.core.util.version import get_git_version as _getVersionString @@ -389,43 +389,32 @@ class MainWindow(QMainWindow): settings = QSettings() return settings.value("data/dataRoot") - def getType(self): - type = QInputDialog().getItem(self, self.tr("Select phases type"), - self.tr("Type:"), [self.tr("manual"), - self.tr("automatic")]) - - if type[0].startswith('auto'): - type = 'auto' - else: - type = type[0] - - return type - def load_autopicks(self, fname=None): self.load_data(fname, type='auto') def load_loc(self, fname=None): - self.load_data(fname, type='loc') + type = getDataType(self) + self.load_data(fname, type=type, loc=True) def load_pilotevent(self): - filt = "PILOT location files (*.mat)" + filt = "PILOT location files (*LOC*.mat)" caption = "Select PILOT location file" fn_loc = QFileDialog().getOpenFileName(self, caption=caption, filter=filt, dir=self.getRoot()) fn_loc = fn_loc[0] loc_dir = os.path.split(fn_loc)[0] - filt = "PILOT phases files (*.mat)" + filt = "PILOT phases files (*PHASES*.mat)" caption = "Select PILOT phases file" fn_phases = QFileDialog().getOpenFileName(self, caption=caption, filter=filt, dir=loc_dir) fn_phases = fn_phases[0] - type = self.getType() + type = getDataType(self) fname_dict = dict(phasfn=fn_phases, locfn=fn_loc) self.load_data(fname_dict, type=type) - def load_data(self, fname=None, type='manual'): + def load_data(self, fname=None, type='manual', loc=False): if not self.okToContinue(): return if fname is None: @@ -435,7 +424,7 @@ class MainWindow(QMainWindow): self.set_fname(fname, type) data = dict(auto=self.autodata, manual=self.data) data[type] += Data(self, evtdata=fname) - if 'loc' not in type: + if not loc: self.updatePicks(type=type) self.drawPicks(picktype=type) self.draw() @@ -485,9 +474,9 @@ class MainWindow(QMainWindow): filt = "Supported file formats" \ " (*.mat *.qml *.xml *.kor *.evt)" caption = "Open an event file" - fname = QFileDialog().getOpenFileName(self, - caption=caption, - filter=filt) + fname = QFileDialog().getOpenFileName(self, caption=caption, + filter=filt, + dir=self.getRoot()) fname = fname[0] else: fname = str(action.data().toString()) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 8b0bdfaf..bf916aff 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -20,7 +20,8 @@ from matplotlib.widgets import MultiCursor from PySide.QtGui import QAction, QApplication, QComboBox, QDateTimeEdit, \ QDialog, QDialogButtonBox, QDoubleSpinBox, QGroupBox, QGridLayout, \ QIcon, QKeySequence, QLabel, QLineEdit, QMessageBox, QPixmap, QSpinBox, \ - QTabWidget, QToolBar, QVBoxLayout, QWidget, QPushButton, QFileDialog + QTabWidget, QToolBar, QVBoxLayout, QWidget, QPushButton, QFileDialog, \ + QInputDialog from PySide.QtCore import QSettings, Qt, QUrl, Signal, Slot from PySide.QtWebKit import QWebView from obspy import Stream, UTCDateTime @@ -33,6 +34,18 @@ from pylot.core.util.utils import prepTimeAxis, getGlobalTimes, scaleWFData, \ demeanTrace, isSorted, findComboBoxIndex +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 createAction(parent, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False): """ From 536019259e54341011933864a8edb7d62c744671 Mon Sep 17 00:00:00 2001 From: Sebastianw Wehling-Benatelli Date: Mon, 6 Jun 2016 14:10:46 +0200 Subject: [PATCH 2/2] [adresses 195] preparing GUI elements for a new dialog widget for interactive comparison --- QtPyLoT.py | 38 ++++++++++++++--- icons.qrc | 1 + icons/compare.png | Bin 0 -> 3108 bytes icons_rc.py | 8 ++-- inputs/autoPyLoT.in | 1 + pylot/core/pick/compare.py | 16 +++++-- pylot/core/util/widgets.py | 84 +++++++++++++++++++++++++++++++++++-- 7 files changed, 131 insertions(+), 17 deletions(-) create mode 100644 icons/compare.png diff --git a/QtPyLoT.py b/QtPyLoT.py index 5b0f5f31..e8709d0c 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -53,7 +53,7 @@ from pylot.core.util.utils import fnConstructor, getLogin, \ getGlobalTimes from pylot.core.io.location import create_creation_info, create_event from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \ - MPLWidget, PropertiesDlg, HelpForm, createAction, PickDlg, getDataType + WaveformWidget, PropertiesDlg, HelpForm, createAction, PickDlg, getDataType from pylot.core.util.structure import DATASTRUCTURE from pylot.core.util.thread import AutoPickThread from pylot.core.util.version import get_git_version as _getVersionString @@ -142,8 +142,8 @@ class MainWindow(QMainWindow): plottitle = "Overview: {0} components ".format(self.getComponent()) # create central matplotlib figure canvas widget - self.DataPlot = MPLWidget(parent=self, xlabel=xlab, ylabel=None, - title=plottitle) + self.DataPlot = WaveformWidget(parent=self, xlabel=xlab, ylabel=None, + title=plottitle) self.DataPlot.mpl_connect('button_press_event', self.pickOnStation) self.DataPlot.mpl_connect('axes_enter_event', @@ -178,6 +178,8 @@ class MainWindow(QMainWindow): auto_icon.addPixmap(QPixmap(':/icons/sync.png')) locate_icon = QIcon() locate_icon.addPixmap(QPixmap(':/icons/locate.png')) + compare_icon = QIcon() + compare_icon.addPixmap(QPixmap(':/icons/compare.png')) newEventAction = self.createAction(self, "&New event ...", self.createNewEvent, @@ -244,6 +246,12 @@ class MainWindow(QMainWindow): "Alt+S", s_icon, "Toggle S phase", True) + self.compare_action = self.createAction(self, "&Compare picks...", + self.comparePicks, "Alt+C", + compare_icon, "Comparison of " + "manual and " + "automatic pick " + "data.", False) printAction = self.createAction(self, "&Print event ...", self.printEvent, QKeySequence.Print, print_icon, @@ -318,7 +326,7 @@ class MainWindow(QMainWindow): ' displayed!') autoPickToolBar = self.addToolBar("autoPyLoT") - autoPickActions = (auto_pick,) + autoPickActions = (auto_pick, self.compare_action) self.addActions(autoPickToolBar, autoPickActions) # pickToolBar = self.addToolBar("PickTools") @@ -568,6 +576,10 @@ class MainWindow(QMainWindow): except KeyError: return None + def comparePicks(self): + if self.check4Comparison(): + compare_dlg = ComparisonDialog(self) + def getPlotWidget(self): return self.DataPlot @@ -828,6 +840,7 @@ class MainWindow(QMainWindow): self.picks.update(picks) elif type == 'auto': self.autopicks.update(picks) + self.check4Comparison() def drawPicks(self, station=None, picktype='manual'): # if picks to draw not specified, draw all picks available @@ -882,9 +895,22 @@ class MainWindow(QMainWindow): def check4Loc(self): return self.picksNum() > 4 - def picksNum(self): + def check4Comparison(self): + mpicks = self.getPicks() + apicks = self.getPicks('auto') + for station, phases in mpicks.items(): + try: + aphases = apicks[station] + for phase in phases.keys(): + if phase in aphases.keys(): + return True + except KeyError: + continue + return False + + def picksNum(self, type='manual'): num = 0 - for phases in self.getPicks().values(): + for phases in self.getPicks(type).values(): num += len(phases) return num diff --git a/icons.qrc b/icons.qrc index 8b2065fc..96b8126c 100644 --- a/icons.qrc +++ b/icons.qrc @@ -5,6 +5,7 @@ icons/locate.png icons/printer.png icons/delete.png + icons/compare.png icons/key_E.png icons/key_N.png icons/key_P.png diff --git a/icons/compare.png b/icons/compare.png new file mode 100644 index 0000000000000000000000000000000000000000..be28ca746ce1746a285f3c01f03674928775e3e6 GIT binary patch literal 3108 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 everything AUTOPHASES_AIC_HOS4_ARH #phasefile# %name of autoPILOT output phase file diff --git a/pylot/core/pick/compare.py b/pylot/core/pick/compare.py index 1a828c2a..d246be67 100644 --- a/pylot/core/pick/compare.py +++ b/pylot/core/pick/compare.py @@ -29,7 +29,10 @@ class Comparison(object): names = list() self._pdfs = dict() for name, fn in kwargs.items(): - self._pdfs[name] = PDFDictionary.from_quakeml(fn) + if not isinstance(PDFDictionary, fn): + self._pdfs[name] = PDFDictionary.from_quakeml(fn) + else: + self._pdfs[name] = fn names.append(name) if len(names) > 2: raise ValueError('Comparison is only defined for two ' @@ -101,14 +104,19 @@ class Comparison(object): return compare_pdfs - def plot(self): - nstations = self.nstations - stations = self.stations + def plot(self, stations=None): + if stations is None: + nstations = self.nstations + stations = self.stations + else: + nstations = len(stations) istations = range(nstations) fig, axarr = plt.subplots(nstations, 2, sharex='col', sharey='row') for n in istations: station = stations[n] + if station not in self.comparison.keys(): + continue compare_pdf = self.comparison[station] for l, phase in enumerate(compare_pdf.keys()): axarr[n, l].plot(compare_pdf[phase].axis, diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index bf916aff..0b30c0c8 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -64,8 +64,86 @@ def createAction(parent, text, slot=None, shortcut=None, icon=None, action.setCheckable(True) return action +class ComparsionDialog(QDialog): + def __init__(self, c, parent=None): + self._data = c + self._stats = c.keys() + self._canvas = PlotWidget(parent) + super(ComparsionDialog, self).__init__(parent) + self -class MPLWidget(FigureCanvas): + def setupUI(self): + pass + + @property + def canvas(self): + return self._canvas + + @property + def stations(self): + return self._stats + + @stations.setter + def stations(self, stations): + self._stats = stations + + @property + def data(self): + return self._data + + @data.setter + def data(self, data): + self.stations = data.keys() + self._data = data + + +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 @@ -79,7 +157,7 @@ class MPLWidget(FigureCanvas): # clear axes each time plot is called self.axes.hold(True) # initialize super class - super(MPLWidget, self).__init__(self.figure) + super(WaveformWidget, self).__init__(self.figure) # add an cursor for station selection self.multiCursor = MultiCursor(self.figure.canvas, (self.axes,), horizOn=True, @@ -223,7 +301,7 @@ class PickDlg(QDialog): self.stime, self.etime = getGlobalTimes(self.getWFData()) # initialize plotting widget - self.multicompfig = MPLWidget(self) + self.multicompfig = WaveformWidget(self) # setup ui self.setupUi()