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
from .externals.qps.plotstyling.plotstyling import PlotStyle, PlotStyleButton
from .externals import pyqtgraph as pg
from .sensorvisualization import SensorListModel
from .temporalprofiles2d import *
from .temporalprofiles3d import *
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 = []
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))
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
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)
def requiredBandsIndices(self, sensor):
"""
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):
value = tp.name()
else:
value = 'undefined'
if role == Qt.DecorationRole:
if columnName == self.cnStyle:
value = plotStyle.createIcon(QSize(25,25))
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
class ProfileViewDockUI(QgsDockWidget, loadUI('profileviewdock.ui')):
def __init__(self, parent=None):
super(ProfileViewDockUI, self).__init__(parent)
self.setupUi(self)
self.addActions(self.findChildren(QAction))
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)
self.plotWidget3D = None
self.plotWidget3DMPL = None
self.init3DWidgets('gl')
#pi = self.plotWidget2D.plotItem
#ax = DateAxis(orientation='bottom', showValues=True)
#pi.layout.addItem(ax, 3,2)

benjamin.jakimow@geo.hu-berlin.de
committed
self.progressBar.setMinimum(0)
self.progressBar.setMaximum(100)
self.progressBar.setValue(0)
self.progressInfo.setText('')
self.pxViewModel2D = None
self.pxViewModel3D = None
self.tableView2DProfiles.horizontalHeader().setResizeMode(QHeaderView.Interactive)
def init3DWidgets(self, mode='gl'):
assert mode in ['gl']
l = self.frame3DPlot.layout()
if ENABLE_OPENGL and OPENGL_AVAILABLE and mode == 'gl':
from eotimeseriesviewer.temporalprofiles3dGL import ViewWidget3D
self.plotWidget3D = ViewWidget3D(parent=self.labelDummy3D.parent())
self.plotWidget3D.setObjectName('plotWidget3D')
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)
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)
w.update()
self.setWindowTitle(title)
class SpectralTemporalVisualization(QObject):

benjamin.jakimow@geo.hu-berlin.de
committed
sigShowPixel = pyqtSignal(TimeSeriesDatum, QgsPoint, QgsCoordinateReferenceSystem)
"""
Signalizes to move to specific date of interest
"""
sigMoveToDate = pyqtSignal(np.datetime64)

benjamin.jakimow@geo.hu-berlin.de
committed
def __init__(self, timeSeries, profileDock):
super(SpectralTemporalVisualization, self).__init__()
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)
# 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)
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(True)
hidden = [FN_ID]
for i, columnConfig in enumerate(config.columns()):
assert isinstance(columnConfig, QgsAttributeTableConfig.ColumnConfig)
config.setColumnHidden(i, columnConfig.name in hidden)
self.mTemporalProfilesTableConfig = config
self.mTemporalProfileLayer.setAttributeTableConfig(self.mTemporalProfilesTableConfig)
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))
# 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)
# 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)
if not ENABLE_OPENGL:
self.ui.listWidget.item(1).setHidden(True)
self.ui.page3D.setHidden(True)
def onTemporalProfilesRemoved(removedProfiles):
#set to valid temporal profile
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)
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)
self.mTemporalProfileLayer.sigTemporalProfilesRemoved.connect(onTemporalProfilesRemoved)
# 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)
def on3DPlotStyleRemoved(plotStyles):
toRemove = []
for plotStyle in plotStyles:
assert isinstance(plotStyle, TemporalProfile3DPlotStyle)
toRemove.append(plotStyle.mPlotItems)
self.plot3D.removeItems(toRemove)
self.plotSettingsModel2D.sigPlotStylesRemoved.connect(on2DPlotStyleRemoved)
self.plotSettingsModel3D.sigPlotStylesRemoved.connect(on3DPlotStyleRemoved)
#initialize the update loop
self.updateRequested = True
self.updateTimer = QTimer(self)
self.updateTimer.timeout.connect(self.onDataUpdate)
self.updateTimer.start(2000)
self.sigMoveToDate.connect(self.onMoveToDate)
self.initActions()
#self.ui.stackedWidget.setCurrentPage(self.ui.pagePixel)
self.ui.onStackPageChanged(self.ui.stackedWidget.currentIndex())
def temporalProfileLayer(self)->TemporalProfileLayer:
"""
Returns a QgsVectorLayer that is used to store profile coordinates.
:return:
"""
return self.mTemporalProfileLayer
def onTemporalProfilesContextMenu(self, event):
assert isinstance(event, QContextMenuEvent)