Newer
Older

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