Newer
Older
assert isinstance(d, datetime.date)
yearDuration = daysPerYear(d)
yearElapsed = d.timetuple().tm_yday
fraction = float(yearElapsed) / float(yearDuration)
if fraction == 1.0:
fraction = 0.9999999
return float(d.year) + fraction
def num2date(n, dt64=True):
n = float(n)
if n < 1:
n += 1
year = int(n)
fraction = n - year
yearDuration = daysPerYear(year)
yearElapsed = fraction * yearDuration
import math
doy = round(yearElapsed)
if doy < 1:
doy = 1
try:
date = datetime.date(year, 1, 1) + datetime.timedelta(days=doy-1)
except:
s = ""
if dt64:
return np.datetime64(date)
else:
return date
#return np.datetime64('{:04}-01-01'.format(year), 'D') + np.timedelta64(int(yearElapsed), 'D')
def depr_date2num(d):
d2 = d.astype(datetime.datetime)
o = d2.toordinal()
#assert d == num2date(o)
return o
if n < 1:
n = 1
return np.datetime64('{:04}-{:02}-{:02}'.format(d.year,d.month,d.day), 'D')
class TemporalProfile(QObject):
_mNextID = 0
@staticmethod
def nextID():
n = TemporalProfile._mNextID
TemporalProfile._mNextID += 1
return n
def __init__(self, timeSeries, spatialPoint):
super(TemporalProfile, self).__init__()
assert isinstance(spatialPoint, SpatialPoint)
self.mUpdated = False
self.mName = '#{}'.format(self.mID)
self.mLoaded = self.mLoadedMax = 0
self.initMetadata()
self.updateLoadingStatus()
def initMetadata(self):
for tsd in self.mTimeSeries:
assert isinstance(tsd, TimeSeriesDatum)
meta = {'doy':tsd.doy,
'date':str(tsd.date)}
sigNameChanged = pyqtSignal(str)
def setName(self, name):
if name != self.mName:
self.mName = name
self.sigNameChanged.emit(self.mName)
def name(self):
return self.mName
def plot(self):
import pyqtgraph as pg
for sensor in self.mTimeSeries.sensors():
assert isinstance(sensor, SensorInstrument)
plotStyle = TemporalProfile2DPlotStyle(self)
plotStyle.setSensor(sensor)
pi = TemporalProfilePlotDataItem(plotStyle)
pi.setClickable(True)
pw = pg.plot(title=self.name())
pw.getPlotItem().addItem(pi)
pi.setColor('green')
pg.QAPP.exec_()
assert isinstance(tsd, TimeSeriesDatum)
assert isinstance(values, dict)
if tsd not in self.mData.keys():
self.mData[tsd] = {}
self.mData[tsd].update(values)
self.updateLoadingStatus()
self.mUpdated = True
def resetUpdated(self):
self.mUpdated = False
def updated(self):
return self.mUpdated
def dataFromExpression(self, sensor, expression, dateType='date'):
assert dateType in ['date','doy']
x = []
y = []
if not isinstance(expression, QgsExpression):
expression = QgsExpression(expression)
assert isinstance(expression, QgsExpression)
expression = QgsExpression(expression)
fields = QgsFields()
sensorTSDs = sorted([tsd for tsd in self.mData.keys() if tsd.sensor == sensor])
for tsd in sensorTSDs:
data = self.mData[tsd]
for k, v in data.items():
if v is not None and fields.fieldNameIndex(k) == -1:
fields.append(qgsFieldFromKeyValue(k, v))
for i, tsd in enumerate(sensorTSDs):
assert isinstance(tsd, TimeSeriesDatum)
data = self.mData[tsd]
context = QgsExpressionContext()
scope = QgsExpressionContextScope()
f = QgsFeature()
f.setFields(fields)
f.setValid(True)
if v is None:
continue
idx = f.fieldNameIndex(k)
field = f.fields().field(idx)
if field.typeName() == 'text':
v = str(v)
else:
v = float(v)
scope.setFeature(f)
context.appendScope(scope)
#value = expression.evaluatePrepared(f)
value = expression.evaluate(context)
if value in [None, NULL]:
s = ""
else:
if dateType == 'date':
x.append(date2num(tsd.date))
elif dateType == 'doy':
x.append(tsd.doy)
y.append(value)
#return np.asarray(x), np.asarray(y)
return x, y
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
def data(self, tsd):
assert isinstance(tsd, TimeSeriesDatum)
if self.hasData(tsd):
return self.mData[tsd]
else:
return {}
def loadingStatus(self):
"""
Returns the loading status in terms of single pixel values.
nLoaded = sum of single band values
nLoadedMax = potential maximum of band values that might be loaded
:return: (nLoaded, nLoadedMax)
"""
return self.mLoaded, self.mLoadedMax
def updateLoadingStatus(self):
"""
Calculates and the loading status in terms of single pixel values.
nMax is the sum of all bands over each TimeSeriesDatum and Sensors
"""
self.mLoaded = self.mLoadedMax
for tsd in self.mTimeSeries:
assert isinstance(tsd, TimeSeriesDatum)
self.mLoadedMax += tsd.sensor.nb
if self.hasData(tsd):
self.mLoaded += len([k for k in self.mData[tsd].keys() if k.startswith('b')])
def hasData(self,tsd):
assert isinstance(tsd, TimeSeriesDatum)
return tsd in self.mData.keys()
def __repr__(self):
return 'TemporalProfile {}'.format(self.mCoordinate)
class SpectralTemporalVisualization(QObject):
sigShowPixel = pyqtSignal(TimeSeriesDatum, QgsPoint, QgsCoordinateReferenceSystem)
"""
Signalizes to move to specific date of interest
"""
sigMoveToDate = pyqtSignal(np.datetime64)
def __init__(self, ui):
super(SpectralTemporalVisualization, self).__init__()
assert isinstance(ui, ProfileViewDockUI), 'arg ui of type: {} {}'.format(type(ui), str(ui))
self.ui = ui
if DEBUG:
import timeseriesviewer.pixelloader
timeseriesviewer.pixelloader.DEBUG = True
self.pixelLoader = PixelLoader()
self.pixelLoader.sigPixelLoaded.connect(self.onPixelLoaded)
self.pixelLoader.sigLoadingStarted.connect(lambda: self.ui.progressInfo.setText('Start loading...'))
self.plot_initialized = False
self.tableView2DProfiles = ui.tableView2DProfiles
self.tableView2DProfiles.setSortingEnabled(False)
self.tableView2DProfiles.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents)
self.plotSettingsModel3D = PlotSettingsModel3D()
#self.plotSettingsModel3D.sigPlotStylesRemoved.connect(self.updatePlot3D)
#self.plotSettingsModel3D.sigPlotStylesAdded.connect(self.updatePlot3D)
#self.plotSettingsModel3D.sigPlotStylesAdded.connect(self.updatePlot3D)
self.plotSettingsModel3D.rowsInserted.connect(self.onRowsInserted3D)
self.ui.tableView3DProfiles.setModel(self.plotSettingsModel3D)
self.ui.tableView3DProfiles.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents)
self.delegateTableView3D = PlotSettingsModel3DWidgetDelegate(self.ui.tableView3DProfiles)
self.delegateTableView3D.setItemDelegates(self.ui.tableView3DProfiles)
# self.mSelectionModel.currentChanged.connect(self.onCurrentSelectionChanged)
self.plot2D = ui.plotWidget2D

