refactor: move Project definition to individual file
This commit is contained in:
parent
72f021cdc1
commit
090bfb47d1
183
PyLoT.py
183
PyLoT.py
@ -25,7 +25,6 @@ https://www.iconfinder.com/iconsets/flavour
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
import logging
|
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import shutil
|
import shutil
|
||||||
@ -48,7 +47,6 @@ from PySide2.QtWidgets import QMainWindow, QInputDialog, QFileDialog, \
|
|||||||
QTreeView, QComboBox, QTabWidget, QPushButton, QGridLayout, QTableWidgetItem, QTableWidget
|
QTreeView, QComboBox, QTabWidget, QPushButton, QGridLayout, QTableWidgetItem, QTableWidget
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from obspy import UTCDateTime, Stream
|
from obspy import UTCDateTime, Stream
|
||||||
from obspy.core.event import Magnitude, Origin
|
|
||||||
from obspy.core.util import AttribDict
|
from obspy.core.util import AttribDict
|
||||||
|
|
||||||
from pylot.core.util.obspyDMT_interface import check_obspydmt_structure
|
from pylot.core.util.obspyDMT_interface import check_obspydmt_structure
|
||||||
@ -68,6 +66,7 @@ from autoPyLoT import autoPyLoT
|
|||||||
from pylot.core.pick.compare import Comparison
|
from pylot.core.pick.compare import Comparison
|
||||||
from pylot.core.pick.utils import getQualityFromUncertainty
|
from pylot.core.pick.utils import getQualityFromUncertainty
|
||||||
from pylot.core.io.phases import picksdict_from_picks
|
from pylot.core.io.phases import picksdict_from_picks
|
||||||
|
from pylot.core.io.project import Project
|
||||||
import pylot.core.loc.nll as nll
|
import pylot.core.loc.nll as nll
|
||||||
from pylot.core.util.errors import DatastructureError, \
|
from pylot.core.util.errors import DatastructureError, \
|
||||||
OverwriteError
|
OverwriteError
|
||||||
@ -79,10 +78,7 @@ from pylot.core.util.utils import fnConstructor, get_login, \
|
|||||||
transform_colors_mpl, transform_colors_mpl_str, getAutoFilteroptions, check_all_obspy, \
|
transform_colors_mpl, transform_colors_mpl_str, getAutoFilteroptions, check_all_obspy, \
|
||||||
check_all_pylot, get_bool, get_none
|
check_all_pylot, get_bool, get_none
|
||||||
from pylot.core.util.gui import make_pen
|
from pylot.core.util.gui import make_pen
|
||||||
from pylot.core.util.event import Event
|
from pylot.core.util.widgets import FilterOptionsDialog, PylotCanvas, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \
|
||||||
from pylot.core.io.location import create_creation_info, create_event
|
|
||||||
from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \
|
|
||||||
PylotCanvas, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \
|
|
||||||
ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \
|
ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \
|
||||||
CompareEventsWidget, ProgressBarWidget, AddMetadataWidget, SingleTextLineDialog, LogWidget, PickQualitiesFromXml, \
|
CompareEventsWidget, ProgressBarWidget, AddMetadataWidget, SingleTextLineDialog, LogWidget, PickQualitiesFromXml, \
|
||||||
SpectrogramTab, SearchFileByExtensionDialog
|
SpectrogramTab, SearchFileByExtensionDialog
|
||||||
@ -3751,181 +3747,6 @@ class MainWindow(QMainWindow):
|
|||||||
form = HelpForm(self, ':/help.html')
|
form = HelpForm(self, ':/help.html')
|
||||||
form.show()
|
form.show()
|
||||||
|
|
||||||
|
|
||||||
class Project(object):
|
|
||||||
'''
|
|
||||||
Pickable class containing information of a PyLoT project, like event lists and file locations.
|
|
||||||
'''
|
|
||||||
|
|
||||||
# TODO: remove rootpath
|
|
||||||
def __init__(self):
|
|
||||||
self.eventlist = []
|
|
||||||
self.location = None
|
|
||||||
self.rootpath = None
|
|
||||||
self.datapath = None
|
|
||||||
self.dirty = False
|
|
||||||
self.parameter = None
|
|
||||||
self._table = None
|
|
||||||
|
|
||||||
def add_eventlist(self, eventlist):
|
|
||||||
'''
|
|
||||||
Add events from an eventlist containing paths to event directories.
|
|
||||||
Will skip existing paths.
|
|
||||||
'''
|
|
||||||
if len(eventlist) == 0:
|
|
||||||
return
|
|
||||||
for item in eventlist:
|
|
||||||
event = Event(item)
|
|
||||||
event.rootpath = self.parameter['rootpath']
|
|
||||||
event.database = self.parameter['database']
|
|
||||||
event.datapath = self.parameter['datapath']
|
|
||||||
if not event.path in self.getPaths():
|
|
||||||
self.eventlist.append(event)
|
|
||||||
self.setDirty()
|
|
||||||
else:
|
|
||||||
print('Skipping event with path {}. Already part of project.'.format(event.path))
|
|
||||||
self.eventlist.sort(key=lambda x: x.pylot_id)
|
|
||||||
self.search_eventfile_info()
|
|
||||||
|
|
||||||
def remove_event(self, event):
|
|
||||||
self.eventlist.remove(event)
|
|
||||||
|
|
||||||
def remove_event_by_id(self, eventID):
|
|
||||||
for event in self.eventlist:
|
|
||||||
if eventID in str(event.resource_id):
|
|
||||||
self.remove_event(event)
|
|
||||||
break
|
|
||||||
|
|
||||||
def read_eventfile_info(self, filename, separator=','):
|
|
||||||
'''
|
|
||||||
Try to read event information from file (:param:filename) comparing specific event datetimes.
|
|
||||||
File structure (each row): event, date, time, magnitude, latitude, longitude, depth
|
|
||||||
separated by :param:separator each.
|
|
||||||
'''
|
|
||||||
with open(filename, 'r') as infile:
|
|
||||||
for line in infile.readlines():
|
|
||||||
eventID, date, time, mag, lat, lon, depth = line.split(separator)[:7]
|
|
||||||
# skip first line
|
|
||||||
try:
|
|
||||||
day, month, year = date.split('/')
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
year = int(year)
|
|
||||||
# hardcoded, if year only consists of 2 digits (e.g. 16 instead of 2016)
|
|
||||||
if year < 100:
|
|
||||||
year += 2000
|
|
||||||
datetime = '{}-{}-{}T{}'.format(year, month, day, time)
|
|
||||||
try:
|
|
||||||
datetime = UTCDateTime(datetime)
|
|
||||||
except Exception as e:
|
|
||||||
print(e, datetime, filename)
|
|
||||||
continue
|
|
||||||
for event in self.eventlist:
|
|
||||||
if eventID in str(event.resource_id) or eventID in event.origins:
|
|
||||||
if event.origins:
|
|
||||||
origin = event.origins[0] # should have only one origin
|
|
||||||
if origin.time == datetime:
|
|
||||||
origin.latitude = float(lat)
|
|
||||||
origin.longitude = float(lon)
|
|
||||||
origin.depth = float(depth)
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
elif not event.origins:
|
|
||||||
origin = Origin(resource_id=event.resource_id,
|
|
||||||
time=datetime, latitude=float(lat),
|
|
||||||
longitude=float(lon), depth=float(depth))
|
|
||||||
event.origins.append(origin)
|
|
||||||
event.magnitudes.append(Magnitude(resource_id=event.resource_id,
|
|
||||||
mag=float(mag),
|
|
||||||
mag_type='M'))
|
|
||||||
break
|
|
||||||
|
|
||||||
def search_eventfile_info(self):
|
|
||||||
'''
|
|
||||||
Search all datapaths in rootpath for filenames with given file extension fext
|
|
||||||
and try to read event info from it
|
|
||||||
'''
|
|
||||||
datapaths = []
|
|
||||||
fext = '.csv'
|
|
||||||
for event in self.eventlist:
|
|
||||||
if not event.datapath in datapaths:
|
|
||||||
datapaths.append(event.datapath)
|
|
||||||
for datapath in datapaths:
|
|
||||||
# datapath = os.path.join(self.rootpath, datapath)
|
|
||||||
if os.path.isdir(datapath):
|
|
||||||
for filename in os.listdir(datapath):
|
|
||||||
filename = os.path.join(datapath, filename)
|
|
||||||
if os.path.isfile(filename) and filename.endswith(fext):
|
|
||||||
try:
|
|
||||||
self.read_eventfile_info(filename)
|
|
||||||
except Exception as e:
|
|
||||||
print('Failed on reading eventfile info from file {}: {}'.format(filename, e))
|
|
||||||
else:
|
|
||||||
print("Directory %s does not exist!" % datapath)
|
|
||||||
|
|
||||||
def getPaths(self):
|
|
||||||
'''
|
|
||||||
Returns paths (eventlist) of all events saved in the project.
|
|
||||||
'''
|
|
||||||
paths = []
|
|
||||||
for event in self.eventlist:
|
|
||||||
paths.append(event.path)
|
|
||||||
return paths
|
|
||||||
|
|
||||||
def setDirty(self, value=True):
|
|
||||||
self.dirty = value
|
|
||||||
|
|
||||||
def getEventFromPath(self, path):
|
|
||||||
'''
|
|
||||||
Search for an event in the project by event path.
|
|
||||||
'''
|
|
||||||
for event in self.eventlist:
|
|
||||||
if event.path == path:
|
|
||||||
return event
|
|
||||||
|
|
||||||
def save(self, filename=None):
|
|
||||||
'''
|
|
||||||
Save PyLoT Project to a file.
|
|
||||||
Can be loaded by using project.load(filename).
|
|
||||||
'''
|
|
||||||
try:
|
|
||||||
import pickle
|
|
||||||
except ImportError:
|
|
||||||
import _pickle as pickle
|
|
||||||
|
|
||||||
if filename:
|
|
||||||
self.location = filename
|
|
||||||
else:
|
|
||||||
filename = self.location
|
|
||||||
|
|
||||||
table = self._table # MP: see below
|
|
||||||
try:
|
|
||||||
outfile = open(filename, 'wb')
|
|
||||||
self._table = [] # MP: Workaround as long as table cannot be saved as part of project
|
|
||||||
pickle.dump(self, outfile, protocol=pickle.HIGHEST_PROTOCOL)
|
|
||||||
self.setDirty(False)
|
|
||||||
self._table = table # MP: see above
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
print('Could not pickle PyLoT project. Reason: {}'.format(e))
|
|
||||||
self.setDirty()
|
|
||||||
self._table = table # MP: see above
|
|
||||||
return False
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def load(filename):
|
|
||||||
'''
|
|
||||||
Load project from filename.
|
|
||||||
'''
|
|
||||||
import pickle
|
|
||||||
infile = open(filename, 'rb')
|
|
||||||
project = pickle.load(infile)
|
|
||||||
infile.close()
|
|
||||||
project.location = filename
|
|
||||||
print('Loaded %s' % filename)
|
|
||||||
return project
|
|
||||||
|
|
||||||
|
|
||||||
class GetExistingDirectories(QFileDialog):
|
class GetExistingDirectories(QFileDialog):
|
||||||
'''
|
'''
|
||||||
File dialog with possibility to select multiple folders.
|
File dialog with possibility to select multiple folders.
|
||||||
|
177
pylot/core/io/project.py
Normal file
177
pylot/core/io/project.py
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from pylot.core.util.event import Event
|
||||||
|
|
||||||
|
|
||||||
|
class Project(object):
|
||||||
|
'''
|
||||||
|
Pickable class containing information of a PyLoT project, like event lists and file locations.
|
||||||
|
'''
|
||||||
|
|
||||||
|
# TODO: remove rootpath
|
||||||
|
def __init__(self):
|
||||||
|
self.eventlist = []
|
||||||
|
self.location = None
|
||||||
|
self.rootpath = None
|
||||||
|
self.datapath = None
|
||||||
|
self.dirty = False
|
||||||
|
self.parameter = None
|
||||||
|
self._table = None
|
||||||
|
|
||||||
|
def add_eventlist(self, eventlist):
|
||||||
|
'''
|
||||||
|
Add events from an eventlist containing paths to event directories.
|
||||||
|
Will skip existing paths.
|
||||||
|
'''
|
||||||
|
if len(eventlist) == 0:
|
||||||
|
return
|
||||||
|
for item in eventlist:
|
||||||
|
event = Event(item)
|
||||||
|
event.rootpath = self.parameter['rootpath']
|
||||||
|
event.database = self.parameter['database']
|
||||||
|
event.datapath = self.parameter['datapath']
|
||||||
|
if not event.path in self.getPaths():
|
||||||
|
self.eventlist.append(event)
|
||||||
|
self.setDirty()
|
||||||
|
else:
|
||||||
|
print('Skipping event with path {}. Already part of project.'.format(event.path))
|
||||||
|
self.eventlist.sort(key=lambda x: x.pylot_id)
|
||||||
|
self.search_eventfile_info()
|
||||||
|
|
||||||
|
def remove_event(self, event):
|
||||||
|
self.eventlist.remove(event)
|
||||||
|
|
||||||
|
def remove_event_by_id(self, eventID):
|
||||||
|
for event in self.eventlist:
|
||||||
|
if eventID in str(event.resource_id):
|
||||||
|
self.remove_event(event)
|
||||||
|
break
|
||||||
|
|
||||||
|
def read_eventfile_info(self, filename, separator=','):
|
||||||
|
'''
|
||||||
|
Try to read event information from file (:param:filename) comparing specific event datetimes.
|
||||||
|
File structure (each row): event, date, time, magnitude, latitude, longitude, depth
|
||||||
|
separated by :param:separator each.
|
||||||
|
'''
|
||||||
|
with open(filename, 'r') as infile:
|
||||||
|
for line in infile.readlines():
|
||||||
|
eventID, date, time, mag, lat, lon, depth = line.split(separator)[:7]
|
||||||
|
# skip first line
|
||||||
|
try:
|
||||||
|
day, month, year = date.split('/')
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
year = int(year)
|
||||||
|
# hardcoded, if year only consists of 2 digits (e.g. 16 instead of 2016)
|
||||||
|
if year < 100:
|
||||||
|
year += 2000
|
||||||
|
datetime = '{}-{}-{}T{}'.format(year, month, day, time)
|
||||||
|
try:
|
||||||
|
datetime = UTCDateTime(datetime)
|
||||||
|
except Exception as e:
|
||||||
|
print(e, datetime, filename)
|
||||||
|
continue
|
||||||
|
for event in self.eventlist:
|
||||||
|
if eventID in str(event.resource_id) or eventID in event.origins:
|
||||||
|
if event.origins:
|
||||||
|
origin = event.origins[0] # should have only one origin
|
||||||
|
if origin.time == datetime:
|
||||||
|
origin.latitude = float(lat)
|
||||||
|
origin.longitude = float(lon)
|
||||||
|
origin.depth = float(depth)
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
elif not event.origins:
|
||||||
|
origin = Origin(resource_id=event.resource_id,
|
||||||
|
time=datetime, latitude=float(lat),
|
||||||
|
longitude=float(lon), depth=float(depth))
|
||||||
|
event.origins.append(origin)
|
||||||
|
event.magnitudes.append(Magnitude(resource_id=event.resource_id,
|
||||||
|
mag=float(mag),
|
||||||
|
mag_type='M'))
|
||||||
|
break
|
||||||
|
|
||||||
|
def search_eventfile_info(self):
|
||||||
|
'''
|
||||||
|
Search all datapaths in rootpath for filenames with given file extension fext
|
||||||
|
and try to read event info from it
|
||||||
|
'''
|
||||||
|
datapaths = []
|
||||||
|
fext = '.csv'
|
||||||
|
for event in self.eventlist:
|
||||||
|
if not event.datapath in datapaths:
|
||||||
|
datapaths.append(event.datapath)
|
||||||
|
for datapath in datapaths:
|
||||||
|
# datapath = os.path.join(self.rootpath, datapath)
|
||||||
|
if os.path.isdir(datapath):
|
||||||
|
for filename in os.listdir(datapath):
|
||||||
|
filename = os.path.join(datapath, filename)
|
||||||
|
if os.path.isfile(filename) and filename.endswith(fext):
|
||||||
|
try:
|
||||||
|
self.read_eventfile_info(filename)
|
||||||
|
except Exception as e:
|
||||||
|
print('Failed on reading eventfile info from file {}: {}'.format(filename, e))
|
||||||
|
else:
|
||||||
|
print("Directory %s does not exist!" % datapath)
|
||||||
|
|
||||||
|
def getPaths(self):
|
||||||
|
'''
|
||||||
|
Returns paths (eventlist) of all events saved in the project.
|
||||||
|
'''
|
||||||
|
paths = []
|
||||||
|
for event in self.eventlist:
|
||||||
|
paths.append(event.path)
|
||||||
|
return paths
|
||||||
|
|
||||||
|
def setDirty(self, value=True):
|
||||||
|
self.dirty = value
|
||||||
|
|
||||||
|
def getEventFromPath(self, path):
|
||||||
|
'''
|
||||||
|
Search for an event in the project by event path.
|
||||||
|
'''
|
||||||
|
for event in self.eventlist:
|
||||||
|
if event.path == path:
|
||||||
|
return event
|
||||||
|
|
||||||
|
def save(self, filename=None):
|
||||||
|
'''
|
||||||
|
Save PyLoT Project to a file.
|
||||||
|
Can be loaded by using project.load(filename).
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
import pickle
|
||||||
|
except ImportError:
|
||||||
|
import _pickle as pickle
|
||||||
|
|
||||||
|
if filename:
|
||||||
|
self.location = filename
|
||||||
|
else:
|
||||||
|
filename = self.location
|
||||||
|
|
||||||
|
table = self._table # MP: see below
|
||||||
|
try:
|
||||||
|
outfile = open(filename, 'wb')
|
||||||
|
self._table = [] # MP: Workaround as long as table cannot be saved as part of project
|
||||||
|
pickle.dump(self, outfile, protocol=pickle.HIGHEST_PROTOCOL)
|
||||||
|
self.setDirty(False)
|
||||||
|
self._table = table # MP: see above
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print('Could not pickle PyLoT project. Reason: {}'.format(e))
|
||||||
|
self.setDirty()
|
||||||
|
self._table = table # MP: see above
|
||||||
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def load(filename):
|
||||||
|
'''
|
||||||
|
Load project from filename.
|
||||||
|
'''
|
||||||
|
import pickle
|
||||||
|
infile = open(filename, 'rb')
|
||||||
|
project = pickle.load(infile)
|
||||||
|
infile.close()
|
||||||
|
project.location = filename
|
||||||
|
print('Loaded %s' % filename)
|
||||||
|
return project
|
@ -20,7 +20,7 @@ import matplotlib
|
|||||||
matplotlib.use('Qt5Agg')
|
matplotlib.use('Qt5Agg')
|
||||||
sys.path.append(os.path.join('/'.join(sys.argv[0].split('/')[:-1]), '../../..'))
|
sys.path.append(os.path.join('/'.join(sys.argv[0].split('/')[:-1]), '../../..'))
|
||||||
|
|
||||||
from PyLoT import Project
|
from pylot.core.io.project import Project
|
||||||
from pylot.core.util.dataprocessing import Metadata
|
from pylot.core.util.dataprocessing import Metadata
|
||||||
from pylot.core.util.array_map import Array_map
|
from pylot.core.util.array_map import Array_map
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user