Newer
Older
# -*- coding: utf-8 -*-
"""
/***************************************************************************

Benjamin Jakimow
committed
EO Time Series Viewer
-------------------
begin : 2017-08-04
git sha : $Format:%H$
copyright : (C) 2017 by HU-Berlin
email : benjamin.jakimow@geo.hu-berlin.de
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""
# noinspection PyPep8Naming
import os, sys, pickle, datetime
from qgis.gui import *
from qgis.core import *

Benjamin Jakimow
committed
from qgis.PyQt.QtCore import *
from qgis.PyQt.QtXml import *
from qgis.PyQt.QtGui import *
from .timeseries import *
from .utils import SpatialExtent, SpatialPoint, px2geo, loadUI, nextColor

Benjamin Jakimow
committed
from .externals.qps.plotstyling.plotstyling import PlotStyle, PlotStyleButton, PlotStyleDialog
from .externals.pyqtgraph import ScatterPlotItem, SpotItem, GraphicsScene
from .externals.qps.externals.pyqtgraph.GraphicsScene.mouseEvents import MouseClickEvent, MouseDragEvent
from .externals import pyqtgraph as pg
from .sensorvisualization import SensorListModel
import numpy as np
#import OpenGL
from eotimeseriesviewer.temporalprofiles3d import *
except Exception as ex:
print('unable to import OpenGL based packages:\n{}'.format(ex))
def getTextColorWithContrast(c):
assert isinstance(c, QColor)
if c.lightness() < 0.5:
return QColor('white')
else:
return QColor('black')
def selectedModelIndices(tableView):
assert isinstance(tableView, QTableView)
result = {}
sm = tableView.selectionModel()
m = tableView.model()
if isinstance(sm, QItemSelectionModel) and isinstance(m, QAbstractItemModel):
for idx in sm.selectedIndexes():
assert isinstance(idx, QModelIndex)
if idx.row() not in result.keys():
result[idx.row()] = idx
return result.values()
def __init__(self, *args, **kwds):
# menu creation is deferred because it is expensive and often
# the user will never see the menu anyway.
self.menu = None
def boundingRect(self):
return super(_SensorPoints,self).boundingRect()
def paint(self, p, *args):
super(_SensorPoints, self).paint(p, *args)
# On right-click, raise the context menu
def mouseClickEvent(self, ev):
if ev.button() == QtCore.Qt.RightButton:
if self.raiseContextMenu(ev):
ev.accept()
def raiseContextMenu(self, ev):
menu = self.getContextMenus()
# Let the scene add on to the end of our context menu
# (this is optional)
menu = self.scene().addParentContextMenus(self, menu, ev)
pos = ev.screenPos()
menu.popup(QtCore.QPoint(pos.x(), pos.y()))
return True
# This method will be called when this item's _children_ want to raise
# a context menu that includes their parents' menus.
def getContextMenus(self, event=None):
if self.menu is None:
self.menu = QMenu()
self.menu.setTitle(self.name + " options..")
green = QAction("Turn green", self.menu)
green.triggered.connect(self.setGreen)
self.menu.addAction(green)
self.menu.green = green
blue = QAction("Turn blue", self.menu)
blue.triggered.connect(self.setBlue)
self.menu.addAction(blue)
self.menu.green = blue
alpha = QWidgetAction(self.menu)
alphaSlider = QSlider()
alphaSlider.setOrientation(QtCore.Qt.Horizontal)
alphaSlider.setMaximum(255)
alphaSlider.setValue(255)
alphaSlider.valueChanged.connect(self.setAlpha)
alpha.setDefaultWidget(alphaSlider)
self.menu.addAction(alpha)
self.menu.alpha = alpha
self.menu.alphaSlider = alphaSlider
return self.menu
class SensorPixelDataMemoryLayer(QgsVectorLayer):
def __init__(self, sensor, crs=None):
assert isinstance(sensor, SensorInstrument)
if crs is None:
crs = QgsCoordinateReferenceSystem('EPSG:4862')
uri = 'Point?crs={}'.format(crs.authid())
super(SensorPixelDataMemoryLayer, self).__init__(uri, 'Pixels_sensor_' + sensor.name(), 'memory', False)
self.mSensor = sensor
#initialize fields
assert self.startEditing()
# standard field names, types, etc.
fieldDefs = [('pxid', QVariant.String, 'integer'),
('date', QVariant.String, 'char'),
('doy', QVariant.Int, 'integer'),
('geo_x', QVariant.Double, 'decimal'),
('geo_y', QVariant.Double, 'decimal'),
('px_x', QVariant.Int, 'integer'),
('px_y', QVariant.Int, 'integer'),
]
# one field for each band
for b in range(sensor.nb):
fName = 'b{}'.format(b + 1)
fieldDefs.append((fName, QVariant.Double, 'decimal'))
# initialize fields
for fieldDef in fieldDefs:
field = QgsField(fieldDef[0], fieldDef[1], fieldDef[2])
self.addAttribute(field)
self.commitChanges()
def sensor(self):
return self.mSensor
def nPixels(self):
raise NotImplementedError()
def dates(self):
raise NotImplementedError()
class PlotSettingsModel3D(QAbstractTableModel):
#sigSensorAdded = pyqtSignal(SensorPlotSettings)
sigVisibilityChanged = pyqtSignal(TemporalProfile2DPlotStyle)
sigPlotStylesAdded = pyqtSignal(list)
sigPlotStylesRemoved = pyqtSignal(list)
def __init__(self, parent=None, *args):
#assert isinstance(tableView, QTableView)
super(PlotSettingsModel3D, self).__init__(parent=parent)
self.mTimeSeries = None
self.cnID = 'ID'
self.cnExpression = LABEL_EXPRESSION_3D
self.cnTemporalProfile = 'Coordinate'
self.cnStyle = 'Style'
self.cnSensor = 'Sensor'
self.columnNames = [self.cnTemporalProfile, self.cnSensor, self.cnStyle, self.cnExpression]
self.mPlotSettings = []
#assert isinstance(plotWidget, DateTimePlotWidget)
self.sortColumnIndex = 0
self.sortOrder = Qt.AscendingOrder
self.sort(0, Qt.AscendingOrder)
def hasStyleForSensor(self, sensor):
assert isinstance(sensor, SensorInstrument)
for plotStyle in self.mPlotSettings:
assert isinstance(plotStyle, TemporalProfile3DPlotStyle)
if plotStyle.sensor() == sensor:
return True
return False
def onSensorRemoved(self, sensor):
assert isinstance(sensor, SensorInstrument)
self.removePlotStyles([s for s in self.mPlotSettings if s.sensor() == sensor])
def __len__(self):
return len(self.mPlotSettings)
def __iter__(self):
return iter(self.mPlotSettings)
def __getitem__(self, slice):
return self.mPlotSettings[slice]
def __contains__(self, item):
return item in self.mPlotSettings
def columnIndex(self, name):
return self.columnNames.index(name)
def insertPlotStyles(self, plotStyles, i=None):
"""
Inserts PlotStyle
:param plotStyles: TemporalProfilePlotStyle | [list-of-TemporalProfilePlotStyle]
:param i: index to insert, defaults to the last list position
"""
if isinstance(plotStyles, TemporalProfile3DPlotStyle):
plotStyles = [plotStyles]
assert isinstance(plotStyles, list)
for plotStyle in plotStyles:
assert isinstance(plotStyle, TemporalProfile3DPlotStyle)
if i is None:
i = len(self.mPlotSettings)
if len(plotStyles) > 0:
self.beginInsertRows(QModelIndex(), i, i + len(plotStyles)-1)
for j, plotStyle in enumerate(plotStyles):
assert isinstance(plotStyle, TemporalProfile3DPlotStyle)
self.mPlotSettings.insert(i+j, plotStyle)
self.endInsertRows()
self.sigPlotStylesAdded.emit(plotStyles)
def removePlotStyles(self, plotStyles):
"""
Removes PlotStyle instances
:param plotStyles: TemporalProfilePlotStyle | [list-of-TemporalProfilePlotStyle]
"""
if isinstance(plotStyles, TemporalProfile3DPlotStyle):
plotStyles = [plotStyles]
assert isinstance(plotStyles, list)
if len(plotStyles) > 0:
for plotStyle in plotStyles:
assert isinstance(plotStyle, TemporalProfile3DPlotStyle)
if plotStyle in self.mPlotSettings:
idx = self.plotStyle2idx(plotStyle)
self.beginRemoveRows(QModelIndex(), idx.row(),idx.row())
self.mPlotSettings.remove(plotStyle)
self.endRemoveRows()
self.sigPlotStylesRemoved.emit(plotStyles)
def sort(self, col, order):
if self.rowCount() == 0:
return
colName = self.columnames[col]
r = order != Qt.AscendingOrder
#self.beginMoveRows(idxSrc,
if colName == self.cnSensor:
self.mPlotSettings.sort(key = lambda sv:sv.sensor().name(), reverse=r)
def rowCount(self, parent = QModelIndex()):
return len(self.mPlotSettings)
def removeRows(self, row, count , parent = QModelIndex()):
self.beginRemoveRows(parent, row, row + count-1)
toRemove = self.mPlotSettings[row:row + count]
for tsd in toRemove:
self.mPlotSettings.remove(tsd)
def plotStyle2idx(self, plotStyle):
assert isinstance(plotStyle, TemporalProfile3DPlotStyle)
if plotStyle in self.mPlotSettings:
i = self.mPlotSettings.index(plotStyle)
return self.createIndex(i, 0)
else:
return QModelIndex()
def idx2plotStyle(self, index):
if index.isValid() and index.row() < self.rowCount():
return self.mPlotSettings[index.row()]
def columnCount(self, parent = QModelIndex()):
return len(self.columnNames)
def data(self, index, role = Qt.DisplayRole):
if role is None or not index.isValid():
return None
value = None
columnName = self.columnNames[index.column()]
plotStyle = self.idx2plotStyle(index)
if isinstance(plotStyle, TemporalProfile3DPlotStyle):
sensor = plotStyle.sensor()
#print(('data', columnName, role))
if role == Qt.DisplayRole:
if columnName == self.cnSensor:
if isinstance(sensor, SensorInstrument):
value = sensor.name()
else:
value = '<Select Sensor>'
elif columnName == self.cnExpression:
value = plotStyle.expression()
elif columnName == self.cnTemporalProfile:
tp = plotStyle.temporalProfile()
if isinstance(tp, TemporalProfile):
value = tp.name()
else:
value = 'undefined'
elif role == Qt.EditRole:
if columnName == self.cnExpression:
value = plotStyle.expression()
elif role == Qt.CheckStateRole:
if columnName == self.cnTemporalProfile:
value = Qt.Checked if plotStyle.isVisible() else Qt.Unchecked
elif role == Qt.UserRole:
value = plotStyle
if columnName == self.cnSensor:
value = plotStyle.sensor()
elif columnName == self.cnStyle:
value = plotStyle
else:
value = plotStyle
#print(('get data',value))
return value
def setData(self, index, value, role=None):
if role is None or not index.isValid():
return False
#print(('Set data', index.row(), index.column(), value, role))
columnName = self.columnNames[index.column()]
if value is None:
return False
result = False
plotStyle = self.idx2plotStyle(index)
if isinstance(plotStyle, TemporalProfile3DPlotStyle):
"""
if role in [Qt.DisplayRole]:
if columnName == self.cnExpression and isinstance(value, str):
plotStyle.setExpression(value)
result = True
elif columnName == self.cnStyle:
if isinstance(value, PlotStyle):
plotStyle.copyFrom(value)
result = True
"""
if role == Qt.CheckStateRole:
if columnName == self.cnTemporalProfile:
plotStyle.setVisibility(value == Qt.Checked)
result = True
if role == Qt.EditRole:
if columnName == self.cnSensor:
plotStyle.setSensor(value)
result = True
elif columnName == self.cnExpression:
plotStyle.setExpression(value)
result = True
elif columnName == self.cnTemporalProfile:
plotStyle.setTemporalProfile(value)
result = True
elif columnName == self.cnStyle:
#set the style and trigger an update
lastItemType = plotStyle.itemType()
lastExpression = plotStyle.expression()
plotStyle.copyFrom(value)
if lastItemType != plotStyle.itemType() or \
lastExpression != plotStyle.expression():
plotStyle.updateDataProperties()
else:
plotStyle.updateStyleProperties()
def flags(self, index):
if index.isValid():
stype = self.idx2plotStyle(index)
columnName = self.columnNames[index.column()]
flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
if columnName in [self.cnTemporalProfile]:
flags = flags | Qt.ItemIsUserCheckable
if columnName in [self.cnTemporalProfile, self.cnSensor, self.cnExpression, self.cnStyle]: #allow check state
flags = flags | Qt.ItemIsEditable
return flags
#return item.qt_flags(index.column())
return Qt.NoItemFlags
def headerData(self, col, orientation, role):
if Qt is None:
return None
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.columnNames[col]
elif orientation == Qt.Vertical and role == Qt.DisplayRole:
return col
return None
class PlotSettingsModel2D(QAbstractTableModel):
# sigSensorAdded = pyqtSignal(SensorPlotSettings)
sigVisibilityChanged = pyqtSignal(TemporalProfile2DPlotStyle)
sigDataChanged = pyqtSignal(TemporalProfile2DPlotStyle)
sigPlotStylesAdded = pyqtSignal(list)
sigPlotStylesRemoved = pyqtSignal(list)
def __init__(self, parent=None, *args):
super(PlotSettingsModel2D, self).__init__(parent=parent)
self.cnID = 'ID'
self.cnSensor = 'Sensor'
self.cnExpression = LABEL_EXPRESSION_2D
self.cnStyle = 'Style'
self.cnTemporalProfile = 'Coordinate'
self.columnNames = [self.cnTemporalProfile, self.cnSensor, self.cnStyle, self.cnExpression]
self.mPlotSettings = []

Benjamin Jakimow
committed
self.mIconSize = QSize(25, 25)
self.dataChanged.connect(self.signaler)
def __len__(self):
return len(self.mPlotSettings)
def __iter__(self):
return iter(self.mPlotSettings)
def __getitem__(self, slice):
return self.mPlotSettings[slice]
def __contains__(self, item):
return item in self.mPlotSettings
def testSlot(self, *args):
print(('TESTSLOT', args))
def signaler(self, idxUL, idxLR):
if idxUL.isValid():
plotStyle = self.idx2plotStyle(idxUL)
cname = self.columnNames[idxUL.column()]
if cname in [self.cnSensor,self.cnStyle]:
self.sigVisibilityChanged.emit(plotStyle)
if cname in [self.cnExpression]:
self.sigDataChanged.emit(plotStyle)
"""
Returns the band indices required to calculate the values for
the different PlotStyle expressions making use of sensor
:param sensor: SensorInstrument for which the band indices are to be returned.
:return: [list-of-band-indices]
"""
bandIndices = set()
assert isinstance(sensor, SensorInstrument)
for p in [p for p in self.mPlotSettings if p.sensor() == sensor]:
assert isinstance(p, TemporalProfile2DPlotStyle)
expression = p.expression()
#remove leading & tailing "
bandKeys = regBandKey.findall(expression)
for bandIndex in [bandKey2bandIndex(key) for key in bandKeys]:
bandIndices.add(bandIndex)
return bandIndices
def insertPlotStyles(self, plotStyles, i=None):
"""
Inserts PlotStyle
:param plotStyles: TemporalProfilePlotStyle | [list-of-TemporalProfilePlotStyle]
:param i: index to insert, defaults to the last list position
"""
if isinstance(plotStyles, TemporalProfile2DPlotStyle):
plotStyles = [plotStyles]
assert isinstance(plotStyles, list)
for plotStyle in plotStyles:
assert isinstance(plotStyle, TemporalProfile2DPlotStyle)
if i is None:
i = len(self.mPlotSettings)
if len(plotStyles) > 0:
self.beginInsertRows(QModelIndex(), i, i + len(plotStyles)-1)
for j, plotStyle in enumerate(plotStyles):
assert isinstance(plotStyle, TemporalProfile2DPlotStyle)
plotStyle.sigExpressionUpdated.connect(lambda s = plotStyle: self.onStyleUpdated(s))
self.mPlotSettings.insert(i+j, plotStyle)
self.endInsertRows()
self.sigPlotStylesAdded.emit(plotStyles)
def onStyleUpdated(self, style):
idx = self.plotStyle2idx(style)
r = idx.row()
self.dataChanged.emit(self.createIndex(r, 0), self.createIndex(r, self.columnCount()))
s = ""
def removePlotStyles(self, plotStyles):
"""
Removes PlotStyle instances
:param plotStyles: TemporalProfilePlotStyle | [list-of-TemporalProfilePlotStyle]
"""
if isinstance(plotStyles, PlotStyle):
plotStyles = [plotStyles]
assert isinstance(plotStyles, list)
if len(plotStyles) > 0:
for plotStyle in plotStyles:
assert isinstance(plotStyle, PlotStyle)
if plotStyle in self.mPlotSettings:
idx = self.plotStyle2idx(plotStyle)
self.beginRemoveRows(QModelIndex(), idx.row(),idx.row())
self.mPlotSettings.remove(plotStyle)
self.endRemoveRows()
self.sigPlotStylesRemoved.emit(plotStyles)
def rowCount(self, parent = QModelIndex()):
return len(self.mPlotSettings)
def removeRows(self, row, count , parent = QModelIndex()):
self.beginRemoveRows(parent, row, row + count-1)
toRemove = self.mPlotSettings[row:row + count]
for tsd in toRemove:
self.mPlotSettings.remove(tsd)
self.endRemoveRows()
def plotStyle2idx(self, plotStyle):
assert isinstance(plotStyle, TemporalProfile2DPlotStyle)
if plotStyle in self.mPlotSettings:
i = self.mPlotSettings.index(plotStyle)
return self.createIndex(i, 0)
else:
return QModelIndex()
def idx2plotStyle(self, index):
if index.isValid() and index.row() < self.rowCount():
return self.mPlotSettings[index.row()]
return None
def columnCount(self, parent = QModelIndex()):
def data(self, index, role = Qt.DisplayRole):
if role is None or not index.isValid():
return None
value = None
columnName = self.columnNames[index.column()]
if isinstance(plotStyle, TemporalProfile2DPlotStyle):
sensor = plotStyle.sensor()
#print(('data', columnName, role))
if role == Qt.DisplayRole:
if columnName == self.cnSensor:
if isinstance(sensor, SensorInstrument):
value = sensor.name()
else:
value = '<Select Sensor>'
elif columnName == self.cnExpression:
value = plotStyle.expression()
elif columnName == self.cnTemporalProfile:
tp = plotStyle.temporalProfile()
if isinstance(tp, TemporalProfile):
else:
value = 'undefined'
if columnName == self.cnTemporalProfile:
value = Qt.Checked if plotStyle.isVisible() else Qt.Unchecked
elif role == Qt.UserRole:
value = plotStyle
if columnName == self.cnSensor:
value = plotStyle.sensor()
elif columnName == self.cnExpression:
value = plotStyle.expression()
elif columnName == self.cnStyle:
value = plotStyle
elif columnName == self.cnTemporalProfile:
value == plotStyle.temporalProfile()
else:
value = plotStyle
#print(('get data',value))
return value
def setData(self, index, value, role=None):
if role is None or not index.isValid():
return False
#print(('Set data', index.row(), index.column(), value, role))
columnName = self.columnNames[index.column()]
result = False
plotStyle = self.idx2plotStyle(index)
if isinstance(plotStyle, TemporalProfile2DPlotStyle):
if columnName == self.cnExpression:
plotStyle.setExpression(value)
plotStyle.updateDataProperties()
result = True
elif columnName == self.cnStyle:
if isinstance(value, PlotStyle):
plotStyle.copyFrom(value)
plotStyle.updateStyleProperties()
result = True
if role == Qt.CheckStateRole:
if columnName == self.cnTemporalProfile:
plotStyle.setVisibility(value == Qt.Checked)
result = True
if role == Qt.EditRole:
if columnName == self.cnExpression:
plotStyle.setExpression(value)
result = True
elif columnName == self.cnStyle:
plotStyle.copyFrom(value)
result = True
elif columnName == self.cnSensor:
plotStyle.setSensor(value)
elif columnName == self.cnTemporalProfile:
plotStyle.setTemporalProfile(value)
if result:
#save plot-style
self.savePlotSettings(plotStyle, index='DEFAULT')
self.dataChanged.emit(index, index)
def savePlotSettings(self, sensorPlotSettings, index='DEFAULT'):
return
def restorePlotSettings(self, sensor, index='DEFAULT'):
return None
def flags(self, index):
if index.isValid():
columnName = self.columnNames[index.column()]
flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
if columnName in [self.cnTemporalProfile]:
if columnName in [self.cnTemporalProfile, self.cnSensor, self.cnExpression, self.cnStyle]: #allow check state
flags = flags | Qt.ItemIsEditable
return flags
#return item.qt_flags(index.column())
return Qt.NoItemFlags
def headerData(self, col, orientation, role):
if Qt is None:
return None
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
elif orientation == Qt.Vertical and role == Qt.DisplayRole:
return col
return None

Benjamin Jakimow
committed
class PlotSettingsTableView(QTableView):

Benjamin Jakimow
committed
def __init__(self, *args, **kwds):
super(PlotSettingsTableView, self).__init__(*args, **kwds)
pal = self.palette()
cSelected = pal.color(QPalette.Active, QPalette.Highlight)
pal.setColor(QPalette.Inactive, QPalette.Highlight, cSelected)
self.setPalette(pal)

Benjamin Jakimow
committed
def contextMenuEvent(self, event: QContextMenuEvent):
"""
Creates and shows the QMenu
:param event: QContextMenuEvent
"""

Benjamin Jakimow
committed
indices = self.selectionModel().selectedIndexes()

Benjamin Jakimow
committed
indices2 = [self.model().mapToSource(idx) for idx in indices]

Benjamin Jakimow
committed
if len(indices2) > 0:
menu = QMenu(self)
a = menu.addAction('Set Style')
a.triggered.connect(lambda *args, i=indices2: self.onSetStyle(i))

Benjamin Jakimow
committed
menu.popup(QCursor.pos())

Benjamin Jakimow
committed
def onSetStyle(self, indices):

Benjamin Jakimow
committed
if len(indices) > 0:
refStyle = None

benjamin.jakimow@geo.hu-berlin.de
committed

Benjamin Jakimow
committed
model = self.model().sourceModel()
assert isinstance(model, PlotSettingsModel2D)

Benjamin Jakimow
committed
colStyle = model.columnIndex(model.cnStyle)

Benjamin Jakimow
committed
for idx in indices:
style = self.model().sourceModel().idx2plotStyle(idx)
if isinstance(style, PlotStyle):
refStyle = style
break
if isinstance(refStyle, PlotStyle):
newStyle = PlotStyleDialog.getPlotStyle(plotStyle=refStyle)
if isinstance(newStyle, PlotStyle):
for idx in indices:
assert isinstance(idx, QModelIndex)
idxStyle = model.createIndex(idx.row(), colStyle)
model.setData(idxStyle, newStyle, role=Qt.EditRole)

Benjamin Jakimow
committed
class PlotSettingsModel2DWidgetDelegate(QStyledItemDelegate):
"""