benjamin.jakimow@geo.hu-berlin.de
committed
pi = self.plot2D.getPlotItem()
pi.getViewBox().sigMoveToDate.connect(self.sigMoveToDate)
pi.getAxis('bottom').setLabel(LABEL_TIME)
pi.getAxis('left').setLabel(LABEL_DN)
self.plot2Dvline = pg.InfiniteLine(angle=90, movable=False)
self.plot2Dhline = pg.InfiniteLine(angle=0, movable=False)
#self.plot2DLabel = pg.TextItem(text='LABEL')
self.plot2DLabel = pg.LabelItem(justify='right')
#pi.setContentsMargins(0.1, 0.1, 0.1, 0.1)
pi.addItem(self.plot2Dvline, ignoreBounds=True)
pi.addItem(self.plot2Dhline, ignoreBounds=True)
self.plot2D.addItem(self.plot2DLabel, ignoreBounds=True)
self.proxy2D = pg.SignalProxy(self.plot2D.scene().sigMouseMoved, rateLimit=60, slot=self.onMouseMoved2D)
self.plot3D = ui.plotWidget3D
## Add a grid to the view
if OPENGL_AVAILABLE:
import pyqtgraph.opengl as gl
self.glGridItem = gl.GLGridItem()
self.glGridItem.setDepthValue(10) # draw grid after surfaces since they may be translucent
self.glPlotDataItems = [self.glGridItem]
self.plot3D.addItem(self.glGridItem)
self.tpCollection = TemporalProfileCollection()
self.tpCollectionListModel = TemporalProfileCollectionListModel(self.tpCollection)
self.ui.tableViewTemporalProfiles.setModel(self.tpCollection)
self.ui.tableViewTemporalProfiles.selectionModel().selectionChanged.connect(self.onTemporalProfileSelectionChanged)
self.ui.tableViewTemporalProfiles.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents)
self.ui.cbTemporalProfile3D.setModel(self.tpCollectionListModel)
#self.pxCollection.sigPixelAdded.connect(self.requestUpdate)
#self.pxCollection.sigPixelRemoved.connect(self.clear)
self.pixelLoader.sigLoadingStarted.connect(self.clear)
self.pixelLoader.sigLoadingFinished.connect(lambda : self.plot2D.enableAutoRange('x', False))
# self.VIEW.setItemDelegateForColumn(3, PointStyleDelegate(self.VIEW))
self.plotData2D = dict()
self.plotData3D = dict()
self.updateRequested = True
self.updateTimer = QTimer(self)
self.updateTimer.timeout.connect(self.onDataUpdate)
self.sigMoveToDate.connect(self.onMoveToDate)

