Newer
Older
if isinstance(sensor, SensorInstrument):
for tsd in self.mTSDs:
if tsd.date() == date and tsd.sensor() == sensor:
return tsd
return None

Benjamin Jakimow
committed
def insertTSD(self, tsd: TimeSeriesDatum)->TimeSeriesDatum:
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
"""
Inserts a TimeSeriesDatum
:param tsd: TimeSeriesDatum
"""
#insert sorted by time & sensor
assert tsd not in self.mTSDs
assert tsd.sensor() in self.mSensors
bisect.insort(self.mTSDs, tsd)
tsd.mTimeSeries = self
tsd.sigRemoveMe.connect(lambda: self.removeTSDs([tsd]))
tsd.sigSourcesChanged.connect(lambda: self.sigSourcesChanged.emit(tsd))
return tsd
def removeTSDs(self, tsds):
"""
Removes a list of TimeSeriesDatum
:param tsds: [list-of-TimeSeriesDatum]
"""
removed = list()
for tsd in tsds:
assert isinstance(tsd, TimeSeriesDatum)
assert tsd in self.mTSDs
self.mTSDs.remove(tsd)
tsd.mTimeSeries = None
removed.append(tsd)
self.sigTimeSeriesDatesRemoved.emit(removed)
def tsds(self, date:np.datetime64=None, sensor:SensorInstrument=None)->list:
"""
Returns a list of TimeSeriesDatum of the TimeSeries. By default all TimeSeriesDatum will be returned.
:param date: numpy.datetime64 to return the TimeSeriesDatum for
:param sensor: SensorInstrument of interest to return the [list-of-TimeSeriesDatum] for.
:return: [list-of-TimeSeriesDatum]
"""
tsds = self.mTSDs[:]
if date:
tsds = [tsd for tsd in tsds if tsd.date() == date]
if sensor:

Benjamin Jakimow
committed
tsds = [tsd for tsd in tsds if tsd.sensor() == sensor]
"""
Removes all data sources from the TimeSeries (which will be empty after calling this routine).
"""
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
if not sensor in self.mSensors:
self.mSensors.append(sensor)
self.sigSensorAdded.emit(sensor)
return sensor
else:
return None
def checkSensorList(self):
"""
Removes sensors without linked TSD / no data
"""
to_remove = []
for sensor in self.sensors():
tsds = [tsd for tsd in self.mTSDs if tsd.sensor() == sensor]
if len(tsds) == 0:
to_remove.append(sensor)
for sensor in to_remove:
self.removeSensor(sensor)
def removeSensor(self, sensor:SensorInstrument)->SensorInstrument:
"""
Removes a sensor and all linked images
:param sensor: SensorInstrument
:return: SensorInstrument or none, if sensor was not defined in the TimeSeries
"""
assert isinstance(sensor, SensorInstrument)
if sensor in self.mSensors:
tsds = [tsd for tsd in self.mTSDs if tsd.sensor() == sensor]
self.removeTSDs(tsds)
self.mSensors.remove(sensor)
self.sigSensorRemoved.emit(sensor)
return sensor
return None
Adds new data sources to the TimeSeries
:param sources: [list-of-TimeSeriesSources]
nMax = len(sources)
self.sigLoadingProgress.emit(0, nMax, 'Start loading {} sources...'.format(nMax))
# 1. read sources
# this could be excluded into a parallel process
addedDates = []
for i, source in enumerate(sources):

Benjamin Jakimow
committed
if isinstance(source, TimeSeriesSource):

Benjamin Jakimow
committed
else:
tss = TimeSeriesSource.create(source)

Benjamin Jakimow
committed
tss.mDate = self.date2date(tss.date())
date = tss.date()
sid = tss.sid()
sensor = self.sensor(sid)
if not isinstance(sensor, SensorInstrument):
sensor = self.addSensor(SensorInstrument(sid))
assert isinstance(sensor, SensorInstrument)
if not isinstance(tsd, TimeSeriesDatum):
tsd = self.insertTSD(TimeSeriesDatum(self, date, sensor))
addedDates.append(tsd)
assert isinstance(tsd, TimeSeriesDatum)
except Exception as ex:
msg = 'Unable to add: {}\n{}'.format(str(source), str(ex))
print(msg, file=sys.stderr)
self.sigLoadingProgress.emit(i+1, nMax, msg)
if len(addedDates) > 0:
self.sigTimeSeriesDatesAdded.emit(addedDates)