Benjamin Jakimow
committed
"""
def __init__(self, tableView, temporalProfileLayer, parent=None):
assert isinstance(tableView, QTableView)
assert isinstance(temporalProfileLayer, TemporalProfileLayer)
super(PlotSettingsModel2DWidgetDelegate, self).__init__(parent=parent)
self._preferedSize = QgsFieldExpressionWidget().sizeHint()
self.mTableView = tableView
self.mTemporalProfileLayer = temporalProfileLayer
self.mTimeSeries = temporalProfileLayer.timeSeries()

Benjamin Jakimow
committed
self.mSensorLayers = {}

Benjamin Jakimow
committed
def paint(self, painter: QPainter, option: 'QStyleOptionViewItem', index: QtCore.QModelIndex):

Benjamin Jakimow
committed
if index.column() == 2:
style = self.style(index)
h = self.mTableView.verticalHeader().defaultSectionSize()
w = self.mTableView.horizontalHeader().defaultSectionSize()
if h > 0 and w > 0:
px = style.createPixmap(size=QSize(w, h))
label = QLabel()
label.setPixmap(px)
painter.drawPixmap(option.rect, px)
#QApplication.style().drawControl(QStyle.CE_CustomBase, label, painter)
else:
super(PlotSettingsModel2DWidgetDelegate, self).paint(painter, option, index)
else:
super(PlotSettingsModel2DWidgetDelegate, self).paint(painter, option, index)

Benjamin Jakimow
committed
def sortFilterProxyModel(self)->QSortFilterProxyModel:
return self.mTableView.model()

Benjamin Jakimow
committed
def plotSettingsModel(self)->PlotSettingsModel2D:
return self.sortFilterProxyModel().sourceModel()

benjamin.jakimow@geo.hu-berlin.de
committed

Benjamin Jakimow
committed
def setItemDelegates(self, tableView):
assert isinstance(tableView, QTableView)
model = self.plotSettingsModel()
assert isinstance(model, PlotSettingsModel2D)
for c in [model.cnSensor, model.cnExpression, model.cnStyle, model.cnTemporalProfile]:
i = model.columnNames.index(c)
tableView.setItemDelegateForColumn(i, self)

Benjamin Jakimow
committed
def getColumnName(self, index):
assert index.isValid()
model = self.plotSettingsModel()
assert isinstance(model, PlotSettingsModel2D)
return model.columnNames[index.column()]

Benjamin Jakimow
committed
def sizeHint(self, options, index):
s = super(ExpressionDelegate, self).sizeHint(options, index)
exprString = self.tableView.model().data(index)
l = QLabel()
l.setText(exprString)
x = l.sizeHint().width() + 100
s = QSize(x, s.height())
return self._preferedSize

Benjamin Jakimow
committed
def exampleLyr(self, sensor):
# if isinstance(sensor, SensorInstrument):
if sensor not in self.mSensorLayers.keys():

benjamin.jakimow@geo.hu-berlin.de
committed

Benjamin Jakimow
committed
crs = QgsCoordinateReferenceSystem('EPSG:4862')
uri = 'Point?crs={}'.format(crs.authid())
lyr = QgsVectorLayer(uri, 'LOCATIONS', 'memory')
f = sensorExampleQgsFeature(sensor)
assert isinstance(f, QgsFeature)
assert lyr.startEditing()
for field in f.fields():
lyr.addAttribute(field)
lyr.addFeature(f)
lyr.commitChanges()
self.mSensorLayers[sensor] = lyr
return self.mSensorLayers[sensor]

Benjamin Jakimow
committed
def createEditor(self, parent, option, index):
cname = self.getColumnName(index)
model = self.plotSettingsModel()
pmodel = self.sortFilterProxyModel()

Benjamin Jakimow
committed
w = None
if index.isValid() and isinstance(model, PlotSettingsModel2D):

Benjamin Jakimow
committed

Benjamin Jakimow
committed
plotStyle = model.idx2plotStyle(pmodel.mapToSource(index))

Benjamin Jakimow
committed

Benjamin Jakimow
committed
if isinstance(plotStyle, TemporalProfile2DPlotStyle):
if cname == model.cnExpression:

Benjamin Jakimow
committed

Benjamin Jakimow
committed
w = QgsFieldExpressionWidget(parent=parent)
w.setExpressionDialogTitle('Values')
w.setToolTip('Set an expression to specify the image band or calculate a spectral index.')
w.fieldChanged[str, bool].connect(lambda n, b: self.checkData(index, w, w.expression()))
w.setExpression(plotStyle.expression())

Benjamin Jakimow
committed
if isinstance(plotStyle.sensor(), SensorInstrument):
w.setLayer(self.exampleLyr(plotStyle.sensor()))

Benjamin Jakimow
committed

Benjamin Jakimow
committed
elif cname == model.cnStyle:
w = PlotStyleButton(parent=parent)
w.setPlotStyle(plotStyle)
w.setToolTip('Set style.')
w.sigPlotStyleChanged.connect(lambda: self.checkData(index, w, w.plotStyle()))

Benjamin Jakimow
committed
elif cname == model.cnSensor:
w = QComboBox(parent=parent)
m = SensorListModel(self.mTimeSeries)
w.setModel(m)

Benjamin Jakimow
committed
elif cname == model.cnTemporalProfile:
w = QgsFeatureListComboBox(parent=parent)
w.setSourceLayer(self.mTemporalProfileLayer)
w.setIdentifierField(FN_ID)
w.setDisplayExpression('to_string("{}")+\' \'+"name"'.format(FN_ID))
w.setAllowNull(False)
else:
raise NotImplementedError()
return w

Benjamin Jakimow
committed
def checkData(self, index, w, value):
assert isinstance(index, QModelIndex)
model = self.mTableView.model()
if index.isValid() and isinstance(model, PlotSettingsModel2D):
plotStyle = model.idx2plotStyle(index)
assert isinstance(plotStyle, TemporalProfile2DPlotStyle)
if isinstance(w, QgsFieldExpressionWidget):
assert value == w.expression()
assert w.isExpressionValid(value) == w.isValidExpression()

Benjamin Jakimow
committed
if w.isValidExpression():
self.commitData.emit(w)
else:
s = ""
#print(('Delegate commit failed',w.asExpression()))
if isinstance(w, PlotStyleButton):

Benjamin Jakimow
committed
self.commitData.emit(w)

Benjamin Jakimow
committed
def style(self, proxyIndex:QModelIndex)->PlotStyle:
model = self.plotSettingsModel()
index = self.sortFilterProxyModel().mapToSource(proxyIndex)
return model.data(index, role=Qt.UserRole)

Benjamin Jakimow
committed
def setEditorData(self, editor, proxyIndex):

Benjamin Jakimow
committed
model = self.plotSettingsModel()
index = self.sortFilterProxyModel().mapToSource(proxyIndex)
w = None
if index.isValid() and isinstance(model, PlotSettingsModel2D):
cname = self.getColumnName(proxyIndex)
if cname == model.cnExpression:
lastExpr = model.data(index, Qt.DisplayRole)
assert isinstance(editor, QgsFieldExpressionWidget)
editor.setProperty('lastexpr', lastExpr)
editor.setField(lastExpr)

Benjamin Jakimow
committed
elif cname == model.cnStyle:
style = model.data(index, Qt.UserRole)
assert isinstance(editor, PlotStyleButton)
editor.setPlotStyle(style)

Benjamin Jakimow
committed
elif cname == model.cnSensor:
assert isinstance(editor, QComboBox)
m = editor.model()
assert isinstance(m, SensorListModel)
sensor = index.data(role=Qt.UserRole)
if isinstance(sensor, SensorInstrument):
idx = m.sensor2idx(sensor)
editor.setCurrentIndex(idx.row())

Benjamin Jakimow
committed
elif cname == model.cnTemporalProfile:
assert isinstance(editor, QgsFeatureListComboBox)
value = editor.identifierValue()
if value != QVariant():
plotStyle = index.data(role=Qt.UserRole)
TP = plotStyle.temporalProfile()
editor.setIdentifierValue(TP.id())
else:
s = ""
else:
raise NotImplementedError()

Benjamin Jakimow
committed
def setModelData(self, w, model, proxyIndex):
index = self.sortFilterProxyModel().mapToSource(proxyIndex)
cname = self.getColumnName(proxyIndex)
model = self.plotSettingsModel()

Benjamin Jakimow
committed
if index.isValid() and isinstance(model, PlotSettingsModel2D):
if cname == model.cnExpression:
assert isinstance(w, QgsFieldExpressionWidget)
expr = w.asExpression()
exprLast = model.data(index, Qt.DisplayRole)

Benjamin Jakimow
committed
if w.isValidExpression() and expr != exprLast:
model.setData(index, w.asExpression(), Qt.EditRole)

Benjamin Jakimow
committed
elif cname == model.cnStyle:
if isinstance(w, PlotStyleButton):
style = w.plotStyle()
model.setData(index, style, Qt.EditRole)

Benjamin Jakimow
committed
elif cname == model.cnSensor:
assert isinstance(w, QComboBox)
sensor = w.itemData(w.currentIndex(), role=Qt.UserRole)
if isinstance(sensor, SensorInstrument):
model.setData(index, sensor, Qt.EditRole)

Benjamin Jakimow
committed
elif cname == model.cnTemporalProfile:
assert isinstance(w, QgsFeatureListComboBox)
fid = w.identifierValue()
if isinstance(fid, int):
# once set manually, do not update to last temporal profile any more
oldStyle = index.data(role=Qt.UserRole)
if isinstance(oldStyle, TemporalProfile2DPlotStyle):
oldStyle.mShowLastLocation = False

Benjamin Jakimow
committed
TP = self.mTemporalProfileLayer.mProfiles.get(fid)
model.setData(index, TP, Qt.EditRole)

Benjamin Jakimow
committed
else:
raise NotImplementedError()

Benjamin Jakimow
committed
class PlotSettingsModel3DWidgetDelegate(QStyledItemDelegate):
"""

