added first project structure and event lists (testing needed)

This commit is contained in:
Marcel Paffrath 2017-04-18 16:24:26 +02:00
parent 3092b4f657
commit 62876dd01d
3 changed files with 275 additions and 35 deletions

View File

@ -33,9 +33,10 @@ matplotlib.rcParams['backend.qt4'] = 'PySide'
from PySide.QtCore import QCoreApplication, QSettings, Signal, QFile, \ from PySide.QtCore import QCoreApplication, QSettings, Signal, QFile, \
QFileInfo, Qt, QSize QFileInfo, Qt, QSize
from PySide.QtGui import QMainWindow, QInputDialog, QIcon, QFileDialog, \ from PySide.QtGui import QMainWindow, QInputDialog, QIcon, QFileDialog, \
QWidget, QHBoxLayout, QStyle, QKeySequence, QLabel, QFrame, QAction, \ QWidget, QHBoxLayout, QVBoxLayout, QStyle, QKeySequence, QLabel, QFrame, QAction, \
QDialog, QErrorMessage, QApplication, QPixmap, QMessageBox, QSplashScreen, \ QDialog, QErrorMessage, QApplication, QPixmap, QMessageBox, QSplashScreen, \
QActionGroup, QListWidget, QDockWidget, QLineEdit QActionGroup, QListWidget, QDockWidget, QLineEdit, QListView, QAbstractItemView, \
QTreeView, QComboBox
import numpy as np import numpy as np
from obspy import UTCDateTime from obspy import UTCDateTime
@ -60,7 +61,7 @@ from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \
getDataType, ComparisonDialog getDataType, ComparisonDialog
from pylot.core.util.map_projection import map_projection from pylot.core.util.map_projection import map_projection
from pylot.core.util.structure import DATASTRUCTURE from pylot.core.util.structure import DATASTRUCTURE
from pylot.core.util.thread import AutoPickThread from pylot.core.util.thread import AutoPickThread, Thread
from pylot.core.util.version import get_git_version as _getVersionString from pylot.core.util.version import get_git_version as _getVersionString
import icons_rc import icons_rc
@ -121,6 +122,7 @@ class MainWindow(QMainWindow):
self.autopicks = {} self.autopicks = {}
self.loc = False self.loc = False
self._metadata = None self._metadata = None
self.project = None
self.array_map = None self.array_map = None
@ -152,8 +154,19 @@ class MainWindow(QMainWindow):
_widget = QWidget() _widget = QWidget()
_widget.setCursor(Qt.CrossCursor) _widget.setCursor(Qt.CrossCursor)
_layout = QHBoxLayout() _layout = QVBoxLayout()
# add event combo box
self.eventBox = QComboBox()
self.eventBox.setMaxVisibleItems(30)
self.eventBox.setEnabled(False)
_event_layout = QHBoxLayout()
_event_layout.addWidget(QLabel('Event: '))
_event_layout.addWidget(self.eventBox)
_event_layout.setStretch(1,1) #set stretch of item 1 to 1
_layout.addLayout(_event_layout)
self.eventBox.activated.connect(self.loadWaveformDataThread)
plottitle = "Overview: {0} components ".format(self.getComponent()) plottitle = "Overview: {0} components ".format(self.getComponent())
# create central matplotlib figure canvas widget # create central matplotlib figure canvas widget
@ -167,9 +180,11 @@ class MainWindow(QMainWindow):
quitIcon = self.style().standardIcon(QStyle.SP_MediaStop) quitIcon = self.style().standardIcon(QStyle.SP_MediaStop)
saveIcon = self.style().standardIcon(QStyle.SP_DriveHDIcon) saveIcon = self.style().standardIcon(QStyle.SP_DriveHDIcon)
openIcon = self.style().standardIcon(QStyle.SP_DirOpenIcon)
helpIcon = self.style().standardIcon(QStyle.SP_DialogHelpButton) helpIcon = self.style().standardIcon(QStyle.SP_DialogHelpButton)
newIcon = self.style().standardIcon(QStyle.SP_FileIcon) newIcon = self.style().standardIcon(QStyle.SP_FileIcon)
newFolderIcon = self.style().standardIcon(QStyle.SP_FileDialogNewFolder)
# create resource icons # create resource icons
locactionicon = QIcon() locactionicon = QIcon()
locactionicon.addPixmap(QPixmap(':/icons/locactionicon.png')) locactionicon.addPixmap(QPixmap(':/icons/locactionicon.png'))
@ -199,10 +214,24 @@ class MainWindow(QMainWindow):
locate_icon.addPixmap(QPixmap(':/icons/locate_button.png')) locate_icon.addPixmap(QPixmap(':/icons/locate_button.png'))
compare_icon = QIcon() compare_icon = QIcon()
compare_icon.addPixmap(QPixmap(':/icons/compare_button.png')) compare_icon.addPixmap(QPixmap(':/icons/compare_button.png'))
newEventAction = self.createAction(self, "&New event ...", self.newProjectAction = self.createAction(self, "&New project ...",
self.createNewEvent, self.createNewProject,
QKeySequence.New, newIcon, QKeySequence.New, newIcon,
"Create a new event.") "Create a new Project.")
self.openProjectAction = self.createAction(self, "Load project ...",
self.loadProject,
QKeySequence.Open,
openIcon,
"Load project file")
self.saveProjectAction = self.createAction(self, "Save project ...",
self.saveProject,
QKeySequence.Save,
saveIcon,
"Save project file")
# newEventAction = self.createAction(self, "&New event ...",
# self.createNewEvent,
# QKeySequence.New, newIcon,
# "Create a new event.")
self.openmanualpicksaction = self.createAction(self, "Load &picks ...", self.openmanualpicksaction = self.createAction(self, "Load &picks ...",
self.load_data, self.load_data,
QKeySequence.Open, QKeySequence.Open,
@ -240,11 +269,10 @@ class MainWindow(QMainWindow):
saveIcon, "Save actual event data.") saveIcon, "Save actual event data.")
self.saveEventAction.setEnabled(False) self.saveEventAction.setEnabled(False)
openWFDataAction = self.createAction(self, "Open &waveforms ...", self.addEventDataAction = self.createAction(self, "Add &events ...",
self.loadWaveformData, self.add_events,
"Ctrl+W", QIcon(":/wfIcon.png"), "Ctrl+W", newFolderIcon,
"Open waveform data (event will " "Add event data")
"be closed)")
prefsEventAction = self.createAction(self, "Preferences", prefsEventAction = self.createAction(self, "Preferences",
self.PyLoTprefs, self.PyLoTprefs,
QKeySequence.Preferences, QKeySequence.Preferences,
@ -290,8 +318,9 @@ class MainWindow(QMainWindow):
homepage (internet connection available), homepage (internet connection available),
or shipped documentation files.""") or shipped documentation files.""")
self.fileMenu = self.menuBar().addMenu('&File') self.fileMenu = self.menuBar().addMenu('&File')
self.fileMenuActions = (newEventAction, self.openmanualpicksaction, self.fileMenuActions = (self.newProjectAction, self.addEventDataAction,
self.saveEventAction, openWFDataAction, None, self.openProjectAction, self.saveProjectAction,
self.openmanualpicksaction, self.saveEventAction, None,
prefsEventAction, quitAction) prefsEventAction, quitAction)
self.fileMenu.aboutToShow.connect(self.updateFileMenu) self.fileMenu.aboutToShow.connect(self.updateFileMenu)
self.updateFileMenu() self.updateFileMenu()
@ -307,7 +336,9 @@ class MainWindow(QMainWindow):
self.addActions(self.helpMenu, helpActions) self.addActions(self.helpMenu, helpActions)
fileToolBar = self.addToolBar("FileTools") fileToolBar = self.addToolBar("FileTools")
fileToolActions = (newEventAction, self.openmanualpicksaction, fileToolActions = (self.newProjectAction, self.addEventDataAction,
self.openProjectAction, self.saveProjectAction,
self.openmanualpicksaction,
self.openautopicksaction, loadlocationaction, self.openautopicksaction, loadlocationaction,
self.loadpilotevent, self.saveEventAction) self.loadpilotevent, self.saveEventAction)
fileToolBar.setObjectName("FileTools") fileToolBar.setObjectName("FileTools")
@ -523,6 +554,50 @@ class MainWindow(QMainWindow):
else: else:
return return
def getWFFnames_from_eventlist(self):
if self.dataStructure:
searchPath = self.dataStructure.expandDataPath()
directory = self.eventBox.currentText()
self.fnames = [os.path.join(directory, f) for f in os.listdir(directory)]
else:
raise DatastructureError('not specified')
if not self.fnames:
return None
return self.fnames
def add_events(self):
if not self.project:
self.project = Project()
ed = getExistingDirectories(self, 'Select event directories...')
if ed.exec_():
eventlist = ed.selectedFiles()
# select only folders that start with 'e', containin two dots and have length 12
eventlist = [item for item in eventlist if item.split('/')[-1].startswith('e')
and len(item.split('/')[-1].split('.')) == 3
and len(item.split('/')[-1]) == 12]
else:
return
if not self.project:
print('No project found.')
return
self.project.add_eventlist(eventlist)
self.init_events()
def init_events(self, new=False):
nitems = self.eventBox.count()
self.eventBox.clear()
if len(self.project.eventlist) == 0:
print('No events to init.')
return
self.eventBox.setEnabled(True)
for event in self.project.eventlist:
self.eventBox.addItem(event)
if new:
self.eventBox.setCurrentIndex(0)
else:
self.eventBox.setCurrentIndex(nitems)
self.loadWaveformDataThread()
def filename_from_action(self, action): def filename_from_action(self, action):
if action.data() is None: if action.data() is None:
filt = "Supported file formats" \ filt = "Supported file formats" \
@ -687,15 +762,23 @@ class MainWindow(QMainWindow):
return self.saveData() return self.saveData()
return True return True
def loadWaveformDataThread(self):
wfd_thread = Thread(self, self.loadWaveformData, 'Reading data input...')
wfd_thread.finished.connect(self.plotWaveformDataThread)
wfd_thread.start()
def loadWaveformData(self): def loadWaveformData(self):
if self.fnames and self.okToContinue(): # if self.fnames and self.okToContinue():
self.setDirty(True) # self.setDirty(True)
ans = self.data.setWFData(self.fnames) # ans = self.data.setWFData(self.fnames)
elif self.fnames is None and self.okToContinue(): # elif self.fnames is None and self.okToContinue():
ans = self.data.setWFData(self.getWFFnames()) # ans = self.data.setWFData(self.getWFFnames())
else: # else:
ans = False # ans = False
self.data.setWFData(self.getWFFnames_from_eventlist())
self._stime = full_range(self.get_data().getWFData())[0] self._stime = full_range(self.get_data().getWFData())[0]
def finishWaveformDataPlot(self):
self.auto_pick.setEnabled(True) self.auto_pick.setEnabled(True)
self.z_action.setEnabled(True) self.z_action.setEnabled(True)
self.e_action.setEnabled(True) self.e_action.setEnabled(True)
@ -704,12 +787,13 @@ class MainWindow(QMainWindow):
self.openautopicksaction.setEnabled(True) self.openautopicksaction.setEnabled(True)
self.loadpilotevent.setEnabled(True) self.loadpilotevent.setEnabled(True)
self.saveEventAction.setEnabled(True) self.saveEventAction.setEnabled(True)
if ans: self.draw()
self.plotWaveformData()
return ans
else:
return ans
def plotWaveformDataThread(self):
wfp_thread = Thread(self, self.plotWaveformData, 'Plotting waveform data...')
wfp_thread.finished.connect(self.finishWaveformDataPlot)
wfp_thread.start()
def plotWaveformData(self): def plotWaveformData(self):
zne_text = {'Z': 'vertical', 'N': 'north-south', 'E': 'east-west'} zne_text = {'Z': 'vertical', 'N': 'north-south', 'E': 'east-west'}
comp = self.getComponent() comp = self.getComponent()
@ -718,7 +802,6 @@ class MainWindow(QMainWindow):
wfst = self.get_data().getWFData().select(component=comp) wfst = self.get_data().getWFData().select(component=comp)
wfst += self.get_data().getWFData().select(component=alter_comp) wfst += self.get_data().getWFData().select(component=alter_comp)
self.getPlotWidget().plotWFData(wfdata=wfst, title=title, mapping=False) self.getPlotWidget().plotWFData(wfdata=wfst, title=title, mapping=False)
self.draw()
plotDict = self.getPlotWidget().getPlotDict() plotDict = self.getPlotWidget().getPlotDict()
pos = plotDict.keys() pos = plotDict.keys()
labels = [plotDict[n][0] for n in pos] labels = [plotDict[n][0] for n in pos]
@ -726,19 +809,19 @@ class MainWindow(QMainWindow):
def plotZ(self): def plotZ(self):
self.setComponent('Z') self.setComponent('Z')
self.plotWaveformData() self.plotWaveformDataThread()
self.drawPicks() self.drawPicks()
self.draw() self.draw()
def plotN(self): def plotN(self):
self.setComponent('N') self.setComponent('N')
self.plotWaveformData() self.plotWaveformDataThread()
self.drawPicks() self.drawPicks()
self.draw() self.draw()
def plotE(self): def plotE(self):
self.setComponent('E') self.setComponent('E')
self.plotWaveformData() self.plotWaveformDataThread()
self.drawPicks() self.drawPicks()
self.draw() self.draw()
@ -1142,7 +1225,7 @@ class MainWindow(QMainWindow):
self.setWindowTitle( self.setWindowTitle(
"PyLoT - processing event %s[*]" % self.get_data().getID()) "PyLoT - processing event %s[*]" % self.get_data().getID())
elif self.get_data().isNew(): elif self.get_data().isNew():
self.setWindowTitle("PyLoT - New event [*]") self.setWindowTitle("PyLoT - New project [*]")
else: else:
self.setWindowTitle( self.setWindowTitle(
"PyLoT - seismic processing the python way[*]") "PyLoT - seismic processing the python way[*]")
@ -1164,6 +1247,50 @@ class MainWindow(QMainWindow):
self.data = Data(self, evtdata=event) self.data = Data(self, evtdata=event)
self.setDirty(True) self.setDirty(True)
def createNewProject(self, exists=False):
if self.okToContinue():
dlg = QFileDialog()
fnm = dlg.getSaveFileName(self, 'Create a new project file...', filter='Pylot project (*.plp)')
filename = fnm[0]
if not filename.split('.')[-1] == 'plp':
filename = fnm[0] + '.plp'
if not exists:
self.project = Project()
self.project.save(filename)
def loadProject(self):
if self.project:
if self.project.dirty:
qmb = QMessageBox(icon=QMessageBox.Question, text='Save changes in current project?')
qmb.setStandardButtons(QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
qmb.setDefaultButton(QMessageBox.Yes)
if qmb.exec_() == 16384:
self.saveProject()
elif qmb.exec_() == 65536:
pass
elif qmb.exec_() == 4194304:
return
dlg = QFileDialog()
fnm = dlg.getOpenFileName(self, 'Open project file...', filter='Pylot project (*.plp)')
if fnm[0]:
self.project = Project.load(fnm[0])
self.init_events(new=True)
def saveProject(self):
if self.project:
self.project.save()
if not self.project.dirty:
qmb = QMessageBox(icon=QMessageBox.Information, text='Saved back project to file:\n{}'.format(self.project.location))
qmb.exec_()
return
else:
# if still dirty because saving failed
qmb = QMessageBox(icon=QMessageBox.Warning, text='Could not save back to original file.\n'
'Choose new file')
qmb.setStandardButtons(QMessageBox.Ok)
qmb.exec_()
self.createNewProject(exists=True)
def draw(self): def draw(self):
self.getPlotWidget().draw() self.getPlotWidget().draw()
@ -1189,6 +1316,82 @@ class MainWindow(QMainWindow):
form.show() form.show()
class Project(object):
'''
Pickable class containing information of a QtPyLoT project, like event lists and file locations.
'''
def __init__(self):
self.eventlist = []
self.location = None
self.dirty = False
def add_eventlist(self, eventlist):
if len(eventlist) == 0:
return
for item in eventlist:
if not item in self.eventlist:
self.eventlist.append(item)
self.setDirty()
def setDirty(self):
self.dirty = True
def setClean(self):
self.dirty = False
def save(self, filename=None):
'''
Save PyLoT Project to a file.
Can be loaded by using project.load(filename).
'''
try:
import cPickle
except ImportError:
import _pickle as cPickle
if filename:
self.location = filename
else:
filename = self.location
try:
outfile = open(filename, 'wb')
cPickle.dump(self, outfile, -1)
self.setClean()
except Exception as e:
print('Could not pickle PyLoT project. Reason: {}'.format(e))
self.setDirty()
@staticmethod
def load(filename):
try:
import cPickle
except ImportError:
import _pickle as cPickle
infile = open(filename, 'rb')
project = cPickle.load(infile)
print('Loaded %s' % filename)
return project
class event(object):
'''
Pickable class containing information on a single event.
'''
def __init__(self):
self.eventID = None
class getExistingDirectories(QFileDialog):
def __init__(self, *args):
super(getExistingDirectories, self).__init__(*args)
self.setOption(self.DontUseNativeDialog, True)
self.setFileMode(self.Directory)
self.setOption(self.ShowDirsOnly, True)
self.findChildren(QListView)[0].setSelectionMode(QAbstractItemView.ExtendedSelection)
self.findChildren(QTreeView)[0].setSelectionMode(QAbstractItemView.ExtendedSelection)
def create_window(): def create_window():
app_created = False app_created = False
app = QCoreApplication.instance() app = QCoreApplication.instance()

View File

@ -1 +1 @@
de38-dirty 3092-dirty

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys import sys
from PySide.QtCore import QThread, Signal from PySide.QtCore import QThread, Signal, Qt
from PySide.QtGui import QDialog, QProgressBar, QLabel, QVBoxLayout
class AutoPickThread(QThread): class AutoPickThread(QThread):
@ -35,3 +36,39 @@ class AutoPickThread(QThread):
def flush(self): def flush(self):
pass pass
class Thread(QThread):
def __init__(self, parent, func, progressText = None):
QThread.__init__(self, parent)
self.func = func
self.progressText = progressText
self.pbdlg = None
self.finished.connect(self.hideProgressbar)
self.showProgressbar()
def run(self):
self.func()
def __del__(self):
self.wait()
def showProgressbar(self):
if self.progressText:
self.pbdlg = QDialog(self.parent())
self.pbdlg.setModal(True)
vl = QVBoxLayout()
pb = QProgressBar()
pb.setRange(0, 0)
vl.addWidget(pb)
vl.addWidget(QLabel(self.progressText))
self.pbdlg.setLayout(vl)
self.pbdlg.show()
self.pbdlg.setWindowFlags(Qt.FramelessWindowHint)
self.pbdlg.show()
def hideProgressbar(self):
if self.pbdlg:
self.pbdlg.hide()