Benjamin Jakimow
committed
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
def setDateTimePrecision(self, mode:DateTimePrecision):
"""
Sets the precision with which the parsed DateTime information will be handled.
:param mode: TimeSeriesViewer:DateTimePrecision
:return:
"""
self.mDateTimePrecision = mode
#do we like to update existing sources?
def date2date(self, date:np.datetime64):
assert isinstance(date, np.datetime64)
if self.mDateTimePrecision == DateTimePrecision.Original:
return date
else:
date = np.datetime64(date, self.mDateTimePrecision.value)
return date
def sourceUris(self)->list:
"""
Returns the uris of all sources
:return: [list-of-str]
"""
uris = []
for tsd in self:
assert isinstance(tsd, TimeSeriesDatum)
uris.extend(tsd.sourceUris())
return uris
def __len__(self):
def __iter__(self):
def __getitem__(self, slice):
def __delitem__(self, slice):
def __contains__(self, item):
def __repr__(self):
info = []
info.append('TimeSeries:')
l = len(self)
info.append(' Scenes: {}'.format(l))
class TimeSeriesTableModel(QAbstractTableModel):
def __init__(self, TS:TimeSeries, parent=None, *args):
super(TimeSeriesTableModel, self).__init__()
assert isinstance(TS, TimeSeries)
self.cnDate = 'Date'
self.cnSensor = 'Sensor'
self.cnNS = 'ns'
self.cnNL = 'nl'
self.cnNB = 'nb'
self.cnCRS = 'CRS'