Benjamin Jakimow
committed
"""
def __init__(self, tableView, temporalProfileLayer, parent=None):
assert isinstance(tableView, QTableView)
assert isinstance(temporalProfileLayer, TemporalProfileLayer)
super(PlotSettingsModel3DWidgetDelegate, self).__init__(parent=parent)
self._preferedSize = QgsFieldExpressionWidget().sizeHint()
self.mTableView = tableView
self.mTimeSeries = temporalProfileLayer.timeSeries()
self.mTemporalProfileLayer = temporalProfileLayer
self.mSensorLayers = {}

Benjamin Jakimow
committed
def setItemDelegates(self, tableView):
assert isinstance(tableView, QTableView)
model = tableView.model()
assert isinstance(model, PlotSettingsModel3D)
for c in [model.cnSensor,
model.cnExpression,
# model.cnStyle,
model.cnTemporalProfile]:
i = model.columnNames.index(c)
tableView.setItemDelegateForColumn(i, self)

Benjamin Jakimow
committed
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
def getColumnName(self, index):
assert index.isValid()
model = index.model()
assert isinstance(model, PlotSettingsModel3D)
return model.columnNames[index.column()]
"""
def sizeHint(self, options, index):
s = super(ExpressionDelegate, self).sizeHint(options, index)
exprString = self.tableView.model().data(index)
l = QLabel()
l.setText(exprString)
x = l.sizeHint().width() + 100
s = QSize(x, s.height())
return self._preferedSize
"""
def createEditor(self, parent, option, index):
cname = self.getColumnName(index)
model = self.mTableView.model()
w = None
if index.isValid() and isinstance(model, PlotSettingsModel3D):
plotStyle = model.idx2plotStyle(index)
if isinstance(plotStyle, TemporalProfile3DPlotStyle):
if cname == model.cnExpression:
w = QgsFieldExpressionWidget(parent=parent)
w.setExpression(plotStyle.expression())
w.setLayer(self.exampleLyr(plotStyle.sensor()))
def onSensorAdded(s):
w.setLayer(self.exampleLyr(s))
#plotStyle.sigSensorChanged.connect(lambda s : w.setLayer(self.exampleLyr(s)))
plotStyle.sigSensorChanged.connect(onSensorAdded)
w.setExpressionDialogTitle('Values')
w.setToolTip('Set an expression to specify the image band or calculate a spectral index.')
w.fieldChanged[str, bool].connect(lambda n, b : self.checkData(index, w, w.expression()))

Benjamin Jakimow
committed
elif cname == model.cnStyle:
w = TemporalProfile3DPlotStyleButton(parent=parent)
w.setPlotStyle(plotStyle)
w.setToolTip('Set plot style')
w.sigPlotStyleChanged.connect(lambda: self.checkData(index, w, w.plotStyle()))

Benjamin Jakimow
committed
elif cname == model.cnSensor:
w = QComboBox(parent=parent)
m = SensorListModel(self.mTimeSeries)
w.setModel(m)

Benjamin Jakimow
committed
elif cname == model.cnTemporalProfile:
w = QgsFeatureListComboBox(parent=parent)
w.setSourceLayer(self.mTemporalProfileLayer)
w.setIdentifierField('id')
w.setDisplayExpression('to_string("id")+\' \'+"name"')
w.setAllowNull(False)
else:
raise NotImplementedError()
return w

Benjamin Jakimow
committed
def exampleLyr(self, sensor):

Benjamin Jakimow
committed
if sensor not in self.mSensorLayers.keys():
crs = QgsCoordinateReferenceSystem('EPSG:4862')
uri = 'Point?crs={}'.format(crs.authid())
lyr = QgsVectorLayer(uri, 'LOCATIONS', 'memory')
assert sensor is None or isinstance(sensor, SensorInstrument)

Benjamin Jakimow
committed
f = sensorExampleQgsFeature(sensor, singleBandOnly=True)
assert isinstance(f, QgsFeature)
assert lyr.startEditing()
for field in f.fields():
lyr.addAttribute(field)
lyr.addFeature(f)
lyr.commitChanges()
self.mSensorLayers[sensor] = lyr
return self.mSensorLayers[sensor]

Benjamin Jakimow
committed
def checkData(self, index, w, value):
assert isinstance(index, QModelIndex)
model = self.mTableView.model()
if index.isValid() and isinstance(model, PlotSettingsModel3D):
plotStyle = model.idx2plotStyle(index)
assert isinstance(plotStyle, TemporalProfile3DPlotStyle)
if isinstance(w, QgsFieldExpressionWidget):
assert value == w.expression()
assert w.isExpressionValid(value) == w.isValidExpression()

Benjamin Jakimow
committed
if w.isValidExpression():
self.commitData.emit(w)
else:
s = ""
#print(('Delegate commit failed',w.asExpression()))
if isinstance(w, TemporalProfile3DPlotStyleButton):

Benjamin Jakimow
committed
self.commitData.emit(w)

Benjamin Jakimow
committed

Benjamin Jakimow
committed
def setEditorData(self, editor, index):
cname = self.getColumnName(index)
model = self.mTableView.model()

Benjamin Jakimow
committed
w = None
if index.isValid() and isinstance(model, PlotSettingsModel3D):
cname = self.getColumnName(index)
style = model.idx2plotStyle(index)

Benjamin Jakimow
committed
if cname == model.cnExpression:
lastExpr = index.model().data(index, Qt.DisplayRole)
assert isinstance(editor, QgsFieldExpressionWidget)
editor.setProperty('lastexpr', lastExpr)
editor.setField(lastExpr)

Benjamin Jakimow
committed
elif cname == model.cnStyle:
assert isinstance(editor, TemporalProfile3DPlotStyleButton)
editor.setPlotStyle(style)

Benjamin Jakimow
committed
elif cname == model.cnSensor:
assert isinstance(editor, QComboBox)
m = editor.model()
assert isinstance(m, SensorListModel)
sensor = index.data(role=Qt.UserRole)
if isinstance(sensor, SensorInstrument):
idx = m.sensor2idx(sensor)
editor.setCurrentIndex(idx.row())
elif cname == model.cnTemporalProfile:
assert isinstance(editor, QgsFeatureListComboBox)
value = editor.identifierValue()
if value != QVariant():
plotStyle = index.data(role=Qt.UserRole)
TP = plotStyle.temporalProfile()
editor.setIdentifierValue(TP.id())
else:
s = ""

Benjamin Jakimow
committed
else:
raise NotImplementedError()

Benjamin Jakimow
committed
def setModelData(self, w, model, index):
cname = self.getColumnName(index)
model = self.mTableView.model()
if index.isValid() and isinstance(model, PlotSettingsModel3D):
if cname == model.cnExpression:
assert isinstance(w, QgsFieldExpressionWidget)
expr = w.asExpression()
exprLast = model.data(index, Qt.DisplayRole)
if w.isValidExpression() and expr != exprLast:
model.setData(index, w.asExpression(), Qt.EditRole)

Benjamin Jakimow
committed
elif cname == model.cnStyle:
assert isinstance(w, TemporalProfile3DPlotStyleButton)
model.setData(index, w.plotStyle(), Qt.EditRole)

Benjamin Jakimow
committed
elif cname == model.cnSensor:
assert isinstance(w, QComboBox)
sensor = w.itemData(w.currentIndex(), role=Qt.UserRole)
assert isinstance(sensor, SensorInstrument)
model.setData(index, sensor, Qt.EditRole)

Benjamin Jakimow
committed
s = ""

Benjamin Jakimow
committed
elif cname == model.cnTemporalProfile:
assert isinstance(w, QgsFeatureListComboBox)
fid = w.identifierValue()
if isinstance(fid, int):
TP = self.mTemporalProfileLayer.mProfiles.get(fid)
model.setData(index, TP, Qt.EditRole)

Benjamin Jakimow
committed
else:
raise NotImplementedError()

Benjamin Jakimow
committed
class ProfileViewDockUI(QgsDockWidget, loadUI('profileviewdock.ui')):

benjamin.jakimow@geo.hu-berlin.de
committed

Benjamin Jakimow
committed
def __init__(self, parent=None):
super(ProfileViewDockUI, self).__init__(parent)
self.setupUi(self)

Benjamin Jakimow
committed
self.addActions(self.findChildren(QAction))

Benjamin Jakimow
committed
self.mActions2D = [self.actionAddStyle2D, self.actionRemoveStyle2D, self.actionRefresh2D, self.actionReset2DPlot]
self.mActions3D = [self.actionAddStyle3D, self.actionRemoveStyle3D, self.actionRefresh3D,
self.actionReset3DCamera]
self.mActionsTP = [self.actionLoadTPFromOgr, self.actionSaveTemporalProfiles, self.actionToggleEditing,
self.actionRemoveTemporalProfile, self.actionLoadMissingValues]
#TBD.
#self.line.setVisible(False)
#self.listWidget.setVisible(False)
self.baseTitle = self.windowTitle()
self.stackedWidget.currentChanged.connect(self.onStackPageChanged)

benjamin.jakimow@geo.hu-berlin.de
committed

Benjamin Jakimow
committed
self.plotWidget3D = None
self.plotWidget3DMPL = None

Benjamin Jakimow
committed
self.init3DWidgets('gl')

benjamin.jakimow@geo.hu-berlin.de
committed

Benjamin Jakimow
committed
#pi = self.plotWidget2D.plotItem
#ax = DateAxis(orientation='bottom', showValues=True)
#pi.layout.addItem(ax, 3,2)

Benjamin Jakimow
committed
self.TS = None

Benjamin Jakimow
committed
self.progressBar.setMinimum(0)
self.progressBar.setMaximum(100)
self.progressBar.setValue(0)
self.progressInfo.setText('')
self.pxViewModel2D = None
self.pxViewModel3D = None

Benjamin Jakimow
committed
self.tableView2DProfiles.horizontalHeader().setResizeMode(QHeaderView.Interactive)

Benjamin Jakimow
committed
def init3DWidgets(self, mode='gl'):
assert mode in ['gl']
l = self.frame3DPlot.layout()

Benjamin Jakimow
committed
if ENABLE_OPENGL and OPENGL_AVAILABLE and mode == 'gl':

Benjamin Jakimow
committed
from eotimeseriesviewer.temporalprofiles3dGL import ViewWidget3D
self.plotWidget3D = ViewWidget3D(parent=self.labelDummy3D.parent())
self.plotWidget3D.setObjectName('plotWidget3D')

Benjamin Jakimow
committed
size = self.labelDummy3D.size()
l.addWidget(self.plotWidget3D)
self.plotWidget3D.setSizePolicy(self.labelDummy3D.sizePolicy())
self.labelDummy3D.setVisible(False)
l.removeWidget(self.labelDummy3D)
#self.plotWidget3D.setBaseSize(size)
self.splitter3D.setSizes([100, 100])
self.frameSettings3D.setEnabled(True)
else:
self.frameSettings3D.setEnabled(False)

Benjamin Jakimow
committed
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
def onStackPageChanged(self, i):
w = self.stackedWidget.currentWidget()
title = self.baseTitle
if w == self.page2D:
title = '{} | 2D'.format(title)
for a in self.mActions2D:
a.setVisible(True)
for a in self.mActions3D + self.mActionsTP:
a.setVisible(False)
elif w == self.page3D:
title = '{} | 3D (experimental!)'.format(title)
for a in self.mActions2D + self.mActionsTP:
a.setVisible(False)
for a in self.mActions3D:
a.setVisible(True)
elif w == self.pagePixel:
title = '{} | Coordinates'.format(title)
for a in self.mActions2D + self.mActions3D:
a.setVisible(False)
for a in self.mActionsTP:
a.setVisible(True)

Benjamin Jakimow
committed
w.update()
self.setWindowTitle(title)

Benjamin Jakimow
committed
class SpectralTemporalVisualization(QObject):
sigShowPixel = pyqtSignal(TimeSeriesDate, QgsPoint, QgsCoordinateReferenceSystem)

Benjamin Jakimow
committed
"""
Signalizes to move to specific date of interest
"""
sigMoveToDate = pyqtSignal(np.datetime64)

Benjamin Jakimow
committed
def __init__(self, timeSeries, profileDock):
super(SpectralTemporalVisualization, self).__init__()

Benjamin Jakimow
committed
assert isinstance(profileDock, ProfileViewDockUI)
self.ui = profileDock
self.mTasks = dict()
#import eotimeseriesviewer.pixelloader
#if DEBUG:
# eotimeseriesviewer.pixelloader.DEBUG = True

Benjamin Jakimow
committed
#the timeseries. will be set later
assert isinstance(timeSeries, TimeSeries)
self.TS = timeSeries
self.plot_initialized = False

Benjamin Jakimow
committed
self.plot2D = self.ui.plotWidget2D
assert isinstance(self.plot2D, DateTimePlotWidget)

Benjamin Jakimow
committed
self.plot2D.getViewBox().sigMoveToDate.connect(self.sigMoveToDate)
self.plot2D.getViewBox().scene().sigMouseClicked.connect(self.onPointsClicked2D)

Benjamin Jakimow
committed
self.plot3D = self.ui.plotWidget3D
self.mLast2DMouseClickPosition = None

Benjamin Jakimow
committed
# temporal profile collection to store loaded values
self.mTemporalProfileLayer = TemporalProfileLayer(self.TS)
self.mTemporalProfileLayer.sigTemporalProfilesAdded.connect(self.onTemporalProfilesAdded)
self.mTemporalProfileLayer.selectionChanged.connect(self.onTemporalProfileSelectionChanged)

Benjamin Jakimow
committed
# fix to not loose C++ reference on temporal profile layer in case it is removed from QGIS mapcanvas
self.mMapCanvas = QgsMapCanvas()
self.mMapCanvas.setVisible(False)
self.mMapCanvas.setLayers([self.mTemporalProfileLayer])
# self.tpCollectionListModel = TemporalProfileCollectionListModel(self.tpCollection)

Benjamin Jakimow
committed
assert isinstance(self.ui.mDualView, QgsDualView)
self.ui.mDualView.init(self.mTemporalProfileLayer, self.mMapCanvas)
self.ui.mDualView.setView(QgsDualView.AttributeTable)
# pixel loader to load pixel values in parallel
config = QgsAttributeTableConfig()
config.update(self.mTemporalProfileLayer.fields())
config.setActionWidgetVisible(False)

Benjamin Jakimow
committed
hidden = []
for i, columnConfig in enumerate(config.columns()):
assert isinstance(columnConfig, QgsAttributeTableConfig.ColumnConfig)
config.setColumnHidden(i, columnConfig.name in hidden)

Benjamin Jakimow
committed
self.mTemporalProfilesTableConfig = config
self.mTemporalProfileLayer.setAttributeTableConfig(self.mTemporalProfilesTableConfig)
#self.pixelLoader = PixelLoader()
#self.pixelLoader.sigPixelLoaded.connect(self.onPixelLoaded)
#self.pixelLoader.sigLoadingStarted.connect(self.onLoadingStarted)
#self.pixelLoader.sigLoadingFinished.connect(self.onLoadingFinished)
#self.pixelLoader.sigProgressChanged.connect(self.onLoadingProgressChanged)

Benjamin Jakimow
committed
# set the plot models for 2D
self.plotSettingsModel2D = PlotSettingsModel2D()
self.plotSettingsModel2DProxy = QSortFilterProxyModel()
self.plotSettingsModel2DProxy.setSourceModel(self.plotSettingsModel2D)
self.ui.tableView2DProfiles.setModel(self.plotSettingsModel2DProxy)
self.ui.tableView2DProfiles.setSortingEnabled(True)
self.ui.tableView2DProfiles.selectionModel().selectionChanged.connect(self.onPlot2DSelectionChanged)
self.ui.tableView2DProfiles.horizontalHeader().setResizeMode(QHeaderView.Interactive)
self.plotSettingsModel2D.sigDataChanged.connect(self.requestUpdate)
self.plotSettingsModel2D.rowsInserted.connect(self.onRowsInserted2D)
self.delegateTableView2D = PlotSettingsModel2DWidgetDelegate(self.ui.tableView2DProfiles, self.mTemporalProfileLayer)
self.delegateTableView2D.setItemDelegates(self.ui.tableView2DProfiles)
#self.ui.tableView2DProfiles.horizontalHeader().sectionResized.connect(self.on2DSettingsTableColumnResize)

Benjamin Jakimow
committed
# set the plot models for 3D
self.plotSettingsModel3D = PlotSettingsModel3D()
self.ui.tableView3DProfiles.setModel(self.plotSettingsModel3D)
self.ui.tableView3DProfiles.setSortingEnabled(False)
self.ui.tableView2DProfiles.selectionModel().selectionChanged.connect(self.onPlot3DSelectionChanged)
self.ui.tableView3DProfiles.horizontalHeader().setResizeMode(QHeaderView.Interactive)
self.plotSettingsModel3D.rowsInserted.connect(self.onRowsInserted3D)
self.delegateTableView3D = PlotSettingsModel3DWidgetDelegate(self.ui.tableView3DProfiles, self.mTemporalProfileLayer)
self.delegateTableView3D.setItemDelegates(self.ui.tableView3DProfiles)

Benjamin Jakimow
committed
if not ENABLE_OPENGL:
self.ui.listWidget.item(1).setHidden(True)
self.ui.page3D.setHidden(True)

Benjamin Jakimow
committed
def onTemporalProfilesRemoved(removedProfiles):
#set to valid temporal profile

Benjamin Jakimow
committed
affectedStyles2D = [p for p in self.plotSettingsModel2D if p.temporalProfile() in removedProfiles]
affectedStyles3D = [p for p in self.plotSettingsModel3D if p.temporalProfile() in removedProfiles]
alternativeProfile = self.mTemporalProfileLayer[-1] if len(self.mTemporalProfileLayer) > 0 else None
for s in affectedStyles2D:
assert isinstance(s, TemporalProfile2DPlotStyle)
m = self.plotSettingsModel2D
idx = m.plotStyle2idx(s)
idx = m.createIndex(idx.row(), m.columnNames.index(m.cnTemporalProfile))
m.setData(idx, alternativeProfile, Qt.EditRole)

Benjamin Jakimow
committed
for s in affectedStyles3D:
assert isinstance(s, TemporalProfile3DPlotStyle)
m = self.plotSettingsModel3D
idx = m.plotStyle2idx(s)
idx = m.createIndex(idx.row(), m.columnNames.index(m.cnTemporalProfile))
m.setData(idx, alternativeProfile, Qt.EditRole)

Benjamin Jakimow
committed
self.mTemporalProfileLayer.sigTemporalProfilesRemoved.connect(onTemporalProfilesRemoved)

Benjamin Jakimow
committed
# remove / add plot style
def on2DPlotStyleRemoved(plotStyles):
for plotStyle in plotStyles:
assert isinstance(plotStyle, PlotStyle)
for pi in plotStyle.mPlotItems:
self.plot2D.plotItem.removeItem(pi)

Benjamin Jakimow
committed
def on3DPlotStyleRemoved(plotStyles):
toRemove = []
for plotStyle in plotStyles:
assert isinstance(plotStyle, TemporalProfile3DPlotStyle)
toRemove.append(plotStyle.mPlotItems)
self.plot3D.removeItems(toRemove)

benjamin.jakimow@geo.hu-berlin.de
committed

Benjamin Jakimow
committed
self.plotSettingsModel2D.sigPlotStylesRemoved.connect(on2DPlotStyleRemoved)
self.plotSettingsModel3D.sigPlotStylesRemoved.connect(on3DPlotStyleRemoved)
# initialize the update loop
self.updateRequested = True

Benjamin Jakimow
committed
self.updateTimer = QTimer(self)
self.updateTimer.timeout.connect(self.onDataUpdate)
self.updateTimer.start(2000)

Benjamin Jakimow
committed
self.sigMoveToDate.connect(self.onMoveToDate)

Benjamin Jakimow
committed

Benjamin Jakimow
committed
self.initActions()
#self.ui.stackedWidget.setCurrentPage(self.ui.pagePixel)
self.ui.onStackPageChanged(self.ui.stackedWidget.currentIndex())

Benjamin Jakimow
committed

Benjamin Jakimow
committed
def onLoadingStarted(self):
self.ui.progressInfo.setText('Start loading...')
self.ui.progressBar.setRange(0, 0)
self.ui.progressBar.setValue(0)
def onLoadingProgressChanged(self, progress):
if self.ui.progressBar.maximum() == 0:
self.ui.progressBar.setRange(0, 100)
value = int(progress)
self.ui.progressBar.setValue(value)
if value == 100:
self.plot2D.enableAutoRange('x', False)
self.ui.progressInfo.setText('')
self.ui.progressBar.setValue(0)

Benjamin Jakimow
committed

Benjamin Jakimow
committed
def plotStyles(self):
return self.plotSettingsModel2D[:]

Benjamin Jakimow
committed
def temporalProfileLayer(self)->TemporalProfileLayer:

Benjamin Jakimow
committed
Returns a QgsVectorLayer that is used to store profile coordinates.
:return:

Benjamin Jakimow
committed
return self.mTemporalProfileLayer

Benjamin Jakimow
committed
def selected2DPlotStyles(self):
result = []

Benjamin Jakimow
committed
m = self.ui.tableView2DProfiles.model()
for idx in selectedModelIndices(self.ui.tableView2DProfiles):
result.append(m.data(idx, Qt.UserRole))
return result

Benjamin Jakimow
committed
def removePlotStyles2D(self, plotStyles):
m = self.ui.tableView2DProfiles.model()
if isinstance(m.sourceModel(), PlotSettingsModel2D):
m.sourceModel().removePlotStyles(plotStyles)

Benjamin Jakimow
committed
def removeTemporalProfiles(self, fids):

Benjamin Jakimow
committed
self.mTemporalProfileLayer.selectByIds(fids)
b = self.mTemporalProfileLayer.isEditable()
self.mTemporalProfileLayer.startEditing()
self.mTemporalProfileLayer.deleteSelectedFeatures()
self.mTemporalProfileLayer.saveEdits(leaveEditable=b)

Benjamin Jakimow
committed
def createNewPlotStyle2D(self):
l = len(self.mTemporalProfileLayer)

Benjamin Jakimow
committed
plotStyle = TemporalProfile2DPlotStyle()
plotStyle.sigExpressionUpdated.connect(self.updatePlot2D)

Benjamin Jakimow
committed
sensors = self.TS.sensors()
if len(sensors) > 0:
plotStyle.setSensor(sensors[0])

Benjamin Jakimow
committed
if len(self.mTemporalProfileLayer) > 0:
temporalProfile = self.mTemporalProfileLayer[0]
plotStyle.setTemporalProfile(temporalProfile)

Benjamin Jakimow
committed
if len(self.plotSettingsModel2D) > 0:
lastStyle = self.plotSettingsModel2D[0] #top style in list is the most-recent
assert isinstance(lastStyle, TemporalProfile2DPlotStyle)
markerColor = nextColor(lastStyle.markerBrush.color())
plotStyle.markerBrush.setColor(markerColor)
self.plotSettingsModel2D.insertPlotStyles([plotStyle], i=0)
pdi = plotStyle.createPlotItem(self.plot2D)

Benjamin Jakimow
committed
assert isinstance(pdi, TemporalProfilePlotDataItem)
#pdi.sigClicked.connect(self.onProfileClicked2D)
#pdi.sigPointsClicked.connect(self.onPointsClicked2D)

Benjamin Jakimow
committed
self.plot2D.plotItem.addItem(pdi)
#self.plot2D.getPlotItem().addItem(pg.PlotDataItem(x=[1, 2, 3], y=[1, 2, 3]))
#plotItem.addDataItem(pdi)
#plotItem.plot().sigPlotChanged.emit(plotItem)
self.updatePlot2D()
return plotStyle

Benjamin Jakimow
committed
def createNewPlotStyle3D(self):
if not (ENABLE_OPENGL and OPENGL_AVAILABLE):
return

Benjamin Jakimow
committed
plotStyle = TemporalProfile3DPlotStyle()
plotStyle.sigExpressionUpdated.connect(self.updatePlot3D)

Benjamin Jakimow
committed
if len(self.mTemporalProfileLayer) > 0:
temporalProfile = self.mTemporalProfileLayer[0]
plotStyle.setTemporalProfile(temporalProfile)
if len(self.plotSettingsModel3D) > 0:
color = self.plotSettingsModel3D[-1].color()
plotStyle.setColor(nextColor(color))

benjamin.jakimow@geo.hu-berlin.de
committed

Benjamin Jakimow
committed
sensors = list(self.TS.mSensors2TSDs.keys())
if len(sensors) > 0:
plotStyle.setSensor(sensors[0])

benjamin.jakimow@geo.hu-berlin.de
committed

Benjamin Jakimow
committed
self.plotSettingsModel3D.insertPlotStyles([plotStyle], i=0) # latest to the top
plotItems = plotStyle.createPlotItem()
self.plot3D.addItems(plotItems)
#self.updatePlot3D()
def onPointsClicked2D(self, event: MouseClickEvent):
assert isinstance(event, MouseClickEvent)
for item in self.plot2D.scene().itemsNearEvent(event):
if isinstance(item, ScatterPlotItem) and isinstance(item.parentItem(), TemporalProfilePlotDataItem):
pdi = item.parentItem()
assert isinstance(pdi, TemporalProfilePlotDataItem)
tp = pdi.mPlotStyle.temporalProfile()
assert isinstance(tp, TemporalProfile)

Benjamin Jakimow
committed
c = tp.coordinate()
spottedItems = item.pointsAt(event.pos())
if len(spottedItems) > 0:
info.append('Sensor: {}'.format(pdi.mPlotStyle.sensor().name()))
info.append('Coordinate: {}, {}'.format(c.x(), c.y()))
for item in spottedItems:
if isinstance(item, SpotItem):
brush1 = item.brush()
brush2 = item.brush()
brush2.setColor(QColor('yellow'))
item.setBrush(brush2)
QTimer.singleShot(500, lambda *args, spotItem=item, brush=brush1: spotItem.setBrush(brush))
pos = item.pos()
self.mLast2DMouseClickPosition = pos
x = pos.x()
y = pos.y()
date = num2date(x)
info.append('{};{}'.format(date, y))
self.ui.tbInfo2D.setPlainText('\n'.join(info))

Benjamin Jakimow
committed
def onTemporalProfilesAdded(self, profiles):
# self.mTemporalProfileLayer.prune()
for plotStyle in self.plotSettingsModel3D:
assert isinstance(plotStyle, TemporalProfilePlotStyleBase)
if not isinstance(plotStyle.temporalProfile(), TemporalProfile):

Benjamin Jakimow
committed
r = self.plotSettingsModel3D.plotStyle2idx(plotStyle).row()
c = self.plotSettingsModel3D.columnIndex(self.plotSettingsModel3D.cnTemporalProfile)
idx = self.plotSettingsModel3D.createIndex(r, c)
self.plotSettingsModel3D.setData(idx, self.mTemporalProfileLayer[0])

Benjamin Jakimow
committed
def onTemporalProfileSelectionChanged(self, selectedFIDs, deselectedFIDs):
nSelected = len(selectedFIDs)

Benjamin Jakimow
committed
self.ui.actionRemoveTemporalProfile.setEnabled(nSelected > 0)

Benjamin Jakimow
committed
def onPlot2DSelectionChanged(self, selected, deselected):

benjamin.jakimow@geo.hu-berlin.de
committed

Benjamin Jakimow
committed
self.ui.actionRemoveStyle2D.setEnabled(len(selected) > 0)

Benjamin Jakimow
committed
def onPlot3DSelectionChanged(self, selected, deselected):

Benjamin Jakimow
committed
self.ui.actionRemoveStyle3D.setEnabled(len(selected) > 0)

Benjamin Jakimow
committed
def initActions(self):

Benjamin Jakimow
committed
self.ui.actionRemoveStyle2D.setEnabled(False)
self.ui.actionRemoveTemporalProfile.setEnabled(False)
self.ui.actionAddStyle2D.triggered.connect(self.createNewPlotStyle2D)
self.ui.actionAddStyle3D.triggered.connect(self.createNewPlotStyle3D)
self.ui.actionRefresh2D.triggered.connect(self.updatePlot2D)
self.ui.actionRefresh3D.triggered.connect(self.updatePlot3D)
self.ui.actionRemoveStyle2D.triggered.connect(lambda:self.removePlotStyles2D(self.selected2DPlotStyles()))
self.ui.actionRemoveTemporalProfile.triggered.connect(lambda :self.removeTemporalProfiles(self.mTemporalProfileLayer.selectedFeatureIds()))
self.ui.actionToggleEditing.triggered.connect(self.onToggleEditing)
self.ui.actionReset2DPlot.triggered.connect(self.plot2D.resetViewBox)
self.plot2D.resetTransform()
self.ui.actionReset3DCamera.triggered.connect(self.reset3DCamera)
self.ui.actionLoadTPFromOgr.triggered.connect(self.onLoadFromVector)

Benjamin Jakimow
committed
self.ui.actionLoadMissingValues.triggered.connect(lambda: self.loadMissingData())
self.ui.actionSaveTemporalProfiles.triggered.connect(lambda *args : self.mTemporalProfileLayer.saveTemporalProfiles(None))

Benjamin Jakimow
committed
#set actions to be shown in the TemporalProfileTableView context menu
ma = [self.ui.actionSaveTemporalProfiles, self.ui.actionLoadMissingValues]

Benjamin Jakimow
committed
self.onEditingToggled()
def onLoadFromVector(self):
from .externals.qps.layerproperties import SelectMapLayersDialog
d = SelectMapLayersDialog()
d.addLayerDescription('Vector Layer', QgsMapLayerProxyModel.VectorLayer)
d.setWindowTitle('Select Vector Layer')
if d.exec() == QDialog.Accepted:
for l in d.mapLayers():
self.mTemporalProfileLayer.loadCoordinatesFromOgr(l.source())
break

Benjamin Jakimow
committed
def onToggleEditing(self, b):

Benjamin Jakimow
committed
if self.mTemporalProfileLayer.isEditable():
self.mTemporalProfileLayer.saveEdits(leaveEditable=False)
else:
self.mTemporalProfileLayer.startEditing()
self.onEditingToggled()

Benjamin Jakimow
committed
def onEditingToggled(self):
lyr = self.mTemporalProfileLayer

Benjamin Jakimow
committed

Benjamin Jakimow
committed
hasSelectedFeatures = lyr.selectedFeatureCount() > 0
isEditable = lyr.isEditable()
self.ui.actionToggleEditing.blockSignals(True)
self.ui.actionToggleEditing.setChecked(isEditable)
#self.actionSaveTemporalProfiles.setEnabled(isEditable)
#self.actionReload.setEnabled(not isEditable)
self.ui.actionToggleEditing.blockSignals(False)

Benjamin Jakimow
committed

Benjamin Jakimow
committed
#self.actionAddAttribute.setEnabled(isEditable)
#self.actionRemoveAttribute.setEnabled(isEditable)
self.ui.actionRemoveTemporalProfile.setEnabled(isEditable and hasSelectedFeatures)
#self.actionPasteFeatures.setEnabled(isEditable)
self.ui.actionToggleEditing.setEnabled(not lyr.readOnly())

Benjamin Jakimow
committed
def reset3DCamera(self, *args):

Benjamin Jakimow
committed
if ENABLE_OPENGL and OPENGL_AVAILABLE:
self.ui.actionReset3DCamera.trigger()
sigMoveToTSD = pyqtSignal(TimeSeriesDate)

Benjamin Jakimow
committed
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, qgsTask ,dump)->typing.List[TemporalProfile]:
"""
Updates TemporalProfiles
:param qgsTask:
:param dump:
:return: [updated TemporalProfiles]
"""
tasks = pickle.loads(dump)
assert isinstance(tasks, list)
s = ""
t0 = time.time()
updatedTemporalProfiles = []
for task in tasks:
assert isinstance(task, TemporalProfileLoaderTask)
if len(task.mRESULTS) > 0:
for tpId, data in task.mRESULTS.items():
tp = self.mTemporalProfileLayer.mProfiles.get(tpId)
if isinstance(tp, TemporalProfile):
tsd = tp.timeSeries().getTSD(task.mSourcePath)
if isinstance(tsd, TimeSeriesDate):
tp.updateData(tsd, data)
if tp not in updatedTemporalProfiles:
updatedTemporalProfiles.append(tp)
if len(task.mERRORS) > 0:
s = ""
return updatedTemporalProfiles
print('WRESULTS {}'.format(time.time() - t0))

Benjamin Jakimow
committed
def requestUpdate(self, *args):
self.updateRequested = True
#next time

Benjamin Jakimow
committed
def onRowsInserted2D(self, parent, start, end):
model = self.ui.tableView2DProfiles.model().sourceModel()
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.ui.tableView2DProfiles.openPersistentEditor(idxExpr)
self.ui.tableView2DProfiles.openPersistentEditor(idxStyle)
start += 1

Benjamin Jakimow
committed
def onRowsInserted3D(self, parent, start, end):
model = self.ui.tableView3DProfiles.model()
if isinstance(model, PlotSettingsModel3D):
colExpression = model.columnIndex(model.cnExpression)
colStyle = model.columnIndex(model.cnStyle)
while start <= end:
idxStyle = model.createIndex(start, colStyle)
idxExpr = model.createIndex(start, colExpression)
self.ui.tableView3DProfiles.openPersistentEditor(idxStyle)
self.ui.tableView3DProfiles.openPersistentEditor(idxExpr)
start += 1
def loadMissingData(self, backgroundProcess=True):

Benjamin Jakimow
committed
"""
Loads all band values of collected locations that have not been loaded until now
"""

Benjamin Jakimow
committed
fids = self.mTemporalProfileLayer.selectedFeatureIds()
if len(fids) == 0:
fids = [f.id() for f in self.mTemporalProfileLayer.getFeatures()]

Benjamin Jakimow
committed
tps = [self.mTemporalProfileLayer.mProfiles.get(fid) for fid in fids]
spatialPoints = [tp.coordinate() for tp in tps if isinstance(tp, TemporalProfile)]
self.loadCoordinate(spatialPoints=spatialPoints, mode='all', backgroundProcess=backgroundProcess)

Benjamin Jakimow
committed
LOADING_MODES = ['missing', 'reload', 'all']
def loadCoordinate(self, spatialPoints=None, LUT_bandIndices=None, mode='missing', backgroundProcess = True):
"""
:param spatialPoints: [list-of-geometries] to load pixel values from
:param LUT_bandIndices: dictionary {sensor:[indices]} with band indices to be loaded per sensor
:param mode:
:return:
"""
"""
Loads a temporal profile for a single or multiple geometries.
:param spatialPoints: SpatialPoint | [list-of-SpatialPoints]
"""
assert mode in SpectralTemporalVisualization.LOADING_MODES
if isinstance(spatialPoints, SpatialPoint):
spatialPoints = [spatialPoints]

Benjamin Jakimow
committed
assert isinstance(spatialPoints, list)

Benjamin Jakimow
committed
if not isinstance(self.plotSettingsModel2D, PlotSettingsModel2D):
return False

Benjamin Jakimow
committed
# if not self.pixelLoader.isReadyToLoad():
# return False

Benjamin Jakimow
committed
assert isinstance(self.TS, TimeSeries)

Benjamin Jakimow
committed
# Get or create the TimeSeriesProfiles which will store the loaded values
tasks = []

Benjamin Jakimow
committed
# Define which (new) bands need to be loaded for each sensor
if LUT_bandIndices is None:
LUT_bandIndices = dict()
for sensor in self.TS.sensors():
if mode in ['all', 'reload']:
LUT_bandIndices[sensor] = list(range(sensor.nb))
else:
LUT_bandIndices[sensor] = self.plotSettingsModel2D.requiredBandsIndices(sensor)

Benjamin Jakimow
committed
assert isinstance(LUT_bandIndices, dict)
for sensor in self.TS.sensors():
assert sensor in LUT_bandIndices.keys()

Benjamin Jakimow
committed
# update new / existing points

Benjamin Jakimow
committed
for spatialPoint in spatialPoints:
assert isinstance(spatialPoint, SpatialPoint)
TP = self.mTemporalProfileLayer.fromSpatialPoint(spatialPoint)
# if no TemporalProfile existed before, create an empty one

Benjamin Jakimow
committed
if not isinstance(TP, TemporalProfile):
TP = self.mTemporalProfileLayer.createTemporalProfiles(spatialPoint)[0]
# set existing plot style to current coordinate
for plotStyle in self.plotSettingsModel2D:
assert isinstance(plotStyle, TemporalProfile2DPlotStyle)
if plotStyle.showLastLocation():
r = self.plotSettingsModel2D.plotStyle2idx(plotStyle).row()
c = self.plotSettingsModel2D.columnIndex(self.plotSettingsModel2D.cnTemporalProfile)
idx = self.plotSettingsModel2D.index(r, c)
self.plotSettingsModel2D.setData(idx, TP, role=Qt.EditRole)
plotStyle.setTemporalProfile(TP)
# create at least 1 plot style

Benjamin Jakimow
committed
if len(self.mTemporalProfileLayer) == 1:
if len(self.plotSettingsModel2D) == 0:
self.createNewPlotStyle2D()
if len(self.plotSettingsModel3D) == 0:
self.createNewPlotStyle3D()

Benjamin Jakimow
committed
# each TSD is a Task
s = ""
# a Task defines which bands are to be loaded
for tsd in self.TS:
assert isinstance(tsd, TimeSeriesDate)

Benjamin Jakimow
committed
# do not load from invisible TSDs
if not tsd.isVisible():
continue

Benjamin Jakimow
committed
# which bands do we need to load?
requiredIndices = set(LUT_bandIndices[tsd.sensor()])
if len(requiredIndices) == 0:
continue

Benjamin Jakimow
committed
if mode == 'missing':
missingIndices = set()

Benjamin Jakimow
committed
assert isinstance(TP, TemporalProfile)
need2load = TP.missingBandIndices(tsd, requiredIndices=requiredIndices)
missingIndices = missingIndices.union(need2load)

Benjamin Jakimow
committed
missingIndices = sorted(list(missingIndices))
else:
missingIndices = requiredIndices

Benjamin Jakimow
committed
if len(missingIndices) > 0:
for tss in tsd.sources():
assert isinstance(tss, TimeSeriesSource)
assert isinstance(TP, TemporalProfile)
if tssExtent.contains(TP.coordinate().toCrs(tssExtent.crs())):
intersectingTPs.append(TP)
if len(intersectingTPs) > 0:
task = TemporalProfileLoaderTask(tss, intersectingTPs)
tasks.append(task)
# pickle.loads(doLoaderTask(mock, pickle.dumps([t])))[0]
if len(tasks) > 0:
self.loadTemporalProfileTasks(tasks, runAsync=backgroundProcess)

Benjamin Jakimow
committed
else:
if DEBUG:
print('Data for geometries already loaded')
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
def loadTemporalProfileTasks(self, tasks:typing.Iterable[TemporalProfileLoaderTask], runAsync=True)->typing.List[TemporalProfile]:
"""
Loads data into TemporalProfiles
:param tasks:
:param runAsync:
:return: [list-of-updated TemporalProfiles], empty if runAsyn
"""
dump = pickle.dumps(tasks)
if runAsync:
qgsTask = QgsTask.fromFunction('Load Profiles', doLoadTemporalProfileTasks, dump,
on_finished=self.onPixelLoaded)
else:
qgsTask = TaskMock()
tid = id(qgsTask)
qgsTask.progressChanged.connect(self.onLoadingProgressChanged)
qgsTask.taskCompleted.connect(lambda *args, tid=tid: self.onRemoveTask(tid))
qgsTask.taskTerminated.connect(lambda *args, tid=tid: self.onRemoveTask(tid))
self.mTasks[tid] = qgsTask
if runAsync:
tm = QgsApplication.taskManager()
assert isinstance(tm, QgsTaskManager)
tm.addTask(qgsTask, 1000)
return []
else:
return self.onPixelLoaded(qgsTask, doLoadTemporalProfileTasks(qgsTask, dump))
def onRemoveTask(self, tid):
if tid in self.mTasks.keys():
del self.mTasks[tid]

Benjamin Jakimow
committed
@QtCore.pyqtSlot()
def onDataUpdate(self):

Benjamin Jakimow
committed
# self.mTemporalProfileLayer.prune()

Benjamin Jakimow
committed
for plotSetting in self.plotSettingsModel2D:
assert isinstance(plotSetting, TemporalProfile2DPlotStyle)
tp = plotSetting.temporalProfile()
for pdi in plotSetting.mPlotItems:
assert isinstance(pdi, TemporalProfilePlotDataItem)
pdi.updateDataAndStyle()
if isinstance(tp, TemporalProfile) and plotSetting.temporalProfile().updated():
plotSetting.temporalProfile().resetUpdatedFlag()

Benjamin Jakimow
committed
for i in self.plot2D.plotItem.dataItems:
i.updateItems()

Benjamin Jakimow
committed
notInit = [0, 1] == self.plot2D.plotItem.getAxis('bottom').range
if notInit:
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
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)

Benjamin Jakimow
committed
if x0 is not None:
self.plot2D.plotItem.setXRange(x0, x1)

Benjamin Jakimow
committed
# self.plot2D.xAxisInitialized = True

Benjamin Jakimow
committed
@QtCore.pyqtSlot()
def updatePlot3D(self):
if ENABLE_OPENGL and OPENGL_AVAILABLE:

Benjamin Jakimow
committed
from eotimeseriesviewer.temporalprofiles3dGL import ViewWidget3D
assert isinstance(self.plot3D, ViewWidget3D)

Benjamin Jakimow
committed
# 1. ensure that data from all bands will be loaded
# new loaded values will be shown in the next updatePlot3D call
coordinates = []
allPlotItems = []
for plotStyle3D in self.plotSettingsModel3D:
assert isinstance(plotStyle3D, TemporalProfile3DPlotStyle)
if plotStyle3D.isPlotable():
coordinates.append(plotStyle3D.temporalProfile().coordinate())

Benjamin Jakimow
committed
if len(coordinates) > 0:
self.loadCoordinate(coordinates, mode='all')

Benjamin Jakimow
committed
toRemove = [item for item in self.plot3D.items if item not in allPlotItems]
self.plot3D.removeItems(toRemove)
toAdd = [item for item in allPlotItems if item not in self.plot3D.items]
self.plot3D.addItems(toAdd)

Benjamin Jakimow
committed
"""
# 3. add new plot items
plotItems = []
for plotStyle3D in self.plotSettingsModel3D:
assert isinstance(plotStyle3D, TemporalProfile3DPlotStyle)
if plotStyle3D.isPlotable():
items = plotStyle3D.createPlotItem(None)
plotItems.extend(items)