benjamin.jakimow@geo.hu-berlin.de
committed
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
def onMouseMoved2D(self, evt):
pos = evt[0] ## using signal proxy turns original arguments into a tuple
plotItem = self.plot2D.getPlotItem()
if plotItem.sceneBoundingRect().contains(pos):
mousePoint = plotItem.vb.mapSceneToView(pos)
x = mousePoint.x()
y = mousePoint.y()
index = int(mousePoint.x())
self.plot2DLabel.setText('Refreshed {}'.format(mousePoint.x(), mousePoint.y()))
#if index > 0 and index < len(data1):
# label.setText(
# "<span style='font-size: 12pt'>x=%0.1f, <span style='color: red'>y1=%0.1f</span>, <span style='color: green'>y2=%0.1f</span>" % (
# mousePoint.x(), data1[index], data2[index]))
self.plot2Dvline.setPos(mousePoint.x())
self.plot2Dhline.setPos(mousePoint.y())
return
vb = plotItem.vb
if plotItem.sceneBoundingRect().contains(pos):
mousePoint = vb.mapSceneToView(pos)
self.vLine.setPos(mousePoint.x())
self.hLine.setPos(mousePoint.y())
info = '{:0.2f}, {:0.2f}'.format(mousePoint.x(), mousePoint.y())
self.tbCursorLocationValue.setText(info)
"""
self.mlabel.setText(
"<span style='font-size: 12pt'>{}</span>".format(info)
"""
else:
self.tbCursorLocationValue.setText('')
self.mlabel.setText('')
def selected2DPlotStyles(self):
result = []
m = self.ui.tableView2DProfiles.model()
for idx in selectedModelIndices(self.ui.tableView2DProfiles):
result.append(m.idx2plotStyle(idx))
return result
def selectedTemporalProfiles(self):
result = []
m = self.ui.tableViewTemporalProfiles.model()
for idx in selectedModelIndices(self.ui.tableViewTemporalProfiles):
result.append(m.idx2tp(idx))
return result
def removePlotStyles(self, plotStyles):
m = self.ui.tableView2DProfiles.model()
m.removePlotStyles(plotStyles)
def removeTemporalProfiles(self, temporalProfiles):
m = self.ui.tableViewTemporalProfiles.model()
if isinstance(m, TemporalProfileCollection):
m.removeTemporalProfiles(temporalProfiles)
def createNewPlotStyle(self):
l = len(self.tpCollection)
if l > 0:
temporalProfile = self.tpCollection[0]
plotStyle = TemporalProfile2DPlotStyle(temporalProfile)
plotStyle.sigExpressionUpdated.connect(self.updatePlot2D)
sensors = self.TS.Sensors.keys()
if len(sensors) > 0:
plotStyle.setSensor(sensors[0])
self.plotSettingsModel2D.insertPlotStyles([plotStyle])
pdi = plotStyle.createPlotItem(self.plot2D)
assert isinstance(pdi, TemporalProfilePlotDataItem)

