Newer
Older

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
1056
1057
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
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
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
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

Benjamin Jakimow
committed
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
self.plot2D.getViewBox().sigMoveToDate.connect(self.sigMoveToDate)
self.plot3D = self.ui.plotWidget3D

Benjamin Jakimow
committed
# temporal profile collection to store loaded values
self.mTemporalProfileLayer = TemporalProfileLayer(self.TS)
self.mTemporalProfileLayer.sigTemporalProfilesAdded.connect(self.onTemporalProfilesAdded)
#self.mTemporalProfileLayer.startEditing()
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)

Benjamin Jakimow
committed
self.pixelLoader = PixelLoader()
self.pixelLoader.sigPixelLoaded.connect(self.onPixelLoaded)
self.pixelLoader.sigLoadingStarted.connect(lambda: self.ui.progressInfo.setText('Start loading...'))
# self.pixelLoader.sigLoadingStarted.connect(self.tpCollection.prune)
self.pixelLoader.sigLoadingFinished.connect(lambda: self.plot2D.enableAutoRange('x', False))

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 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 onTemporalProfilesContextMenu(self, event):
assert isinstance(event, QContextMenuEvent)
tableView = self.ui.tableViewTemporalProfiles
selectionModel = self.ui.tableViewTemporalProfiles.selectionModel()
assert isinstance(selectionModel, QItemSelectionModel)

Benjamin Jakimow
committed
model = self.ui.tableViewTemporalProfiles.model()
assert isinstance(model, TemporalProfileLayer)

Benjamin Jakimow
committed
temporalProfiles = []

Benjamin Jakimow
committed
if len(selectionModel.selectedIndexes()) > 0:
for idx in selectionModel.selectedIndexes():
tp = model.idx2tp(idx)
if isinstance(tp, TemporalProfile) and not tp in temporalProfiles:
temporalProfiles.append(tp)
else:
temporalProfiles = model[:]

Benjamin Jakimow
committed
spatialPoints = [tp.coordinate() for tp in temporalProfiles]

Benjamin Jakimow
committed
menu = QMenu()

Benjamin Jakimow
committed
a = menu.addAction('Load missing')
a.setToolTip('Loads missing band-pixels.')
a.triggered.connect(lambda : self.loadCoordinate(spatialPoints=spatialPoints, mode='all'))
s = ""

Benjamin Jakimow
committed
a = menu.addAction('Reload')
a.setToolTip('Reloads all band-pixels.')
a.triggered.connect(lambda: self.loadCoordinate(spatialPoints=spatialPoints, mode='reload'))

Benjamin Jakimow
committed
menu.popup(tableView.viewport().mapToGlobal(event.pos()))
self.menu = menu

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

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)
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()

Benjamin Jakimow
committed
def onProfileClicked2D(self, pdi):
if isinstance(pdi, TemporalProfilePlotDataItem):
sensor = pdi.mPlotStyle.sensor()
tp = pdi.mPlotStyle.temporalProfile()
if isinstance(tp, TemporalProfile) and isinstance(sensor, SensorInstrument):
c = tp.coordinate()
info = ['Sensor:{}'.format(sensor.name()),
'Coordinate:{}, {}'.format(c.x(), c.y())]
self.ui.tbInfo2D.setPlainText('\n'.join(info))

Benjamin Jakimow
committed
def onPointsClicked2D(self, pdi, spottedItems):

Benjamin Jakimow
committed
if isinstance(pdi, TemporalProfilePlotDataItem) and isinstance(spottedItems, list):
sensor = pdi.mPlotStyle.sensor()
tp = pdi.mPlotStyle.temporalProfile()
if isinstance(tp, TemporalProfile) and isinstance(sensor, SensorInstrument):
c = tp.coordinate()
info.append('Sensor: {}'.format(sensor.name()))
info.append('Coordinate: {}, {}'.format(c.x(), c.y()))

Benjamin Jakimow
committed
for item in spottedItems:
pos = item.pos()
x = pos.x()
y = pos.y()
date = num2date(x)
info.append('Date: {}\nValue: {}'.format(date, y))
else:
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(lambda : self.mTemporalProfileLayer.loadCoordinatesFromOgr(None))
self.ui.actionLoadMissingValues.triggered.connect(lambda: self.loadMissingData())
self.ui.actionSaveTemporalProfiles.triggered.connect(lambda *args : self.mTemporalProfileLayer.saveTemporalProfiles)
#set actions to be shown in the TemporalProfileTableView context menu
ma = [self.ui.actionSaveTemporalProfiles, self.ui.actionLoadMissingValues]

Benjamin Jakimow
committed
self.onEditingToggled()

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])

Benjamin Jakimow
committed
def onPixelLoaded(self, d):

Benjamin Jakimow
committed
if isinstance(d, PixelLoaderTask):

Benjamin Jakimow
committed
bn = os.path.basename(d.sourcePath)
if d.success():

Benjamin Jakimow
committed
t = 'Loaded {} pixel from {}.'.format(len(d.resProfiles), bn)
self.mTemporalProfileLayer.addPixelLoaderResult(d)
self.updateRequested = True
else:
t = 'Failed loading from {}.'.format(bn)
if d.info and d.info != '':
t += '({})'.format(d.info)

Benjamin Jakimow
committed
# QgsApplication.processEvents()
self.ui.progressInfo.setText(t)

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

Benjamin Jakimow
committed
def onObservationClicked(self, plotDataItem, points):
for p in points:
tsd = p.data()
#print(tsd)

Benjamin Jakimow
committed
def loadMissingData(self, backgroundProcess=False):
"""
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

Benjamin Jakimow
committed
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

Benjamin Jakimow
committed
tasks = []
TPs = []
theGeometries = []

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 TemporaProfile existed before, create an empty one
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
TPs.append(TP)
theGeometries.append(TP.coordinate())

Benjamin Jakimow
committed
TP_ids = [TP.id() for TP in TPs]
# 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
for TP in TPs:
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 pathImg in tsd.sourceUris():
task = PixelLoaderTask(pathImg, theGeometries,
bandIndices=missingIndices,
temporalProfileIDs=TP_ids)
tasks.append(task)

Benjamin Jakimow
committed
if len(tasks) > 0:

Benjamin Jakimow
committed
if DEBUG:
print('Start loading for {} geometries from {} sources...'.format(
len(theGeometries), len(tasks)
))
if backgroundProcess:
self.pixelLoader.startLoading(tasks)
else:
import eotimeseriesviewer.pixelloader
tasks = [PixelLoaderTask.fromDump(eotimeseriesviewer.pixelloader.doLoaderTask(None, task.toDump())) for task in tasks]
l = len(tasks)
for i, task in enumerate(tasks):
self.pixelLoader.sigPixelLoaded.emit(task)

Benjamin Jakimow
committed
else:
if DEBUG:
print('Data for geometries already loaded')

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)