Benjamin Jakimow
committed
self.plot3D.addItems(plotItems)
self.plot3D.updateDataRanges()
self.plot3D.resetScaling()
"""

Benjamin Jakimow
committed
@QtCore.pyqtSlot()
def updatePlot2D(self):
if isinstance(self.plotSettingsModel2D, PlotSettingsModel2D):

Benjamin Jakimow
committed
locations = set()
for plotStyle in self.plotSettingsModel2D:
assert isinstance(plotStyle, TemporalProfile2DPlotStyle)
if plotStyle.isPlotable():
locations.add(plotStyle.temporalProfile().coordinate())

Benjamin Jakimow
committed
for pdi in plotStyle.mPlotItems:
assert isinstance(pdi, TemporalProfilePlotDataItem)
pdi.updateDataAndStyle()

Benjamin Jakimow
committed
#2. load pixel data
self.loadCoordinate(list(locations))

Benjamin Jakimow
committed
# https://github.com/pyqtgraph/pyqtgraph/blob/5195d9dd6308caee87e043e859e7e553b9887453/examples/customPlot.py
return
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
# 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 eotimeseriesviewer.utils import file_search
searchDir = r'H:\LandsatData\Landsat_NovoProgresso'
files = list(file_search(searchDir, '*227065*band4.img', recursive=True))
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
#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()