Benjamin Jakimow
committed
self.mColumnNames = [self.cnDate, self.cnSensor,
self.cnNS, self.cnNL, self.cnNB,
self.mTimeSeries = TS
self.mSensors = set()
self.mTimeSeries.sigTimeSeriesDatesRemoved.connect(self.removeTSDs)
self.mTimeSeries.sigTimeSeriesDatesAdded.connect(self.addTSDs)
self.addTSDs([tsd for tsd in self.mTimeSeries])
def timeSeries(self)->TimeSeries:
"""
:return: TimeSeries
"""
return self.mTimeSeries

Benjamin Jakimow
committed
def removeTSDs(self, tsds:list):
"""
Removes TimeSeriesDatum instances
:param tsds: list
"""
if tsd in self.mTimeSeries:
self.mTimeSeries.removeTSDs([tsd])
elif tsd in self.items:
idx = self.getIndexFromDate(tsd)
self.removeRows(idx.row(), 1)

Benjamin Jakimow
committed
def tsdChanged(self, tsd:TimeSeriesDatum):
idx = self.getIndexFromDate(tsd)
self.dataChanged.emit(idx, idx)
i = self.mColumnNames.index(self.cnSensor)
idx0 = self.createIndex(0, i)
idx1 = self.createIndex(self.rowCount(), i)
self.dataChanged.emit(idx0, idx1)
for tsd in tsds:
assert isinstance(tsd, TimeSeriesDatum)
row = bisect.bisect_left(self.items, tsd)
self.beginInsertRows(QModelIndex(), row, row)
self.items.insert(row, tsd)
self.endInsertRows()
#self.sort(self.sortColumnIndex, self.sortOrder)
for tsd in tsds:
assert isinstance(tsd, TimeSeriesDatum)
tsd.sigVisibilityChanged.connect(lambda: self.tsdChanged(tsd))
if sensor not in self.mSensors:
self.mSensors.add(sensor)
sensor.sigNameChanged.connect(self.sensorsChanged)
def rowCount(self, parent = QModelIndex())->int:
return len(self.items)
def removeRows(self, row, count , parent=QModelIndex()):
self.beginRemoveRows(parent, row, row+count-1)
toRemove = self.items[row:row+count]
for tsd in toRemove:
self.items.remove(tsd)
self.endRemoveRows()
def getIndexFromDate(self, tsd:TimeSeriesDatum)->QModelIndex:
assert isinstance(tsd, TimeSeriesDatum)
return self.createIndex(self.items.index(tsd),0)
def getDateFromIndex(self, index:QModelIndex)->TimeSeriesDatum:
assert isinstance(index, QModelIndex)
if index.isValid():
return self.items[index.row()]
return None
def getTimeSeriesDatumFromIndex(self, index:QModelIndex)->TimeSeriesDatum:
assert isinstance(index, QModelIndex)
if index.isValid():
i = index.row()
if i >= 0 and i < len(self.items):
return self.items[i]
return None
def columnCount(self, parent = QModelIndex())->int:
return len(self.mColumnNames)
def data(self, index, role = Qt.DisplayRole):
if role is None or not index.isValid():
return None
value = None
columnName = self.mColumnNames[index.column()]
TSD = self.getTimeSeriesDatumFromIndex(index)
assert isinstance(TSD, TimeSeriesDatum)
if role == Qt.DisplayRole or role == Qt.ToolTipRole:
value = '\n'.join([tss.crs().description() for tss in tssList])
elif columnName == self.cnNB:
value = TSD.sensor().nb
elif columnName == self.cnNL:
elif columnName == self.cnSensor:
value = TSD.sensor().name()
elif columnName in keys:
value = TSD.__dict__[columnName]
else:
s = ""
elif role == Qt.CheckStateRole:
if columnName == self.cnDate:
value = Qt.Checked if TSD.isVisible() else Qt.Unchecked
elif role == Qt.BackgroundColorRole:
value = None
elif role == Qt.UserRole:
value = TSD
return value
def setData(self, index, value, role=None):
if role is None or not index.isValid():
return None
if role is Qt.UserRole:
s = ""
columnName = self.mColumnNames[index.column()]
TSD = self.getTimeSeriesDatumFromIndex(index)
if columnName == self.cnDate and role == Qt.CheckStateRole:
TSD.setVisibility(value != Qt.Unchecked)
return True
else:
return False
return False
def flags(self, index):
if index.isValid():
columnName = self.mColumnNames[index.column()]
flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable

Benjamin Jakimow
committed
if columnName == self.cnDate: # allow check state
flags = flags | Qt.ItemIsUserCheckable
return flags

Benjamin Jakimow
committed
# return item.qt_flags(index.column())
return None
def headerData(self, col, orientation, role):
if Qt is None:
return None
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.mColumnNames[col]
elif orientation == Qt.Vertical and role == Qt.DisplayRole:
return col
return None
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
def getSpatialPropertiesFromDataset(ds):
assert isinstance(ds, gdal.Dataset)
nb = ds.RasterCount
nl = ds.RasterYSize
ns = ds.RasterXSize
proj = ds.GetGeoTransform()
px_x = float(abs(proj[1]))
px_y = float(abs(proj[5]))
crs = QgsCoordinateReferenceSystem(ds.GetProjection())
return nb, nl, ns, crs, px_x, px_y
wl = None
wlu = None
# see http://www.harrisgeospatial.com/docs/ENVIHeaderFiles.html for supported wavelength units
regWLkey = re.compile('.*wavelength[_ ]*$', re.I)
regWLUkey = re.compile('.*wavelength[_ ]*units?$', re.I)
regNumeric = re.compile(r"([-+]?\d*\.\d+|[-+]?\d+)", re.I)
regWLU = re.compile('((micro|nano|centi)meters)|(um|nm|mm|cm|m|GHz|MHz)', re.I)
if isinstance(ds, QgsRasterLayer):
lyr = ds
md = [l.split('=') for l in str(lyr.metadata()).splitlines() if 'wavelength' in l.lower()]
#see http://www.harrisgeospatial.com/docs/ENVIHeaderFiles.html for supported wavelength units
for kv in md:
key, value = kv
key = key.lower()
if key == 'center wavelength':
tmp = re.findall(r'\d*\.\d+|\d+', value) #find floats
if len(tmp) == 0:
tmp = re.findall(r'\d+', value) #find integers
if len(tmp) == lyr.bandCount():
wl = [float(w) for w in tmp]
if key == 'wavelength units':
match = regWLU.search(value)
if match:
wlu = match.group()
names = ['nanometers','micrometers','millimeters','centimeters','decimenters']
si = ['nm','um','mm','cm','dm']
if wlu in names:
wlu = si[names.index(wlu)]
elif isinstance(ds, gdal.Dataset):
for domain in ds.GetMetadataDomainList():
md = ds.GetMetadata_Dict(domain)
for key, value in md.items():
if wl is None and regWLkey.search(key):
numbers = regNumeric.findall(value)
if len(numbers) == ds.RasterCount:
wl = [float(n) for n in numbers]
if wlu is None and regWLUkey.search(key):
match = regWLU.search(value)
if match:
wlu = match.group().lower()
names = ['nanometers', 'micrometers', 'millimeters', 'centimeters', 'decimeters']
si = ['nm', 'um', 'mm', 'cm', 'dm']
if wlu in names:
wlu = si[names.index(wlu)]
return wl, wlu

Benjamin Jakimow
committed
q = QApplication([])

Benjamin Jakimow
committed
p.setRange(0, 0)
p.show()
q.exec_()

benjamin.jakimow@geo.hu-berlin.de
committed
print(convertMetricUnit(100, 'cm', 'm'))
print(convertMetricUnit(1, 'm', 'um'))