Newer
Older
import os, sys, pickle, datetime
from qgis.gui import *
from qgis.core import *
from PyQt4.QtCore import *
from PyQt4.QtXml import *
from PyQt4.QtGui import *
from timeseriesviewer import jp, SETTINGS
from utils import SpatialExtent, SpatialPoint, px2geo
from ui.docks import TsvDockWidgetBase, loadUi
from plotstyling import PlotStyle, PlotStyleButton
from pixelloader import PixelLoader, PixelLoaderResult
import pyqtgraph as pg
from osgeo import gdal, gdal_array
import numpy as np
def getTextColorWithContrast(c):
assert isinstance(c, QColor)
if c.lightness() < 0.5:
return QColor('white')
else:
return QColor('black')
class DateTimeAxis(pg.AxisItem):
def __init__(self, *args, **kwds):
super(DateTimeAxis, self).__init__(*args, **kwds)
def logTickStrings(self, values, scale, spacing):
s = ""
def tickStrings(self, values, scale, spacing):
strns = []
if len(values) == 0:
return []
#assert isinstance(values[0],
values = [num2date(v) for v in values]
rng = max(values)-min(values)
ndays = rng.astype(int)
strns = []
for v in values:
if ndays == 0:
strns.append(v.astype(str))
strns.append(v.astype(str))
return strns
def tickValues(self, minVal, maxVal, size):
d = super(DateTimeAxis, self).tickValues(minVal, maxVal, size)
class SensorPoints(pg.PlotDataItem):
def __init__(self, *args, **kwds):
super(SensorPoints, self).__init__(*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()
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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 PlotSettingsWidgetDelegate(QStyledItemDelegate):
def __init__(self, tableView, parent=None):
super(PlotSettingsWidgetDelegate, self).__init__(parent=parent)
self._preferedSize = QgsFieldExpressionWidget().sizeHint()
self.tableView = tableView
def getColumnName(self, index):
assert index.isValid()
assert isinstance(index.model(), PlotSettingsModel)
return index.model().columnames[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)
if cname == 'y-value':
w = QgsFieldExpressionWidget(parent)
sv = self.tableView.model().data(index, Qt.UserRole)
w.setLayer(sv.memLyr)
w.setExpressionDialogTitle('Values sensor {}'.format(sv.sensor().name()))
w.setToolTip('Set values shown for sensor {}'.format(sv.sensor().name()))
w.fieldChanged.connect(lambda : self.checkData(w, w.expression()))
elif cname == 'style':
sv = self.tableView.model().data(index, Qt.UserRole)
w = PlotStyleButton(parent)
w.setPlotStyle(sv)
w.setToolTip('Set sensor style.')
w.sigPlotStyleChanged.connect(lambda: self.checkData(w, w.plotStyle()))
else:
raise NotImplementedError()
return w
def checkData(self, w, expression):
if isinstance(w, QgsFieldExpressionWidget):
assert expression == w.expression()
assert w.isExpressionValid(expression) == w.isValidExpression()
if w.isValidExpression():
self.commitData.emit(w)
else:
s = ""
#print(('Delegate commit failed',w.asExpression()))
self.commitData.emit(w)
def setEditorData(self, editor, index):
cname = self.getColumnName(index)
if cname == 'y-value':
lastExpr = index.model().data(index, Qt.DisplayRole)
assert isinstance(editor, QgsFieldExpressionWidget)
editor.setProperty('lastexpr', lastExpr)
editor.setField(lastExpr)
elif cname == 'style':
style = index.data()
assert isinstance(editor, PlotStyleButton)
editor.setPlotStyle(style)
else:
raise NotImplementedError()
def setModelData(self, w, model, index):
cname = self.getColumnName(index)
if cname == 'y-value':
assert isinstance(w, QgsFieldExpressionWidget)
exprLast = model.data(index, Qt.DisplayRole)
if w.isValidExpression() and expr != exprLast:
model.setData(index, w.asExpression(), Qt.UserRole)
elif cname == 'style':
assert isinstance(w, PlotStyleButton)
model.setData(index, w.plotStyle(), Qt.UserRole)
else:
raise NotImplementedError()
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
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 PixelCollection(QObject):
"""
Object to store pixel data delivered by PixelLoader
"""
sigSensorAdded = pyqtSignal(SensorInstrument)
sigSensorRemoved = pyqtSignal(SensorInstrument)
sigPixelAdded = pyqtSignal()
sigPixelRemoved = pyqtSignal()
super(PixelCollection, self).__init__()
self.sensorPxLayers = dict()
self.memLyrCrs = QgsCoordinateReferenceSystem('EPSG:4326')
self.clear()
if isinstance(timeSeries, TimeSeries):
self.TS = timeSeries
for sensor in self.TS.Sensors:
self.addSensor(sensor)
self.TS.sigSensorAdded.connect(self.addSensor)
self.TS.sigSensorRemoved.connect(self.removeSensor)
def getFieldDefn(self, name, values):
if isinstance(values, np.ndarray):
# add bands
if values.dtype in [np.int8, np.int16, np.int32, np.int64,
np.uint8, np.uint16, np.uint32, np.uint64]:
fType = QVariant.Int
fTypeName = 'integer'
elif values.dtype in [np.float16, np.float32, np.float64]:
fType = QVariant.Double
fTypeName = 'decimal'
else:
raise NotImplementedError()
return QgsField(name, fType, fTypeName)
def setFeatureAttribute(self, feature, name, value):
assert isinstance(feature, QgsFeature)
assert isinstance(name, str)
i = feature.fieldNameIndex(name)
assert i >= 0, 'Field "{}" does not exist'.format(name)
field = feature.fields()[i]
if field.isNumeric():
if field.type() == QVariant.Int:
value = int(value)
elif field.type() == QVariant.Double:
value = float(value)
else:
raise NotImplementedError()
feature.setAttribute(i, value)
def addSensor(self, sensor):
assert isinstance(sensor, SensorInstrument)
assert sensor not in self.sensorPxLayers.keys()
mem = SensorPixelDataMemoryLayer(sensor, crs=self.memLyrCrs)
self.sensorPxLayers[sensor] = mem
self.sigSensorAdded.emit(sensor)
def sensorData(self, sensor):
assert isinstance(sensor, SensorInstrument)
assert sensor in self.sensorPxLayers.keys()
return self.sensorPxLayers[sensor]
def removeSensor(self, sensor):
if sensor in self.sensorPxLayers.keys():
del self.sensorPxLayers[sensor]
def addPixel(self, d):
assert isinstance(d, PixelLoaderResult)
if d.success():
tsd = self.TS.getTSD(d.source)
values = d.pxData
nodata = np.asarray(d.noDataValue)
nb, nl, ns = values.shape
assert nb >= 1
assert isinstance(tsd, TimeSeriesDatum)
mem = self.sensorData(tsd.sensor)
#insert each single pixel, line by line
indicesY, indicesX = d.imagePixelIndices()
doy = tsd.doy
gt = d.geoTransformation
nb, nl, ns = d.pxData.shape
srcCrs = d.imageCrs()
for i in range(ns):
for j in range(nl):
profile = d.pxData[:, j, i]
if np.any(np.any(profile == nodata)):
continue
geo = px2geo(QPoint(indicesX[i], indicesY[i]), gt)
geo = SpatialPoint(srcCrs, geo).toCrs(self.memLyrCrs)
if not isinstance(geo, SpatialPoint):
continue
geometry = QgsPointV2(geo.x(), geo.y())
feature = QgsFeature(mem.fields())
#fnames = [f.name() for f in mem.fields()]
feature.setGeometry(QgsGeometry(geometry))
feature.setAttribute('date', str(tsd.date))
feature.setAttribute('doy', doy)
feature.setAttribute('geo_x', geo.x())
feature.setAttribute('geo_y', geo.y())
feature.setAttribute('px_x', indicesX[i])
feature.setAttribute('px_y', indicesY[i])
for iBand, bandIndex in enumerate(d.pxBandIndices):
name ='b{}'.format(bandIndex+1)
if profile.ndim == 1:
self.setFeatureAttribute(feature, name, profile[iBand])
else:
self.setFeatureAttribute(feature, name, profile[iBand,:])
mem.startEditing()
assert mem.addFeature(feature)
assert mem.commitChanges()
#each pixel is a new feature
self.sigPixelAdded.emit()
pass
def clear(self):
self.sensorPxLayers.clear()
def clearPixels(self):
sensors = self.sensorPxLayers.keys()
n_deleted = 0
for sensor in sensors:
mem = self.sensorPxLayers[sensor]
assert mem.startEditing()
mem.selectAll()
b, n = mem.deleteSelectedFeatures()
n_deleted += n
assert mem.commitChanges()
if n_deleted > 0:
self.sigPixelRemoved.emit()
def dateValues(self, sensor, expression):
mem = self.sensorData(sensor)
dp = mem.dataProvider()
exp = QgsExpression(expression)
exp.prepare(dp.fields())
possibleTsds = self.TS.getTSDs(sensorOfInterest=sensor)
tsds = []
values = []
if exp.isValid():
mem.selectAll()
for feature in mem.selectedFeatures():
date = np.datetime64(feature.attribute('date'))
y = exp.evaluatePrepared(feature)
if y is not None:
tsd = next(tsd for tsd in possibleTsds if tsd.date == date)
tsds.append(tsd)
values.append(y)
return tsds, values
class SensorPlotStyle(PlotStyle):
def __init__(self):
super(SensorPlotStyle, self).__init__()
self.mSensor = None
self.memLyr = None
self.mExpression = u'"b1"'
self.mIsVisible = True
def connectSensor(self, sensor, memoryLayer):
assert isinstance(sensor, SensorInstrument)
assert isinstance(memoryLayer, QgsVectorLayer)
self.memLyr = memoryLayer
self.mSensor = sensor
def isValid(self):
"""
:return: True, if connected to a sensor and memoryLayer that contains pixel values
"""
return isinstance(self.memLyr, QgsVectorLayer) and isinstance(self.mSensor, SensorInstrument)
def sensor(self):
return self.mSensor
def setVisibility(self, b):
self.mIsVisible
def isVisible(self):
return self.mIsVisible
def setExpression(self, exp):
self.mExpression = exp
def expression(self):
return self.mExpression
def __reduce_ex__(self, protocol):
return self.__class__, (), self.__getstate__()
def __getstate__(self):
result = super(SensorPlotStyle, self).__getstate__()
#remove
del result['memLyr']
del result['mSensor']
return result
class DateTimeViewBox(pg.ViewBox):
"""
Subclass of ViewBox
"""
sigMoveToDate = pyqtSignal(np.datetime64)
def __init__(self, parent=None):
"""
Constructor of the CustomViewBox
"""
super(DateTimeViewBox, self).__init__(parent)
#self.menu = None # Override pyqtgraph ViewBoxMenu
#self.menu = self.getMenu() # Create the menu
#self.menu = None
def raiseContextMenu(self, ev):
pt = self.mapDeviceToView(ev.pos())
print(pt.x(), pt.y())
date = num2date(pt.x())
menu = QMenu(None)
a = menu.addAction('Move to {}'.format(date))
a.setData(date)
a.triggered.connect(lambda : self.sigMoveToDate.emit(date))
self.scene().addParentContextMenus(self, menu, ev)
menu.exec_(ev.screenPos().toPoint())
class DateTimePlotWidget(pg.PlotWidget):
"""
Subclass of PlotWidget
"""
def __init__(self, parent=None):
"""
Constructor of the widget
"""
super(DateTimePlotWidget, self).__init__(parent, viewBox=DateTimeViewBox())
self.plotItem = pg.PlotItem(axisItems={'bottom':DateTimeAxis(orientation='bottom')}, viewBox=DateTimeViewBox())
self.setCentralItem(self.plotItem)
class PlotSettingsModel(QAbstractTableModel):
#sigSensorAdded = pyqtSignal(SensorPlotSettings)
sigVisibilityChanged = pyqtSignal(SensorPlotStyle)
sigDataChanged = pyqtSignal(SensorPlotStyle)
columnames = ['sensor','nb','style','y-value']
def __init__(self, pixelCollection, parent=None, *args):
#assert isinstance(tableView, QTableView)
super(PlotSettingsModel, self).__init__(parent=parent)
assert isinstance(pixelCollection, PixelCollection)
self.mSensorPlotSettings = []
self.sortColumnIndex = 0
self.sortOrder = Qt.AscendingOrder
self.pxCollection.sigSensorAdded.connect(self.addSensor)
self.pxCollection.sigSensorRemoved.connect(self.removeSensor)
for sensor in self.pxCollection.sensorPxLayers.keys():
self.addSensor(sensor)
self.sort(0, Qt.AscendingOrder)
s = ""
self.dataChanged.connect(self.signaler)
def testSlot(self, *args):
print('TESTSLOT')
s = ""

benjamin.jakimow@geo.hu-berlin.de
committed
def signaler(self, idxUL, idxLR):
if idxUL.isValid():
sensorView = self.getSensorPlotSettingsFromIndex(idxUL)
cname = self.columnames[idxUL.column()]
self.sigVisibilityChanged.emit(sensorView)
if cname in ['y-value']:
self.sigDataChanged.emit(sensorView)
def requiredBands(self, sensor):
"""
Returns the band indices required to calculate the values for this sensor
:param sensor:
:return: [list-of-band-indices]
"""
idx = self.getIndexFromSensor(sensor)
idx = self.createIndex(idx.row(),self.columnames.index('y-value'))
equation = self.data(idx)
plotSettings = self.data(idx, Qt.UserRole)
assert isinstance(plotSettings, SensorPlotStyle)
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
expression = plotSettings.expression()
fields = plotSettings.memLyr.fields()
bandNames = []
bandIndices = []
LUT_Field2Band = dict()
for field in fields:
assert isinstance(field, QgsField)
LUT_Field2Band[field.name()] = field.name()
if len(field.alias()) > 0:
LUT_Field2Band[field.alias()] = field.name()
for name, fieldName in LUT_Field2Band.items():
if re.search(name+'($|[^\d])', expression):
bandNames.append(fieldName)
continue
for bandName in bandNames:
if re.search('b\d+', bandName):
bandIndices.append(int(bandName[1:])-1)
return bandIndices
def addSensor(self, sensor):
assert isinstance(sensor, SensorInstrument)
index = 'DEFAULT'
sensorSettings = self.restorePlotSettings(sensor, index=index)
if not isinstance(sensorSettings, SensorPlotStyle):
sensorSettings = SensorPlotStyle()
sensorSettings.connectSensor(sensor, self.pxCollection.sensorPxLayers[sensor])

benjamin.jakimow@geo.hu-berlin.de
committed
i = len(self.mSensorPlotSettings)
self.beginInsertRows(QModelIndex(),i,i)
self.mSensorPlotSettings.append(sensorSettings)
self.endInsertRows()

benjamin.jakimow@geo.hu-berlin.de
committed
sensor.sigNameChanged.connect(self.onSensorNameChanged)
def removeSensor(self, sensor):
assert isinstance(sensor, SensorInstrument)
toRemove = [s for s in self.mSensorPlotSettings if s.sensor() == sensor]
for s in toRemove:
idx = self.getIndexFromSensor(s.sensor())
self.beginRemoveRows(QModelIndex(), idx.row(),idx.row())
self.mSensorPlotSettings.remove(s)
self.endRemoveRows()

benjamin.jakimow@geo.hu-berlin.de
committed
def onSensorNameChanged(self, name):
self.beginResetModel()

benjamin.jakimow@geo.hu-berlin.de
committed
self.endResetModel()
def sort(self, col, order):
if self.rowCount() == 0:
return
colName = self.columnames[col]
r = order != Qt.AscendingOrder
#self.beginMoveRows(idxSrc,
if colName == 'sensor':
self.mSensorPlotSettings.sort(key = lambda sv:sv.sensor.name(), reverse=r)
elif colName == 'nb':
self.mSensorPlotSettings.sort(key=lambda sv: sv.sensor.nb, reverse=r)
elif colName == 'y-value':
self.mSensorPlotSettings.sort(key=lambda sv: sv.expression, reverse=r)
elif colName == 'style':
self.mSensorPlotSettings.sort(key=lambda sv: sv.color, reverse=r)
def rowCount(self, parent = QModelIndex()):
return len(self.mSensorPlotSettings)
def removeRows(self, row, count , parent=QModelIndex()):
self.beginRemoveRows(parent, row, row+count-1)
toRemove = self.mSensorPlotSettings[row:row + count]
for tsd in toRemove:
self.mSensorPlotSettings.remove(tsd)
self.endRemoveRows()
def getIndexFromSensor(self, sensor):
assert isinstance(sensor, SensorInstrument)
sensorViews = [i for i, s in enumerate(self.mSensorPlotSettings) if s.sensor() == sensor]
assert len(sensorViews) == 1
return self.createIndex(sensorViews[0],0)
def getSensorPlotSettingsFromIndex(self, index):
if index.isValid():
return self.mSensorPlotSettings[index.row()]
return None
def columnCount(self, parent = QModelIndex()):
return len(self.columnames)
def data(self, index, role = Qt.DisplayRole):
if role is None or not index.isValid():
return None
value = None
columnName = self.columnames[index.column()]
sw = self.getSensorPlotSettingsFromIndex(index)
sensor = sw.sensor()
#print(('data', columnName, role))
if role == Qt.DisplayRole:
if columnName == 'sensor':
value = sensor.name()
elif columnName == 'nb':
value = str(sensor.nb)
elif columnName == 'y-value':
value = sw.expression()
elif role == Qt.CheckStateRole:
if columnName == 'sensor':
value = Qt.Checked if sw.isVisible() else Qt.Unchecked
elif role == Qt.UserRole:
value = sw
#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.columnames[index.column()]

benjamin.jakimow@geo.hu-berlin.de
committed
if value is None:
return False
result = False
sw = self.getSensorPlotSettingsFromIndex(index)
assert isinstance(sw, SensorPlotStyle)
if role in [Qt.DisplayRole, Qt.EditRole]:
if columnName == 'y-value':
sw.setExpression(value)
result = True
elif columnName == 'style':
if isinstance(value, PlotStyle):
result = True
if role == Qt.CheckStateRole:
if columnName == 'sensor':
sw.setVisibility(value == Qt.Checked)
result = True
if role == Qt.UserRole:
if columnName == 'y-value':
sw.setExpression(value)
result = True
elif columnName == 'style':
if result:
#save plot-style
self.savePlotSettings(sw, index='DEFAULT')
self.dataChanged.emit(index, index)
return result
def savePlotSettings(self, sensorPlotSettings, index='DEFAULT'):
assert isinstance(sensorPlotSettings, SensorPlotStyle)
id = 'SPS.{}.{}'.format(index, sensorPlotSettings.sensor().id())
d = pickle.dumps(sensorPlotSettings)
SETTINGS.setValue(id, d)
def restorePlotSettings(self, sensor, index='DEFAULT'):
assert isinstance(sensor, SensorInstrument)
id = 'SPS.{}.{}'.format(index, sensor.id())
sensorPlotSettings = SETTINGS.value(id)
if sensorPlotSettings is not None:
try:
sensorPlotSettings = pickle.loads(sensorPlotSettings)
s = ""
except:
sensorPlotSettings = None
pass
if isinstance(sensorPlotSettings, SensorPlotStyle):
return sensorPlotSettings
else:
def flags(self, index):
if index.isValid():
columnName = self.columnames[index.column()]
flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
if columnName == 'sensor':
flags = flags | Qt.ItemIsUserCheckable

benjamin.jakimow@geo.hu-berlin.de
committed
if columnName in ['y-value','style']: #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.columnames[col]
elif orientation == Qt.Vertical and role == Qt.DisplayRole:
return col
return None
class ProfileViewDockUI(TsvDockWidgetBase, loadUi('profileviewdock.ui')):
def __init__(self, parent=None):
super(ProfileViewDockUI, self).__init__(parent)
self.setupUi(self)
from timeseriesviewer import OPENGL_AVAILABLE, SETTINGS
#TBD.
self.line.setVisible(False)
self.listWidget.setVisible(False)
self.stackedWidget.setCurrentWidget(self.page2D)
if OPENGL_AVAILABLE:
l = self.page3D.layout()
l.removeWidget(self.labelDummy3D)
from pyqtgraph.opengl import GLViewWidget
self.plotWidget3D = GLViewWidget(self.page3D)
l.addWidget(self.plotWidget3D)
else:
self.plotWidget3D = None
#pi = self.plotWidget2D.plotItem
#ax = DateAxis(orientation='bottom', showValues=True)
#pi.layout.addItem(ax, 3,2)
self.baseTitle = self.windowTitle()
self.TS = None
self.progressBar.setMinimum(0)
self.progressBar.setMaximum(100)
self.progressBar.setValue(0)
self.progressInfo.setText('')
self.pxViewModel2D = None
self.pxViewModel3D = None
self.tableView2DBands.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents)
self.tableView2DBands.setSortingEnabled(True)
self.btnRefresh2D.setDefaultAction(self.actionRefresh2D)
def date2num(d):
d2 = d.astype(datetime.datetime)
o = d2.toordinal()
#assert d == num2date(o)
return o
def num2date(n):
if n < 1:
n = 1
d = datetime.date.fromordinal(n)
return np.datetime64(d, 'D')
class SpectralTemporalVisualization(QObject):
sigShowPixel = pyqtSignal(TimeSeriesDatum, QgsPoint, QgsCoordinateReferenceSystem)
"""
Signalizes to move to specific date of interest
"""
sigMoveToDate = pyqtSignal(np.datetime64)
def __init__(self, ui):
super(SpectralTemporalVisualization, self).__init__()
#assert isinstance(timeSeries, TimeSeries)
assert isinstance(ui, ProfileViewDockUI)
self.ui = ui
self.pixelLoader = PixelLoader()
self.pixelLoader.sigPixelLoaded.connect(self.onPixelLoaded)
self.pixelLoader.sigLoadingStarted.connect(lambda: self.ui.progressInfo.setText('Start loading...'))
self.plot_initialized = False
self.TV = ui.tableView2DBands
self.TV.setSortingEnabled(False)
self.plot2D = ui.plotWidget2D
self.plot2D.plotItem.getViewBox().sigMoveToDate.connect(self.sigMoveToDate)
self.plot3D = ui.plotWidget3D
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
self.pxCollection = PixelCollection()
self.pxCollection.sigPixelAdded.connect(self.requestUpdate)
self.pxCollection.sigPixelRemoved.connect(self.clear)
self.plotSettingsModel = None
self.pixelLoader.sigLoadingStarted.connect(self.clear)
self.pixelLoader.sigLoadingFinished.connect(lambda : self.plot2D.enableAutoRange('x', False))
self.ui.actionRefresh2D.triggered.connect(lambda: self.setData())
# self.VIEW.setItemDelegateForColumn(3, PointStyleDelegate(self.VIEW))
self.plotData2D = dict()
self.plotData3D = dict()
self.updateRequested = True
self.updateTimer = QTimer(self)
self.updateTimer.timeout.connect(self.updatePlot)
self.updateTimer.start(2000)
self.sigMoveToDate.connect(self.onMoveToDate)
def connectTimeSeries(self, TS):
assert isinstance(TS, TimeSeries)
self.TS = TS
self.pxCollection.connectTimeSeries(self.TS)
self.TS.sigSensorRemoved.connect(self.removeSensor)
self.plotSettingsModel = PlotSettingsModel(self.pxCollection, parent=self)
self.plotSettingsModel.sigVisibilityChanged.connect(self.setVisibility)
self.plotSettingsModel.sigDataChanged.connect(self.requestUpdate)
self.plotSettingsModel.rowsInserted.connect(self.onRowsInserted)
# self.plotSettingsModel.modelReset.connect(self.updatePersistantWidgets)
self.TV.setModel(self.plotSettingsModel)
self.delegate = PlotSettingsWidgetDelegate(self.TV)
self.TV.setItemDelegateForColumn(2, self.delegate)
self.TV.setItemDelegateForColumn(3, self.delegate)
# self.TV.setItemDelegateForColumn(3, PointStyleDelegate(self.TV))
def onMoveToDate(self, date):
dt = np.asarray([np.abs(tsd.date - date) for tsd in self.TS])
i = np.argmin(dt)
self.sigMoveToTSD.emit(self.TS[i])
def onPixelLoaded(self, nDone, nMax, d):
self.ui.progressBar.setValue(nDone)
self.ui.progressBar.setMaximum(nMax)
assert isinstance(d, PixelLoaderResult)
QgsApplication.processEvents()
bn = os.path.basename(d.source)
if d.success():
t = 'Last loaded from {}.'.format(bn)
self.pxCollection.addPixel(d)
else:
t = 'Failed loading from {}.'.format(bn)
if d.info and d.info != '':
t += '({})'.format(d.info)
def requestUpdate(self, *args):
self.updateRequested = True
#next time
def updatePersistentWidgets(self):

benjamin.jakimow@geo.hu-berlin.de
committed
model = self.TV.model()
if model:
colExpression = model.columnames.index('y-value')
colStyle = model.columnames.index('style')
for row in range(model.rowCount()):
idxExpr = model.createIndex(row, colExpression)
idxStyle = model.createIndex(row, colStyle)
#self.TV.closePersistentEditor(idxExpr)
#self.TV.closePersistentEditor(idxStyle)
self.TV.openPersistentEditor(idxExpr)
self.TV.openPersistentEditor(idxStyle)
#self.TV.openPersistentEditor(model.createIndex(start, colStyle))
s = ""
def onRowsInserted(self, parent, start, end):
model = self.TV.model()
if model:
colExpression = model.columnames.index('y-value')
colStyle = model.columnames.index('style')
while start <= end:
idxExpr = model.createIndex(start, colExpression)
idxStyle = model.createIndex(start, colStyle)