Newer
Older
import os
import sys
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()
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
151
152
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)

benjamin.jakimow@geo.hu-berlin.de
committed
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)

benjamin.jakimow@geo.hu-berlin.de
committed
sn = sv.sensor.name()
#w = QgsColorButton(parent, 'Point color {}'.format(sn))
#w.setColor(QColor(index.data()))
#w.colorChanged.connect(lambda: self.commitData.emit(w))
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()
class PixelCollection(QObject):
"""
Object to store pixel data returned by PixelLoader
"""
sigSensorAdded = pyqtSignal(SensorInstrument)
sigSensorRemoved = pyqtSignal(SensorInstrument)
sigPixelAdded = pyqtSignal()
sigPixelRemoved = pyqtSignal()
def __init__(self, timeSeries):
assert isinstance(timeSeries, TimeSeries)
super(PixelCollection, self).__init__()
self.TS = timeSeries
self.sensors = []
self.sensorPxLayers = dict()
self.memLyrCrs = QgsCoordinateReferenceSystem('EPSG:4326')
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
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 = 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 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)
if tsd.sensor not in self.sensorPxLayers.keys():
#create new temp layer
uri = 'Point?crs={}'.format(self.memLyrCrs.authid())

benjamin.jakimow@geo.hu-berlin.de
committed
mem = QgsVectorLayer(uri, 'Pixels_sensor_'+tsd.sensor.name(), 'memory', False)
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
self.sensorPxLayers[tsd.sensor] = mem
assert mem.startEditing()
#standard field names, types, etc.
fieldDefs = [('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'),
]
for fieldDef in fieldDefs:
field = QgsField(fieldDef[0], fieldDef[1], fieldDef[2])
mem.addAttribute(field)
for i in range(nb):
fName = 'b{}'.format(i+1)
mem.addAttribute(self.getFieldDefn(fName, values))
assert mem.commitChanges()
self.sigSensorAdded.emit(tsd.sensor)
s = ""
mem = self.sensorPxLayers[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 b in range(nb):
name ='b{}'.format(b+1)
self.setFeatureAttribute(feature, name, profile[b])
mem.startEditing()
assert mem.addFeature(feature)
assert mem.commitChanges()
#each pixel is a new feature
self.sigPixelAdded.emit()
pass
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()
self.sigSensorRemoved.emit(sensor)
if n_deleted > 0:
self.sigPixelRemoved.emit()
def dateValues(self, sensor, expression):
if sensor not in self.sensorPxLayers.keys():
return []
mem = self.sensorPxLayers[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
from plotstyling import PlotStyle
class SensorPlotSettings(PlotStyle):
def __init__(self, sensor, memoryLyr):
super(SensorPlotSettings, self).__init__()
assert isinstance(sensor, SensorInstrument)
assert isinstance(memoryLyr, QgsVectorLayer)
self.sensor = sensor
self.expression = u'"b1"'
self.isVisible = True
self.memLyr = memoryLyr
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
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
self.moveToDateAction = QAction('Move to...', self)
self.moveToDateAction.triggered.connect(lambda : self.sigMoveToDate.emit(self.moveToDateAction.data()))
def raiseContextMenu(self, ev):
menu = self.getMenu(ev)
if self.moveToDateAction not in menu.actions():
menu.addSeparator()
menu.addAction(self.moveToDateAction)
#refresh action
pt = self.mapDeviceToView(ev.pos())
doi = num2date(pt.x())
self.moveToDateAction.setText('Move to {}'.format(doi))
self.moveToDateAction.setData(doi)
#self.scene().addParentContextMenus(self, menu, ev)
menu.popup(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(SensorPlotSettings)
sigDataChanged = pyqtSignal(SensorPlotSettings)
columnames = ['sensor','nb','style','y-value']
def __init__(self, pxCollection, parent=None, *args):
#assert isinstance(tableView, QTableView)
super(PlotSettingsModel, self).__init__(parent=parent)
self.items = []
self.sortColumnIndex = 0
self.sortOrder = Qt.AscendingOrder
self.pxCollection = pxCollection
self.pxCollection.sigSensorAdded.connect(self.addSensor)
#self.pxCollection.sigSensorRemoved.connect(self.removeSensor)
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.getSensorFromIndex(idxUL)
cname = self.columnames[idxUL.column()]
self.sigVisibilityChanged.emit(sensorView)
if cname in ['y-value']:
self.sigDataChanged.emit(sensorView)
def addSensor(self, sensor):
assert isinstance(sensor, SensorInstrument)
assert sensor in self.pxCollection.sensorPxLayers.keys()

benjamin.jakimow@geo.hu-berlin.de
committed
sensorSettings = SensorPlotSettings(sensor, self.pxCollection.sensorPxLayers[sensor])
i = len(self.items)
idx = self.createIndex(i,i, sensorSettings)
self.beginInsertRows(QModelIndex(),i,i)
self.items.append(sensorSettings)
self.endInsertRows()
#self.sort(self.sortColumnIndex, self.sortOrder)
self.sigSensorAdded.emit(sensorSettings)

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.items if s.sensor == sensor]
for s in toRemove:
idx = self.getIndexFromSensor(s.sensor)
self.beginRemoveRows(QModelIndex(), idx.row(),idx.row())
self.items.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':

benjamin.jakimow@geo.hu-berlin.de
committed
self.items.sort(key = lambda sv:sv.sensor.name(), reverse=r)
elif colName == 'nb':
self.items.sort(key=lambda sv: sv.sensor.nb, reverse=r)
elif colName == 'y-value':
self.items.sort(key=lambda sv: sv.expression, reverse=r)
elif colName == 'style':
self.items.sort(key=lambda sv: sv.color, reverse=r)
def rowCount(self, parent = QModelIndex()):
return len(self.items)
def removeRows(self, row, count , parent=QModelIndex()):
self.beginRemoveRows(parent, row, row+count-1)
toRemove = self.items[row:row+count]
for tsd in toRemove:
self.items.remove(tsd)
self.endRemoveRows()
def getIndexFromSensor(self, sensor):
sensorViews = [i for i, s in enumerate(self.items) if s.sensor == sensor]
assert len(sensorViews) == 1
return self.createIndex(sensorViews[0],0)
def getSensorFromIndex(self, index):
if index.isValid():
return self.items[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.getSensorFromIndex(index)
#print(('data', columnName, role))
if role == Qt.DisplayRole:
if columnName == 'sensor':

benjamin.jakimow@geo.hu-berlin.de
committed
value = sw.sensor.name()
elif columnName == 'nb':
value = str(sw.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.getSensorFromIndex(index)
if role in [Qt.DisplayRole, Qt.EditRole]:
if columnName == 'y-value':
sw.expression = value
result = True
elif columnName == 'style':
if isinstance(value, PlotStyle):
result = True
if role == Qt.CheckStateRole:
if columnName == 'sensor':
sw.isVisible = value == Qt.Checked
result = True
if role == Qt.UserRole:
if columnName == 'y-value':
sw.expression = value
result = True
elif columnName == 'style':
if result:
self.dataChanged.emit(index, index)
return result
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')):
sigMoveToTSD = pyqtSignal(TimeSeriesDatum)
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.pixelLoader = PixelLoader()
self.pixelLoader.sigPixelLoaded.connect(self.onPixelLoaded)
self.pixelLoader.sigLoadingStarted.connect(lambda : self.progressInfo.setText('Start loading...'))
self.pixelCollection = None
self.tableView2DBands.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents)
self.tableView2DBands.setSortingEnabled(True)
self.btnRefresh2D.setDefaultAction(self.actionRefresh2D)
def connectTimeSeries(self, TS):
assert isinstance(TS, TimeSeries)
self.TS = TS
self.pixelCollection = PixelCollection(self.TS)
self.spectralTempVis = SpectralTemporalVisualization(self)
self.spectralTempVis.sigMoveToDate.connect(self.onMoveToDate)
self.TS.sigSensorRemoved.connect(self.spectralTempVis.removeSensor)
self.actionRefresh2D.triggered.connect(lambda : self.spectralTempVis.setData())
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.progressBar.setValue(nDone)
self.progressBar.setMaximum(nMax)
assert isinstance(d, PixelLoaderResult)
QgsApplication.processEvents()
bn = os.path.basename(d.source)
if d.success():
t = 'Last loaded from {}.'.format(bn)
if self.pixelCollection is not None:
self.pixelCollection.addPixel(d)
else:
t = 'Failed loading from {}.'.format(bn)
self.progressInfo.setText(t)
def loadCoordinate(self, spatialPoint):
assert isinstance(spatialPoint, SpatialPoint)
from timeseriesviewer.timeseries import TimeSeries
assert isinstance(self.TS, TimeSeries)
files = [tsd.pathImg for tsd in self.TS if tsd.isVisible()]
self.pixelLoader.setNumberOfProcesses(SETTINGS.value('n_threads', 1))
self.pixelLoader.startLoading(files, spatialPoint)
if self.spectralTempVis is not None:
self.setWindowTitle('{} | {} {}'.format(self.baseTitle, str(spatialPoint.toString()), spatialPoint.crs().authid()))
def date2num(d):
d2 = d.astype(datetime.datetime)
o = d2.toordinal()
#assert d == num2date(o)
return o
def num2date(n):
n = int(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.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
self.pxCollection = ui.pixelCollection
self.plotSettingsModel = PlotSettingsModel(self.pxCollection, parent=self)
self.plotSettingsModel.sigSensorAdded.connect(self.requestUpdate)
self.plotSettingsModel.sigVisibilityChanged.connect(self.setVisibility)
#self.plotSettingsModel.sigVisibilityChanged.connect(self.loadData)
self.plotSettingsModel.sigDataChanged.connect(self.requestUpdate)
#self.plotSettingsModel.sigVisiblityChanged.connect(self.refresh)
self.plotSettingsModel.rowsInserted.connect(self.onRowsInserted)

benjamin.jakimow@geo.hu-berlin.de
committed
#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))
for s in self.pxCollection.sensorPxLayers.keys():
self.plotSettingsModel.addSensor(s)
self.pxCollection.sigPixelAdded.connect(self.requestUpdate)
self.pxCollection.sigPixelRemoved.connect(self.clear)
self.ui.pixelLoader.sigLoadingStarted.connect(self.clear)
self.ui.pixelLoader.sigLoadingFinished.connect(lambda : self.plot2D.enableAutoRange('x', False))
# 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)
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)
self.TV.openPersistentEditor(idxExpr)
self.TV.openPersistentEditor(idxStyle)
start += 1
#self.TV.openPersistentEditor(model.createIndex(start, colStyle))
s = ""
def onObservationClicked(self, plotDataItem, points):
for p in points:
tsd = p.data()
print(tsd)
s =""
def clear(self):
#first remove from pixelCollection
self.pxCollection.clearPixels()
self.plotData2D.clear()
self.plotData3D.clear()
pi = self.plot2D.getPlotItem()
plotItems = pi.listDataItems()
for p in plotItems:
p.clear()
p.update()
if len(self.ui.TS) > 0:
rng = [self.ui.TS[0].date, self.ui.TS[-1].date]
rng = [date2num(d) for d in rng]
self.plot2D.getPlotItem().setRange(xRange=rng)
QApplication.processEvents()
if self.plot3D:
pass
def setVisibility(self, sensorView):
assert isinstance(sensorView, SensorPlotSettings)
self.setVisibility2D(sensorView)
def setVisibility2D(self, sensorView):
assert isinstance(sensorView, SensorPlotSettings)
p = self.plotData2D[sensorView.sensor]
p.setSymbol(sensorView.markerSymbol)
p.setSymbolSize(sensorView.markerSize)
p.setSymbolBrush(sensorView.markerBrush)
p.setSymbolPen(sensorView.markerPen)
p.setPen(sensorView.linePen)
p.setVisible(sensorView.isVisible)
p.update()
self.plot2D.update()
if sensorView is None:
for sv in self.plotSettingsModel.items:
self.setData(sv)
else:
assert isinstance(sensorView, SensorPlotSettings)
self.setData2D(sensorView)
@QtCore.pyqtSlot()
def updatePlot(self):
if self.updateRequested:
self.setData()
self.updateRequested = False
def setData(self, sensorView = None):
self.updateLock = True
if sensorView is None:
for sv in self.plotSettingsModel.items:
self.setData(sv)
else:
assert isinstance(sensorView, SensorPlotSettings)
self.setData2D(sensorView)
self.updateLock = False
def removeSensor(self, sensor):
s = ""
self.plotSettingsModel.removeSensor(sensor)
if sensor in self.plotData2D.keys():
#remove from settings model
self.plotSettingsModel.removeSensor(sensor)
self.plotData2D.pop(sensor)
self.pxCollection.sensorPxLayers.pop(sensor)
# remove from px layer dictionary
#self.sensorPxLayers.pop(sensor)
#todo: remove from plot
s = ""
def setData2D(self, sensorView):
assert isinstance(sensorView, SensorPlotSettings)
if sensorView.sensor not in self.plotData2D.keys():

benjamin.jakimow@geo.hu-berlin.de
committed
plotDataItem = self.plot2D.plot(name=sensorView.sensor.name(), pen=None, symbol='o', symbolPen=None)
plotDataItem.sigPointsClicked.connect(self.onObservationClicked)
self.plotData2D[sensorView.sensor] = plotDataItem
self.setVisibility2D(sensorView)
plotDataItem = self.plotData2D[sensorView.sensor]

benjamin.jakimow@geo.hu-berlin.de
committed
plotDataItem.setToolTip('Values {}'.format(sensorView.sensor.name()))
#https://github.com/pyqtgraph/pyqtgraph/blob/5195d9dd6308caee87e043e859e7e553b9887453/examples/customPlot.py
tsds, values = self.pxCollection.dateValues(sensorView.sensor, sensorView.expression)
if len(tsds) > 0:
dates = np.asarray([date2num(tsd.date) for tsd in tsds])
values = np.asarray(values)
i = np.argsort(dates)
plotDataItem.appendData()
plotDataItem.setData(x=dates[i], y=values[i], data=tsds[i])
def setData3D(self, *arg):
pass
# prepare QGIS environment
if sys.platform == 'darwin':
PATH_QGS = r'/Applications/QGIS.app/Contents/MacOS'
os.environ['GDAL_DATA'] = r'/usr/local/Cellar/gdal/1.11.3_1/share'
else:
# assume OSGeo4W startup
PATH_QGS = os.environ['QGIS_PREFIX_PATH']
assert os.path.exists(PATH_QGS)
qgsApp = QgsApplication([], True)