benjamin.jakimow@geo.hu-berlin.de
committed
pdi.sigClicked.connect(self.onProfileClicked2D)
pdi.sigPointsClicked.connect(self.onPointsClicked2D)
self.plot2D.getPlotItem().addItem(pdi)
#self.plot2D.getPlotItem().addItem(pg.PlotDataItem(x=[1, 2, 3], y=[1, 2, 3]))
#plotItem.plot().sigPlotChanged.emit(plotItem)
self.updatePlot2D()

benjamin.jakimow@geo.hu-berlin.de
committed
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
def onProfileClicked2D(self, pdi):
if isinstance(pdi, TemporalProfilePlotDataItem):
sensor = pdi.mPlotStyle.sensor()
tp = pdi.mPlotStyle.temporalProfile()
if isinstance(tp, TemporalProfile) and isinstance(sensor, SensorInstrument):
info = ['Sensor:{}'.format(sensor.name()),
'Coordinate:{}, {}'.format(tp.mCoordinate.x(), tp.mCoordinate.y())]
self.ui.tbInfo2D.setPlainText('\n'.join(info))
def onPointsClicked2D(self, pdi, spottedItems):
if isinstance(pdi, TemporalProfilePlotDataItem) and isinstance(spottedItems, list):
sensor = pdi.mPlotStyle.sensor()
tp = pdi.mPlotStyle.temporalProfile()
if isinstance(tp, TemporalProfile) and isinstance(sensor, SensorInstrument):
info = ['Sensor: {}'.format(sensor.name()),
'Coordinate: {}, {}'.format(tp.mCoordinate.x(), tp.mCoordinate.y())]
for item in spottedItems:
pos = item.pos()
x = pos.x()
y = pos.y()
date = num2date(x)
info.append('Date: {}\nValue: {}'.format(date, y))
self.ui.tbInfo2D.setPlainText('\n'.join(info))
def onTemporalProfileSelectionChanged(self, selected, deselected):
self.ui.actionRemoveTemporalProfile.setEnabled(len(selected) > 0)
def onPlot2DSelectionChanged(self, selected, deselected):
self.ui.actionRemoveView.setEnabled(len(selected) > 0)
self.ui.actionRemoveView.setEnabled(False)
self.ui.actionRemoveTemporalProfile.setEnabled(False)
self.ui.btnAddView.setDefaultAction(self.ui.actionAddView)
self.ui.btnRemoveView.setDefaultAction(self.ui.actionRemoveView)
self.ui.btnRefresh2D.setDefaultAction(self.ui.actionRefresh2D)
self.ui.btnRefresh3D.setDefaultAction(self.ui.actionRefresh3D)
self.ui.btnRemoveTemporalProfile.setDefaultAction(self.ui.actionRemoveTemporalProfile)
self.ui.btnReset3DCamera.setDefaultAction(self.ui.actionReset3DCamera)
self.ui.actionRefresh2D.triggered.connect(self.updatePlot2D)
self.ui.actionRefresh3D.triggered.connect(self.updatePlot3D)
self.ui.actionAddView.triggered.connect(self.createNewPlotStyle)
self.ui.actionRemoveView.triggered.connect(lambda:self.removePlotStyles(self.selected2DPlotStyles()))
self.ui.actionRemoveTemporalProfile.triggered.connect(lambda :self.removeTemporalProfiles(self.selectedTemporalProfiles()))
self.ui.actionReset3DCamera.triggered.connect(self.reset3DCamera)
self.tpCollection.sigMaxProfilesChanged.connect(self.ui.sbMaxTP.setValue)
self.ui.sbMaxTP.valueChanged.connect(self.tpCollection.setMaxProfiles)
#todo: self.ui.actionRemoveView.triggered.connect(self.plotSettingsModel.createPlotStyle)
def reset3DCamera(self, *args):
if OPENGL_AVAILABLE:
self.plot3D.setCameraPosition((0,0,0), distance=10, elevation=10)
assert isinstance(TS, TimeSeries)
self.TS = TS
self.plotSettingsModel2D = PlotSettingsModel2D(self.tpCollection, self.plot2D, parent=self)
self.plotSettingsModel2D.sigVisibilityChanged.connect(self.setVisibility)
self.plotSettingsModel2D.sigDataChanged.connect(self.requestUpdate)
self.plotSettingsModel2D.rowsInserted.connect(self.onRowsInserted2D)
self.plotSettingsModel3D.connectTimeSeries(self.TS)
# self.plotSettingsModel.modelReset.connect(self.updatePersistantWidgets)
self.tableView2DProfiles.setModel(self.plotSettingsModel2D)
#self.tableView2DProfilesSelectionModel = QItemSelectionModel(self.mModel)
self.tableView2DProfiles.selectionModel().selectionChanged.connect(self.onPlot2DSelectionChanged)
#self.tableView2DProfilesSelectionModel.selectionChanged.connect(self.onPlot2DSelectionChanged)
#self.tableView2DProfilesSelectionModel.setSelectionModel(self.mSelectionModel)
self.delegateTableView2D = PlotSettingsModel2DWidgetDelegate(self.tableView2DProfiles, self.TS, self.tpCollectionListModel)
self.delegateTableView2D.setItemDelegates(self.tableView2DProfiles)
def onMoveToDate(self, date):
dt = np.asarray([np.abs(tsd.date - date) for tsd in self.TS])
i = np.argmin(dt)
self.sigMoveToTSD.emit(self.TS[i])
def onPixelLoaded(self, nDone, nMax, d):
self.ui.progressBar.setValue(nDone)
self.ui.progressBar.setMaximum(nMax)
if d.success():
t = 'Last loaded from {}.'.format(bn)
else:
t = 'Failed loading from {}.'.format(bn)
if d.info and d.info != '':
t += '({})'.format(d.info)
def requestUpdate(self, *args):
self.updateRequested = True
#next time
def onRowsInserted2D(self, parent, start, end):
model = self.tableView2DProfiles.model()
if isinstance(model, PlotSettingsModel2D):
colExpression = model.columnIndex(model.cnExpression)
colStyle = model.columnIndex(model.cnStyle)
while start <= end:
idxExpr = model.createIndex(start, colExpression)
idxStyle = model.createIndex(start, colStyle)
self.tableView2DProfiles.openPersistentEditor(idxExpr)
self.tableView2DProfiles.openPersistentEditor(idxStyle)
start += 1
#self.TV.openPersistentEditor(model.createIndex(start, colStyle))
s = ""
def onRowsInserted3D(self, parent, start, end):
model = self.ui.tableView3DProfiles.model()
if isinstance(model, PlotSettingsModel3D):
colStyle = model.columnIndex(model.cnStyle)
while start <= end:
idxStyle = model.createIndex(start, colStyle)
self.ui.tableView3DProfiles.openPersistentEditor(idxStyle)
start += 1
def onObservationClicked(self, plotDataItem, points):
for p in points:
tsd = p.data()
def clear(self):
#first remove from pixelCollection
self.plotData2D.clear()
self.plotData3D.clear()
pi = self.plot2D.getPlotItem()
plotItems = pi.listDataItems()
for p in plotItems:
p.clear()
p.update()
if len(self.TS) > 0:
rng = [self.TS[0].date, self.TS[-1].date]
rng = [date2num(d) for d in rng]
self.plot2D.getPlotItem().setRange(xRange=rng)
if self.plot3D:
pass
def loadCoordinate(self, spatialPoints=None, LUT_bandIndices=None):
"""
Loads a temporal profile for a single or multiple geometries.
:param spatialPoints: SpatialPoint | [list-of-SpatialPoints]
"""
if not isinstance(self.plotSettingsModel2D, PlotSettingsModel2D):
return False
if not self.pixelLoader.isReadyToLoad():
return False
assert isinstance(self.TS, TimeSeries)
#Get or create the TimeSeriesProfiles which will store the loaded values
tasks = []
TPs = []
theGeometries = []
# Define a which (new) bands need to be loaded for each sensor
if LUT_bandIndices is None:
LUT_bandIndices = dict()
for sensor in self.TS.Sensors:
LUT_bandIndices[sensor] = self.plotSettingsModel2D.requiredBandsIndices(sensor)
assert isinstance(LUT_bandIndices, dict)
for sensor in self.TS.Sensors:
assert sensor in LUT_bandIndices.keys()
#update new / existing points
if isinstance(spatialPoints, SpatialPoint):
spatialPoints = [spatialPoints]
for spatialPoint in spatialPoints:
assert isinstance(spatialPoint, SpatialPoint)
TP = self.tpCollection.fromSpatialPoint(spatialPoint)
if not isinstance(TP, TemporalProfile):
TP = TemporalProfile(self.TS, spatialPoint)
self.tpCollection.insertTemporalProfiles(TP, i=0)
TPs.append(TP)
theGeometries.append(TP.mCoordinate)
TP_ids = [TP.mID for TP in TPs]
#each TSD is a Task
#a Task defines which bands are to be loaded
for tsd in self.TS:
#do not load from invisible TSDs
if not tsd.isVisible():
continue
#which bands do we need to load?
requiredIndices = set(LUT_bandIndices[tsd.sensor])
if len(requiredIndices) == 0:
continue
else:
s = ""
missingIndices = set()
for TP in TPs:
assert isinstance(TP, TemporalProfile)
existingBandKeys = [k for k in TP.data(tsd).keys() if PlotSettingsModel2D.regBandKeyExact.search(k)]
existingBandIndices = set([bandKey2bandIndex(k) for k in existingBandKeys])
need2load = requiredIndices.difference(existingBandIndices)
missingIndices = missingIndices.union(need2load)
if len(missingIndices) > 0:
task = PixelLoaderTask(tsd.pathImg, theGeometries,
bandIndices=missingIndices,
temporalProfileIDs=TP_ids)
tasks.append(task)
if len(tasks) > 0:
aGoodDefault = 2 if len(self.TS) > 25 else 1
self.pixelLoader.setNumberOfProcesses(SETTINGS.value('profileloader_threads', aGoodDefault))
if DEBUG:
print('Start loading for {} geometries from {} sources...'.format(
len(theGeometries), len(tasks)
))
self.pixelLoader.startLoading(tasks)
else:
if DEBUG:
print('Data for geometries already loaded')
def setVisibility(self, sensorPlotStyle):
assert isinstance(sensorPlotStyle, TemporalProfile2DPlotStyle)
self.setVisibility2D(sensorPlotStyle)
def setVisibility2D(self, sensorPlotStyle):
self.plot2D.update()
if sensorView is None:
for sv in self.plotSettingsModel2D.items:
self.setData(sv)
else:
assert isinstance(sensorView, TemporalProfile2DPlotStyle)
self.setData2D(sensorView)
def onDataUpdate(self):
for plotSetting in self.plotSettingsModel2D:
assert isinstance(plotSetting, TemporalProfile2DPlotStyle)
if plotSetting.temporalProfile().updated():
for pdi in plotSetting.mPlotItems:
assert isinstance(pdi, TemporalProfilePlotDataItem)
pdi.updateDataAndStyle()
plotSetting.temporalProfile().resetUpdated()
for i in self.plot2D.getPlotItem().dataItems:
i.updateItems()
if not self.plot2D.xAxisInitialized:
x0 = x1 = None
for plotSetting in self.plotSettingsModel2D:
assert isinstance(plotSetting, TemporalProfile2DPlotStyle)
for pdi in plotSetting.mPlotItems:
assert isinstance(pdi, TemporalProfilePlotDataItem)
if pdi.xData.ndim == 0 or pdi.xData.shape[0] == 0:
continue
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
if x0 is None:
x0 = pdi.xData.min()
x1 = pdi.xData.max()
else:
x0 = min(pdi.xData.min(), x0)
x1 = max(pdi.xData.max(), x1)
if x0 is not None:
self.plot2D.getPlotItem().setXRange(x0, x1)
self.plot2D.xAxisInitialized = True
@QtCore.pyqtSlot()
def updatePlot3D(self):
if OPENGL_AVAILABLE:
from pyqtgraph.opengl import GLViewWidget
import pyqtgraph.opengl as gl
assert isinstance(self.plot3D, GLViewWidget)
w = self.plot3D
#we need the data from all bands
del self.glPlotDataItems[:]
for i in w.items:
w.removeItem(i)
idx = self.ui.cbTemporalProfile3D.currentIndex()
if idx >= 0:
tp = self.ui.cbTemporalProfile3D.itemData(idx, role=Qt.UserRole)
assert isinstance(tp, TemporalProfile)
#1. ensure that data from all bands will be loaded
LUT_bandIndices = dict()
for sensor in self.TS.sensors():
assert isinstance(sensor, SensorInstrument)
LUT_bandIndices[sensor] = list(range(sensor.nb))
self.loadCoordinate(tp.mCoordinate, LUT_bandIndices=LUT_bandIndices)
#2. visualize already loaded data
LUTStyle = {}
for style in self.plotSettingsModel3D:
assert isinstance(style, TemporalProfile3DPlotStyle)
LUTStyle[style.sensor()] = style
dataPos = []
x0 = x1 = y0 = y1 = z0 = z1 = 0
for iDate, tsd in enumerate(tp.mTimeSeries):
bandKeys = sorted([k for k in data.keys() if k.startswith('b') and data[k] != None], key=lambda k: bandKey2bandIndex(k))
if len(bandKeys) < 2:
continue
t = date2num(tsd.date)
x = []
y = []
z = []
for i, k in enumerate(bandKeys):
x.append(i)
y.append(t)
z.append(data[k])
x = np.asarray(x)
y = np.asarray(y)
z = np.asarray(z)
if iDate == 0:
x0, x1 = (x.min(), x.max())
y0, y1 = (y.min(), y.max())
z0, z1 = (z.min(), z.max())
else:
x0, x1 = (min(x.min(), x0), max(x.max(), x1))
y0, y1 = (min(y.min(), y0), max(y.max(), y1))
z0, z1 = (min(z.min(), z0), max(z.max(), z1))
if tsd.sensor in LUTStyle.keys():
style = LUTStyle[tsd.sensor]
else:
style = TemporalProfile3DPlotStyle(tsd.sensor)
dataPos.append((x,y,z, style))
xyz = [(x0,x1),(y0,y1),(z0,z1)]
l = len(dataPos)
for iPos, pos in enumerate(dataPos):
x,y,z, style = pos
assert isinstance(style, TemporalProfile3DPlotStyle)
if not style.isVisible():
continue
arr = np.asarray((x,y,z), dtype=np.float64).transpose()
for i, m in enumerate(xyz):
arr[:, i] = (arr[:,i] - m0)/(m1-m0)
plt = gl.GLLinePlotItem(pos=arr,
#color=pg.glColor((i, n * 1.3)),
#color=pg.glColor(255,123,123,125),
#color=pg.glColor((iPos, l * 1.3)),
color=pg.glColor(style.color()),
self.glPlotDataItems.append(plt)
for i, item in enumerate(self.glPlotDataItems):
w.addItem(item)
#self.glGridItem.scale(0.1,0.1,0.1, local=False)
#w.setBackgroundColor(QColor('black'))
#w.setCameraPosition(pos=(0.0, 0.0, 0.0), distance=1.)
w.addItem(self.glGridItem)
w.update()
"""
for sensor, values in data.items():
if len(values['z']) > 0:
x = values['x']
y = values['y']
z = values['z']
p2 = gl.GLSurfacePlotItem(x=x, y=y, z=z, shader='normalColor')
p2.translate(-10, -10, 0)
w.addItem(p2)
"""
@QtCore.pyqtSlot()
def updatePlot2D(self):
if isinstance(self.plotSettingsModel2D, PlotSettingsModel2D):
pi = self.plot2D.getPlotItem()
piDataItems = pi.listDataItems()
for plotSetting in self.plotSettingsModel2D:
assert isinstance(plotSetting, TemporalProfile2DPlotStyle)
locations.add(plotSetting.temporalProfile().mCoordinate)
for pdi in plotSetting.mPlotItems:
assert isinstance(pdi, TemporalProfilePlotDataItem)
#for i in pi.dataItems:
# i.updateItems()
#self.plot2D.update()
#2. load pixel data
self.loadCoordinate(list(locations))
# https://github.com/pyqtgraph/pyqtgraph/blob/5195d9dd6308caee87e043e859e7e553b9887453/examples/customPlot.py
return
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
# prepare QGIS environment
if sys.platform == 'darwin':
PATH_QGS = r'/Applications/QGIS.app/Contents/MacOS'
os.environ['GDAL_DATA'] = r'/usr/local/Cellar/gdal/1.11.3_1/share'
else:
# assume OSGeo4W startup
PATH_QGS = os.environ['QGIS_PREFIX_PATH']
assert os.path.exists(PATH_QGS)
qgsApp = QgsApplication([], True)
QApplication.addLibraryPath(r'/Applications/QGIS.app/Contents/PlugIns')
QApplication.addLibraryPath(r'/Applications/QGIS.app/Contents/PlugIns/qgis')
qgsApp.setPrefixPath(PATH_QGS, True)
qgsApp.initQgis()
gb = QGroupBox()
gb.setTitle('Sandbox')
PL = PixelLoader()
if False:
files = ['observationcloud/testdata/2014-07-26_LC82270652014207LGN00_BOA.bsq',
'observationcloud/testdata/2014-08-03_LE72270652014215CUB00_BOA.bsq'
]
else:
from timeseriesviewer.utils import file_search
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
searchDir = r'H:\LandsatData\Landsat_NovoProgresso'
files = file_search(searchDir, '*227065*band4.img', recursive=True)
#files = files[0:3]
lyr = QgsRasterLayer(files[0])
coord = lyr.extent().center()
crs = lyr.crs()
l = QVBoxLayout()
btnStart = QPushButton()
btnStop = QPushButton()
prog = QProgressBar()
tboxResults = QPlainTextEdit()
tboxResults.setMaximumHeight(300)
tboxThreads = QPlainTextEdit()
tboxThreads.setMaximumHeight(200)
label = QLabel()
label.setText('Progress')
def showProgress(n,m,md):
prog.setMinimum(0)
prog.setMaximum(m)
prog.setValue(n)
info = []
for k, v in md.items():
info.append('{} = {}'.format(k,str(v)))
tboxResults.setPlainText('\n'.join(info))
#tboxThreads.setPlainText(PL.threadInfo())
qgsApp.processEvents()
PL.sigPixelLoaded.connect(showProgress)
btnStart.setText('Start loading')
btnStart.clicked.connect(lambda : PL.startLoading(files, coord, crs))
btnStop.setText('Cancel')
btnStop.clicked.connect(lambda: PL.cancelLoading())
lh = QHBoxLayout()
lh.addWidget(btnStart)
lh.addWidget(btnStop)
l.addLayout(lh)
l.addWidget(prog)
l.addWidget(tboxThreads)
l.addWidget(tboxResults)
gb.setLayout(l)
gb.show()
#rs.setBackgroundStyle('background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #222, stop:1 #333);')
#rs.handle.setStyleSheet('background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #282, stop:1 #393);')
qgsApp.exec_()
qgsApp.exitQgis()
if __name__ == '__main__':
import site, sys
from timeseriesviewer import utils
qgsApp = utils.initQgisApplication()
if False: #the ultimative test for floating point division correctness, at least on a DOY-level
date1 = np.datetime64('1960-12-31','D')
assert date1 == num2date(date2num(date1))
#1960 - 12 - 31
for year in range(1960, 2057):
for doy in range(1, daysPerYear(year)+1):
dt = datetime.timedelta(days=doy - 1)
date1 = np.datetime64('{}-01-01'.format(year)) + np.timedelta64(doy-1,'D')
date2 = datetime.date(year=year, month=1, day=1) + datetime.timedelta(days=doy-1)
assert date1 == num2date(date2num(date1), dt64=True), 'date1: {}'.format(date1)
assert date2 == num2date(date2num(date2), dt64=False), 'date2: {}'.format(date1)
STVis = SpectralTemporalVisualization(ui)
STVis.setTimeSeries(TS)