Newer
Older
colorRampItems.append(QgsColorRampShader.ColorRampItem(value, color))
shaderFunc.setColorRampItemList(colorRampItems)
shader = QgsRasterShader()
shader.setMaximumValue(cmax)
shader.setMinimumValue(cmin)
shader.setRasterShaderFunction(shaderFunc)
r.setShader(shader)
return r

benjamin.jakimow@geo.hu-berlin.de
committed
class DatumViewUI(QFrame, loadUI('timeseriesdatumview.ui')):
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
"""
Widget to host the MapCanvases of all map views that relate to a single Datum-Sensor combinbation.
"""
def __init__(self, title='<#>', parent=None):
super(DatumViewUI, self).__init__(parent)
self.setupUi(self)
def sizeHint(self):
m = self.layout().contentsMargins()
s = QSize(0, 0)
map = None
widgets = [self.layout().itemAt(i).widget() for i in range(self.layout().count())]
widgets = [w for w in widgets if isinstance(w, QWidget)]
maps = [w for w in widgets if isinstance(w, MapCanvas)]
others = [w for w in widgets if not isinstance(w, MapCanvas)]
s = self.layout().spacing()
m = self.layout().contentsMargins()
def totalHeight(widgetList):
total = QSize(0,0)
for w in widgetList:
ws = w.size()
if ws.width() == 0:
ws = w.sizeHint()
if w.isVisible():
total.setWidth(max([total.width(), ws.width()]))
total.setHeight(total.height() + ws.height())
return total
baseSize = totalHeight(widgets)
if baseSize.width() == 0:
for o in others:
baseSize.setWidth(9999)
s = QSize(baseSize.width() + m.left() + m.right(),
baseSize.height() + m.top() + m.bottom())
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
return s
"""
def sizeHint(self):
if not self.ui.isVisible():
return QSize(0,0)
else:
#return self.ui.sizeHint()
size = self.ui.sizeHint()
s = self.ui.layout().spacing()
m = self.ui.layout().contentsMargins()
dx = m.left() + m.right() + s
dy = self.ui.layout().spacing()
n = len([m for m in self.mapCanvases.keys() if m.isVisible()])
if n > 0:
baseSize = self.mapCanvases.values()[0].size()
size = QSize(baseSize.width()+ dx, \
size.height()+ (n+1)*(dy+2*s))
else:
s = ""
return size
"""

benjamin.jakimow@geo.hu-berlin.de
committed
sigRenderProgress = pyqtSignal(int,int)
sigLoadingStarted = pyqtSignal(MapView, TimeSeriesDatum)
sigLoadingFinished = pyqtSignal(MapView, TimeSeriesDatum)
sigVisibilityChanged = pyqtSignal(bool)
assert isinstance(timeSeriesDatum, TimeSeriesDatum)
assert isinstance(stv, SpatialTemporalVisualization)

benjamin.jakimow@geo.hu-berlin.de
committed

benjamin.jakimow@geo.hu-berlin.de
committed
self.ui.create()
self.showLoading(False)
self.wOffset = self.ui.layout().count()-1

benjamin.jakimow@geo.hu-berlin.de
committed
self.minHeight = self.ui.height()

benjamin.jakimow@geo.hu-berlin.de
committed
self.renderProgress = dict()
assert isinstance(stv, SpatialTemporalVisualization)
self.STV = stv
self.mSensor = self.TSD.sensor
self.mSensor.sigNameChanged.connect(lambda :self.setColumnInfo())
self.TSD.sigVisibilityChanged.connect(self.setVisibility)

benjamin.jakimow@geo.hu-berlin.de
committed
self.setColumnInfo()

benjamin.jakimow@geo.hu-berlin.de
committed
self.mapCanvases = dict()
self.mRenderState = dict()

benjamin.jakimow@geo.hu-berlin.de
committed

benjamin.jakimow@geo.hu-berlin.de
committed
def setColumnInfo(self):
labelTxt = '{}\n{}'.format(str(self.TSD.date), self.TSD.sensor.name())
tooltip = '{}'.format(self.TSD.pathImg)

benjamin.jakimow@geo.hu-berlin.de
committed
self.ui.labelTitle.setText(labelTxt)
self.ui.labelTitle.setToolTip(tooltip)

benjamin.jakimow@geo.hu-berlin.de
committed
def setVisibility(self, b):
self.ui.setVisible(b)
self.sigVisibilityChanged.emit(b)

benjamin.jakimow@geo.hu-berlin.de
committed
def setHighlighted(self, b=True, timeout=1000):
styleOn = """.QFrame {
border: 4px solid red;
border-radius: 4px;
}"""
styleOff = """"""
if b is True:
self.ui.setStyleSheet(styleOn)
if timeout > 0:
QTimer.singleShot(timeout, lambda : self.setHighlighted(b=False))
else:
self.ui.setStyleSheet(styleOff)

benjamin.jakimow@geo.hu-berlin.de
committed
def removeMapView(self, mapView):
canvas = self.mapCanvases.pop(mapView)
self.ui.layout().removeWidget(canvas)

benjamin.jakimow@geo.hu-berlin.de
committed
canvas.close()

benjamin.jakimow@geo.hu-berlin.de
committed
def refresh(self):

benjamin.jakimow@geo.hu-berlin.de
committed
if self.ui.isVisible():
for c in self.mapCanvases.values():
if c.isVisible():

benjamin.jakimow@geo.hu-berlin.de
committed
def insertMapView(self, mapView):
assert isinstance(mapView, MapView)
from timeseriesviewer.mapcanvas import MapCanvas

benjamin.jakimow@geo.hu-berlin.de
committed
mapCanvas.setObjectName('MapCanvas {} {}'.format(mapView.title(), self.TSD.date))
mapCanvas.setMapView(mapView)
mapCanvas.setTSD(self.TSD)
self.registerMapCanvas(mapView, mapCanvas)

benjamin.jakimow@geo.hu-berlin.de
committed
mapView.registerMapCanvas(self.mSensor, mapCanvas)
# register MapCanvas on STV level
self.STV.registerMapCanvas(mapCanvas)
mapCanvas.renderComplete.connect(lambda : self.onRenderingChange(False))
mapCanvas.renderStarting.connect(lambda : self.onRenderingChange(True))

benjamin.jakimow@geo.hu-berlin.de
committed
mapCanvas.sigDataLoadingFinished.connect(
lambda dt: self.STV.TSV.ui.dockSystemInfo.addTimeDelta('Map {}'.format(self.mSensor.name()), dt))

benjamin.jakimow@geo.hu-berlin.de
committed
mapCanvas.sigDataLoadingFinished.connect(
lambda dt: self.STV.TSV.ui.dockSystemInfo.addTimeDelta('All Sensors', dt))
def showLoading(self, b):
if b:
self.ui.progressBar.setRange(0,0)
self.ui.progressBar.setValue(-1)
else:
self.ui.progressBar.setRange(0,1)
self.ui.progressBar.setValue(0)
def onRenderingChange(self, b):
mc = self.sender()
#assert isinstance(mc, QgsMapCanvas)
self.mRenderState[mc] = b
self.showLoading(any(self.mRenderState.values()))
def onRendering(self, *args):
renderFlags = [m.renderFlag() for m in self.mapCanvases.values()]
drawFlags = [m.isDrawing() for m in self.mapCanvases.values()]

benjamin.jakimow@geo.hu-berlin.de
committed
# print((renderFlags, drawFlags))
isLoading = any(renderFlags)
self.showLoading(isLoading)
s = ""

benjamin.jakimow@geo.hu-berlin.de
committed
def registerMapCanvas(self, mapView, mapCanvas):
from timeseriesviewer.mapcanvas import MapCanvas
assert isinstance(mapCanvas, MapCanvas)
#mapView.sigTitleChanged.connect(lambda title : mapCanvas.setSaveFileName('{}_{}'.format(self.TSD.date, title)))
mapCanvas.layerModel().setRasterLayerSources([self.TSD.pathImg])
self.ui.layout().insertWidget(self.wOffset + len(self.mapCanvases), mapCanvas)
self.ui.update()
#register signals handled on (this) DV level
mapCanvas.renderStarting.connect(lambda: self.sigLoadingStarted.emit(mapView, self.TSD))
mapCanvas.mapCanvasRefreshed.connect(lambda: self.sigLoadingFinished.emit(mapView, self.TSD))
mapCanvas.sigShowProfiles.connect(lambda c, t : mapView.sigShowProfiles.emit(c,mapCanvas, t))
mapCanvas.sigChangeDVRequest.connect(self.onMapCanvasRequest)

benjamin.jakimow@geo.hu-berlin.de
committed
def onMapCanvasRequest(self, mapCanvas, key):
if key == 'hide_date':
self.TSD.setVisibility(False)
if key == 'copy_sensor':
QApplication.clipboard().setText(self.TSD.sensor.name())
if key == 'copy_date':
QApplication.clipboard().setText(str(self.TSD.date))
if key == 'copy_path':
QApplication.clipboard().setText(str(self.TSD.pathImg))

benjamin.jakimow@geo.hu-berlin.de
committed
def __lt__(self, other):
assert isinstance(other, DatumView)
return self.TSD < other.TSD

benjamin.jakimow@geo.hu-berlin.de
committed
def __eq__(self, other):
assert isinstance(other, DatumView)
return self.TSD == other.TSD

benjamin.jakimow@geo.hu-berlin.de
committed
class SpatialTemporalVisualization(QObject):
"""
"""
sigLoadingStarted = pyqtSignal(DatumView, MapView)
sigLoadingFinished = pyqtSignal(DatumView, MapView)
sigShowProfiles = pyqtSignal(SpatialPoint, MapCanvas, str)

benjamin.jakimow@geo.hu-berlin.de
committed
sigShowMapLayerInfo = pyqtSignal(dict)
sigSpatialExtentChanged = pyqtSignal(SpatialExtent)
sigCRSChanged = pyqtSignal(QgsCoordinateReferenceSystem)

benjamin.jakimow@geo.hu-berlin.de
committed
def __init__(self, timeSeriesViewer):
super(SpatialTemporalVisualization, self).__init__()

benjamin.jakimow@geo.hu-berlin.de
committed
#assert isinstance(timeSeriesViewer, TimeSeriesViewer), timeSeriesViewer
#default map settings
self.mSpatialExtent = SpatialExtent.world()
self.mCRS = self.mSpatialExtent.crs()
self.mSize = QSize(200,200)
self.mColor = Qt.black

benjamin.jakimow@geo.hu-berlin.de
committed
self.ui = timeSeriesViewer.ui
#map-tool handling
self.mMapToolActivator = None
self.mMapTools = []

benjamin.jakimow@geo.hu-berlin.de
committed
self.scrollArea = self.ui.scrollAreaSubsets
assert isinstance(self.scrollArea, MapViewScrollArea)
self.mRefreshTimer = QTimer(self)
self.mRefreshTimer.setInterval(1000)
self.mRefreshTimer.timeout.connect(self.refresh)
self.scrollArea.sigResized.connect(self.mRefreshTimer.start)
self.scrollArea.horizontalScrollBar().valueChanged.connect(self.mRefreshTimer.start)

benjamin.jakimow@geo.hu-berlin.de
committed
self.TSV = timeSeriesViewer
self.TS = timeSeriesViewer.TS

benjamin.jakimow@geo.hu-berlin.de
committed
self.targetLayout = self.ui.scrollAreaSubsetContent.layout()
#self.MVC = MapViewCollection(self)
#self.MVC.sigShowProfiles.connect(self.sigShowProfiles.emit)
self.MVC = self.ui.dockMapViews
assert isinstance(self.MVC, MapViewCollectionDock)

benjamin.jakimow@geo.hu-berlin.de
committed
self.MVC.sigShowProfiles.connect(self.sigShowProfiles.emit)
self.vectorOverlay = None
self.DVC.sigResizeRequired.connect(self.adjustScrollArea)

Benjamin Jakimow
committed
#self.DVC.sigLoadingStarted.connect(self.ui.dockRendering.addStartedWork)
#self.DVC.sigLoadingFinished.connect(self.ui.dockRendering.addFinishedWork)
#self.timeSeriesDateViewCollection.sigSpatialExtentChanged.connect(self.setSpatialExtent)
self.TS.sigTimeSeriesDatesAdded.connect(self.DVC.addDates)
self.TS.sigTimeSeriesDatesRemoved.connect(self.DVC.removeDates)

benjamin.jakimow@geo.hu-berlin.de
committed
#add dates, if already existing

benjamin.jakimow@geo.hu-berlin.de
committed
if len(self.TS) > 0:
self.setSpatialExtent(self.TS.getMaxSpatialExtent())

benjamin.jakimow@geo.hu-berlin.de
committed

benjamin.jakimow@geo.hu-berlin.de
committed
def createMapView(self):
self.MVC.createMapView()
def registerMapCanvas(self, mapCanvas):
from timeseriesviewer.mapcanvas import MapCanvas
assert isinstance(mapCanvas, MapCanvas)
self.mMapCanvases.append(mapCanvas)
#set general canvas properties
mapCanvas.setFixedSize(self.mSize)
mapCanvas.setCrs(self.mCRS)
mapCanvas.setSpatialExtent(self.mSpatialExtent)
#register on map canvas signals
mapCanvas.sigSpatialExtentChanged.connect(lambda e: self.setSpatialExtent(e, mapCanvas))

benjamin.jakimow@geo.hu-berlin.de
committed
def setCrosshairStyle(self, crosshairStyle):
from timeseriesviewer.mapcanvas import MapCanvas
for mapCanvas in self.mMapCanvases:
assert isinstance(mapCanvas, MapCanvas)
mapCanvas.setCrosshairStyle(crosshairStyle)
#self.MVC.setCrosshairStyle(crosshairStyle)

benjamin.jakimow@geo.hu-berlin.de
committed
def setShowCrosshair(self, b):
self.MVC.setShowCrosshair(b)
def setVectorLayer(self, lyr):
self.MVC.setVectorLayer(lyr)

benjamin.jakimow@geo.hu-berlin.de
committed
assert isinstance(size, QSize)
from timeseriesviewer.mapcanvas import MapCanvas
for mapCanvas in self.mMapCanvases:
assert isinstance(mapCanvas, MapCanvas)
mapCanvas.setFixedSize(size)
self.sigMapSizeChanged.emit(self.mSize)

benjamin.jakimow@geo.hu-berlin.de
committed
self.adjustScrollArea()
def subsetSize(self):
return QSize(self.mSize)

benjamin.jakimow@geo.hu-berlin.de
committed
def refresh(self):

benjamin.jakimow@geo.hu-berlin.de
committed
tsdView.refresh()

benjamin.jakimow@geo.hu-berlin.de
committed
def adjustScrollArea(self):
#adjust scroll area widget to fit all visible widgets
m = self.targetLayout.contentsMargins()

benjamin.jakimow@geo.hu-berlin.de
committed
w = h = 0
s = QSize()
r = None
tsdViews = [v for v in self.DVC if v.ui.isVisible()]
mapViews = [v for v in self.MVC if v.isVisible()]
nX = len(tsdViews)
nY = len(mapViews)
spacing = self.targetLayout.spacing()
margins = self.targetLayout.contentsMargins()

benjamin.jakimow@geo.hu-berlin.de
committed
sizeX = 1
sizeY = 50
if nX > 0:
s = tsdViews[0].ui.sizeHint().width()
s = nX * (s + spacing) + margins.left() + margins.right()
sizeX = s
if nY > 0 and nX > 0:
s = tsdViews[0].ui.sizeHint().height()
s = s + margins.top() + margins.bottom()

benjamin.jakimow@geo.hu-berlin.de
committed
#s = tsdViews[0].ui.sizeHint()
#s = QSize(nX * (s.width() + spacing) + margins.left() + margins.right(),
# s.height() + margins.top() + margins.bottom())

benjamin.jakimow@geo.hu-berlin.de
committed
#print(sizeX, sizeY)
self.targetLayout.parentWidget().setFixedSize(QSize(sizeX, sizeY))

benjamin.jakimow@geo.hu-berlin.de
committed
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
def setMapTool(self, mapToolKey, *args, **kwds):
# filter map tools
self.mMapToolActivator = self.sender()
del self.mMapTools[:]
from timeseriesviewer.mapcanvas import MapTools, CursorLocationMapTool, SpectralProfileMapTool, TemporalProfileMapTool
for canvas in self.mMapCanvases:
mt = None
if mapToolKey in MapTools.mapToolKeys():
mt = MapTools.create(mapToolKey, canvas, *args, **kwds)
if isinstance(mapToolKey, QgsMapTool):
mt = MapTools.copy(mapToolKey, canvas, *args, **kwds)
if isinstance(mt, QgsMapTool):
canvas.setMapTool(mt)
self.mMapTools.append(mt)
#if required, link map-tool with specific EnMAP-Box slots
if isinstance(mt, CursorLocationMapTool):
mt.sigLocationRequest[SpatialPoint, QgsMapCanvas].connect(lambda c, m : self.sigShowProfiles.emit(c,m, mapToolKey))
return self.mMapTools

benjamin.jakimow@geo.hu-berlin.de
committed
def setMaxTSDViews(self, n=-1):
self.nMaxTSDViews = n
#todo: remove views
def setSpatialCenter(self, center, mapCanvas0=None):
if self.mBlockCanvasSignals:
return True
assert isinstance(center, SpatialPoint)
center = center.toCrs(self.mCRS)
if not isinstance(center, SpatialPoint):
return
self.mBlockCanvasSignals = True
self.mSpatialExtent.setCenter(center)
for mapCanvas in self.mMapCanvases:
if mapCanvas != mapCanvas0:
oldState = mapCanvas.blockSignals(True)
mapCanvas.setCenter(center)
mapCanvas.blockSignals(oldState)
self.mBlockCanvasSignals = False
self.sigSpatialExtentChanged.emit(self.mSpatialExtent)
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
def setSpatialCenter(self, center, mapCanvas0=None):
if self.mBlockCanvasSignals:
return True
assert isinstance(center, SpatialPoint)
center = center.toCrs(self.mCRS)
if not isinstance(center, SpatialPoint):
return None
self.mBlockCanvasSignals = True
for mapCanvas in self.mMapCanvases:
if mapCanvas != mapCanvas0:
oldState = mapCanvas.blockSignals(True)
mapCanvas.setCenter(center)
mapCanvas.blockSignals(oldState)
self.mBlockCanvasSignals = False
#for mapCanvas in self.mMapCanvases:
# mapCanvas.refresh()
self.mRefreshTimer.start()
def setSpatialExtent(self, extent, mapCanvas0=None):
if self.mBlockCanvasSignals:
return True
assert isinstance(extent, SpatialExtent)
extent = extent.toCrs(self.mCRS)
if not isinstance(extent, SpatialExtent) \
or extent.isEmpty() or not extent.isFinite() \
or extent.width() <= 0 \
or extent.height() <= 0 \
or extent == self.mSpatialExtent:
self.mBlockCanvasSignals = True
self.mSpatialExtent = extent
for mapCanvas in self.mMapCanvases:
if mapCanvas != mapCanvas0:
oldState = mapCanvas.blockSignals(True)
mapCanvas.setExtent(extent)
mapCanvas.blockSignals(oldState)
#for mapCanvas in self.mMapCanvases:
# mapCanvas.refresh()
self.sigSpatialExtentChanged.emit(extent)

benjamin.jakimow@geo.hu-berlin.de
committed
def setBackgroundColor(self, color):
assert isinstance(color, QColor)
self.mColor = color
for mapCanvas in self.mMapCanvases:
assert isinstance(mapCanvas, MapCanvas)
mapCanvas.setCanvasColor(color)
mapCanvas.refresh()
def backgroundColor(self):
return self.mColor
def mapCanvasIterator(self):
return self.mMapCanvases[:]
def setCrs(self, crs):
assert isinstance(crs, QgsCoordinateReferenceSystem)
from timeseriesviewer.utils import saveTransform
if saveTransform(self.mSpatialExtent, self.mCRS, crs):
self.mCRS = crs
for mapCanvas in self.mapCanvasIterator():
#print(('STV set CRS {} {}', str(mapCanvas), self.mCRS.description()))
mapCanvas.setCrs(crs)
else:
pass
self.sigCRSChanged.emit(self.mCRS)

benjamin.jakimow@geo.hu-berlin.de
committed
def spatialExtent(self):
return self.mSpatialExtent

benjamin.jakimow@geo.hu-berlin.de
committed
def navigateToTSD(self, TSD):
assert isinstance(TSD, TimeSeriesDatum)
#get widget related to TSD

benjamin.jakimow@geo.hu-berlin.de
committed
assert isinstance(self.scrollArea, QScrollArea)
self.scrollArea.ensureWidgetVisible(tsdv.ui)

benjamin.jakimow@geo.hu-berlin.de
committed
sigResizeRequired = pyqtSignal()
sigLoadingStarted = pyqtSignal(MapView, TimeSeriesDatum)
sigLoadingFinished = pyqtSignal(MapView, TimeSeriesDatum)

benjamin.jakimow@geo.hu-berlin.de
committed
sigShowProfiles = pyqtSignal(SpatialPoint)
sigSpatialExtentChanged = pyqtSignal(SpatialExtent)

benjamin.jakimow@geo.hu-berlin.de
committed
def __init__(self, STViz):
assert isinstance(STViz, SpatialTemporalVisualization)
super(DateViewCollection, self).__init__()

benjamin.jakimow@geo.hu-berlin.de
committed
#self.tsv = tsv
#self.timeSeries = tsv.TS
self.views = list()
self.STV = STViz
self.ui = self.STV.targetLayout.parentWidget()

benjamin.jakimow@geo.hu-berlin.de
committed
self.scrollArea = self.ui.parentWidget().parentWidget()
#potentially there are many more dates than views.
#therefore we implement the addinng/removing of mapviews here
#we reduce the number of layout refresh calls by
#suspending signals, adding the new map view canvases, and sending sigResizeRequired
self.STV.MVC.sigMapViewAdded.connect(self.addMapView)
self.STV.MVC.sigMapViewRemoved.connect(self.removeMapView)

benjamin.jakimow@geo.hu-berlin.de
committed
self.setFocusView(None)

benjamin.jakimow@geo.hu-berlin.de
committed
def tsdFromMapCanvas(self, mapCanvas):
assert isinstance(mapCanvas, MapCanvas)
for view in self.views:
assert isinstance(view, DatumView)
if mapCanvas in view.mapCanvases.values():
return view.TSD
return None

benjamin.jakimow@geo.hu-berlin.de
committed
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
def tsdView(self, tsd):
r = [v for v in self.views if v.TSD == tsd]
if len(r) == 1:
return r[0]
else:
raise Exception('TSD not in list')
def addMapView(self, mapView):
assert isinstance(mapView, MapView)
w = self.ui
w.setUpdatesEnabled(False)
for tsdv in self.views:
tsdv.ui.setUpdatesEnabled(False)
for tsdv in self.views:
tsdv.insertMapView(mapView)
for tsdv in self.views:
tsdv.ui.setUpdatesEnabled(True)
#mapView.sigSensorRendererChanged.connect(lambda *args : self.setRasterRenderer(mapView, *args))
mapView.sigMapViewVisibility.connect(lambda: self.sigResizeRequired.emit())
mapView.sigShowProfiles.connect(self.sigShowProfiles.emit)

benjamin.jakimow@geo.hu-berlin.de
committed
w.setUpdatesEnabled(True)

benjamin.jakimow@geo.hu-berlin.de
committed
self.sigResizeRequired.emit()
def removeMapView(self, mapView):
assert isinstance(mapView, MapView)
for tsdv in self.views:
tsdv.removeMapView(mapView)
self.sigResizeRequired.emit()

benjamin.jakimow@geo.hu-berlin.de
committed
def highlightDate(self, tsd):
"""
Highlights a time series data for a specific time our
:param tsd:
:return:
"""
tsdView = self.tsdView(tsd)
if isinstance(tsdView, DatumView):
tsdView.setHighlight(True)

benjamin.jakimow@geo.hu-berlin.de
committed
def setFocusView(self, tsd):
self.focusView = tsd
def orderedViews(self):
#returns the
if self.focusView is not None:
assert isinstance(self.focusView, DatumView)

benjamin.jakimow@geo.hu-berlin.de
committed
return sorted(self.views,key=lambda v: np.abs(v.TSD.date - self.focusView.TSD.date))
else:
return self.views

benjamin.jakimow@geo.hu-berlin.de
committed
def setSubsetSize(self, size):
assert isinstance(size, QSize)
self.subsetSize = size
for tsdView in self.orderedViews():
tsdView.blockSignals(True)
for tsdView in self.orderedViews():
tsdView.setSubsetSize(size)
for tsdView in self.orderedViews():
tsdView.blockSignals(False)

benjamin.jakimow@geo.hu-berlin.de
committed
def addDates(self, tsdList):
"""
Create a new TSDView
:param tsdList:
:return:
"""
for tsd in tsdList:
assert isinstance(tsd, TimeSeriesDatum)
#tsdView.setSubsetSize(self.subsetSize)
DV.sigLoadingStarted.connect(self.sigLoadingStarted.emit)
DV.sigLoadingFinished.connect(self.sigLoadingFinished.emit)
DV.sigVisibilityChanged.connect(lambda: self.STV.adjustScrollArea())

benjamin.jakimow@geo.hu-berlin.de
committed
for i, mapView in enumerate(self.STV.MVC):
DV.insertMapView(mapView)

benjamin.jakimow@geo.hu-berlin.de
committed
bisect.insort(self.views, DV)
i = self.views.index(DV)

benjamin.jakimow@geo.hu-berlin.de
committed
DV.ui.setParent(self.STV.targetLayout.parentWidget())
self.STV.targetLayout.insertWidget(i, DV.ui)
DV.ui.show()

benjamin.jakimow@geo.hu-berlin.de
committed
if len(tsdList) > 0:
self.sigResizeRequired.emit()
def removeDates(self, tsdList):
toRemove = [v for v in self.views if v.TSD in tsdList]
removedDates = []
for DV in toRemove:
self.views.remove(DV)

benjamin.jakimow@geo.hu-berlin.de
committed
for mapCanvas in DV.mapCanvases.values():
toRemove = mapCanvas.layers()
mapCanvas.setLayers([])
toRemove = [l for l in toRemove if isinstance(l, QgsRasterLayer)]
if len(toRemove) > 0:
QgsProject.instance().removeMapLayers([l.id() for l in toRemove])

benjamin.jakimow@geo.hu-berlin.de
committed
DV.ui.parent().layout().removeWidget(DV.ui)
DV.ui.hide()
DV.ui.close()
removedDates.append(DV.TSD)
del DV

benjamin.jakimow@geo.hu-berlin.de
committed
if len(removedDates) > 0:
self.sigResizeRequired.emit()
def __len__(self):
return len(self.views)
def __iter__(self):
return iter(self.views)
def __getitem__(self, slice):
return self.views[slice]
def __delitem__(self, slice):
self.removeDates(self.views[slice])
class MapViewListModel(QAbstractListModel):
"""
A model to keep a list of map views.
"""
sigMapViewsAdded = pyqtSignal(list)
sigMapViewsRemoved = pyqtSignal(list)
def __init__(self, parent=None):
super(MapViewListModel, self).__init__(parent)
self.mMapViewList = []
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
def addMapView(self, mapView):
i = len(self.mMapViewList)
self.insertMapView(i, mapView)
def insertMapView(self, i, mapView):
self.insertMapViews(i, [mapView])
def insertMapViews(self, i, mapViews):
assert isinstance(mapViews, list)
assert i >= 0 and i <= len(self.mMapViewList)
self.beginInsertRows(QModelIndex(), i, i + len(mapViews) - 1)
for j in range(len(mapViews)):
mapView = mapViews[j]
assert isinstance(mapView, MapView)
mapView.sigTitleChanged.connect(
lambda : self.doRefresh([mapView])
)
self.mMapViewList.insert(i + j, mapView)
self.endInsertRows()
self.sigMapViewsAdded.emit(mapViews)
def doRefresh(self, mapViews):
for mapView in mapViews:
idx = self.mapView2idx(mapView)
self.dataChanged.emit(idx, idx)
def removeMapView(self, mapView):
self.removeMapViews([mapView])
def removeMapViews(self, mapViews):
assert isinstance(mapViews, list)
for mv in mapViews:
assert mv in self.mMapViewList
idx = self.mapView2idx(mv)
self.beginRemoveRows(idx.parent(), idx.row(), idx.row())
self.mMapViewList.remove(mv)
self.endRemoveRows()
self.sigMapViewsRemoved.emit(mapViews)
def rowCount(self, parent=None, *args, **kwargs):
return len(self.mMapViewList)
def columnCount(self, QModelIndex_parent=None, *args, **kwargs):
return 1
def idx2MapView(self, index):
if isinstance(index, QModelIndex):
if index.isValid():
index = index.row()
else:
return None
assert index >= 0 and index < len(self.mMapViewList)
return self.mMapViewList[index]
def mapView2idx(self, mapView):
assert isinstance(mapView, MapView)
row = self.mMapViewList.index(mapView)
return self.createIndex(row, 0, mapView)
def __len__(self):
return len(self.mMapViewList)
def __iter__(self):
return iter(self.mMapViewList)
def __getitem__(self, slice):
return self.mMapViewList[slice]
def data(self, index, role=Qt.DisplayRole):
if not index.isValid():
return None
if (index.row() >= len(self.mMapViewList)) or (index.row() < 0):
return None
mapView = self.idx2MapView(index)
assert isinstance(mapView, MapView)
value = None
if role == Qt.DisplayRole:
value = '{} {}'.format(index.row() +1 , mapView.title())
#if role == Qt.DecorationRole:
#value = classInfo.icon(QSize(20,20))
if role == Qt.UserRole:
value = mapView
return value

benjamin.jakimow@geo.hu-berlin.de
committed
class MapViewCollectionDock(QgsDockWidget, loadUI('mapviewdock.ui')):
sigMapViewAdded = pyqtSignal(MapView)
sigMapViewRemoved = pyqtSignal(MapView)
sigShowProfiles = pyqtSignal(SpatialPoint, MapCanvas, str)

Benjamin Jakimow
committed
sigMapCanvasColorChanged = pyqtSignal(QColor)
sigSpatialExtentChanged = pyqtSignal(SpatialExtent)
sigCrsChanged = pyqtSignal(QgsCoordinateReferenceSystem)
sigMapSizeChanged = pyqtSignal(QSize)
def setTimeSeries(self, timeSeries):
assert isinstance(timeSeries, TimeSeries)
self.TS = timeSeries
self.TS.sigSensorAdded.connect(self.addSensor)
self.TS.sigSensorRemoved.connect(self.removeSensor)
self.mMapViews = MapViewListModel()
self.btnAddMapView.setDefaultAction(self.actionAddMapView)
self.btnRemoveMapView.setDefaultAction(self.actionRemoveMapView)
self.btnRefresh.setDefaultAction(self.actionApplyStyles)

benjamin.jakimow@geo.hu-berlin.de
committed
self.btnHighlightMapView.setDefaultAction(self.actionHighlightMapView)

Benjamin Jakimow
committed
self.btnCrs.crsChanged.connect(self.sigCrsChanged)
self.btnMapCanvasColor.colorChanged.connect(self.sigMapCanvasColorChanged)
self.btnApplySizeChanges.clicked.connect(lambda : self.sigMapSizeChanged.emit(QSize(self.spinBoxMapSizeX.value(),self.spinBoxMapSizeY.value())))
self.actionAddMapView.triggered.connect(self.createMapView)
self.actionRemoveMapView.triggered.connect(lambda : self.removeMapView(self.currentMapView()) if self.currentMapView() else None)
self.actionHighlightMapView.triggered.connect(lambda : self.currentMapView().setHighlighted(True) if self.currentMapView() else None)
self.actionApplyStyles.triggered.connect(self.refreshCurrentMapView)
#self.actionApplyStyles.triggered.connect(self.dummySlot)
self.mMapViews.sigMapViewsRemoved.connect(self.onMapViewsRemoved)
self.mMapViews.sigMapViewsAdded.connect(self.onMapViewsAdded)
self.mMapViews.sigMapViewsAdded.connect(self.updateButtons)
self.mMapViews.sigMapViewsRemoved.connect(self.updateButtons)
self.cbMapView.currentIndexChanged[int].connect(lambda i : None if i < 0 else self.setCurrentMapView(self.mMapViews.idx2MapView(i)) )

Benjamin Jakimow
committed
self.spinBoxMapSizeX.valueChanged.connect(lambda: self.onMapSizeChanged('X'))
self.spinBoxMapSizeY.valueChanged.connect(lambda: self.onMapSizeChanged('Y'))
self.mLastMapSize = self.mapSize()
#self.mapSize() #inits mLastMapSize

Benjamin Jakimow
committed
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
def setCrs(self, crs):
assert isinstance(crs, QgsCoordinateReferenceSystem)
self.btnCrs.setCrs(crs)
self.btnCrs.setLayerCrs(crs)
def setMapSize(self, size):
assert isinstance(size, QSize)
ws = [self.spinBoxMapSizeX, self.spinBoxMapSizeY]
oldSize = self.mapSize()
b = oldSize != size
for w in ws:
w.blockSignals(True)
self.spinBoxMapSizeX.setValue(size.width()),
self.spinBoxMapSizeY.setValue(size.height())
self.mLastMapSize = QSize(size)
for w in ws:
w.blockSignals(False)
self.mLastMapSize = QSize(size)
if b:
self.sigMapSizeChanged.emit(size)
def onMapSizeChanged(self, dim):
newSize = self.mapSize()
#1. set size of other dimension accordingly
if dim is not None:
if self.checkBoxKeepSubsetAspectRatio.isChecked():
if dim == 'X':
vOld = self.mLastMapSize.width()
vNew = newSize.width()
targetSpinBox = self.spinBoxMapSizeY
elif dim == 'Y':
vOld = self.mLastMapSize.height()
vNew = newSize.height()
targetSpinBox = self.spinBoxMapSizeX
oldState = targetSpinBox.blockSignals(True)
targetSpinBox.setValue(int(round(float(vNew) / vOld * targetSpinBox.value())))
targetSpinBox.blockSignals(oldState)
newSize = self.mapSize()
if newSize != self.mLastMapSize:
self.btnApplySizeChanges.setEnabled(True)
else:
self.sigMapSizeChanged.emit(self.mapSize())
self.btnApplySizeChanges.setEnabled(False)
self.setMapSize(newSize)
def mapSize(self):
return QSize(self.spinBoxMapSizeX.value(),
self.spinBoxMapSizeY.value())
def refreshCurrentMapView(self, *args):
mv = self.currentMapView()
if isinstance(mv, MapView):
mv.refreshMapView()
else:
s =""
def dummySlot(self):
s =""
for mapView in mapViews:
idx = self.stackedWidget.indexOf(mapView.ui)
if idx >= 0:
self.stackedWidget.removeWidget(mapView.ui)
mapView.ui.close()
else:
s = ""
self.actionRemoveMapView.setEnabled(len(self.mMapViews) > 0)
def onMapViewsAdded(self, mapViews):
nextShown = None
for mapView in mapViews:
mapView.sigTitleChanged.connect(self.updateTitle)
self.stackedWidget.addWidget(mapView.ui)
if nextShown is None:
nextShown = mapView
contents = mapView.ui.scrollAreaWidgetContents
size = contents.size()
hint = contents.sizeHint()
#mapView.ui.scrollArea.update()
s = ""
#setMinimumSize(mapView.ui.scrollAreaWidgetContents.sizeHint())
#hint = contents.sizeHint()
#contents.setMinimumSize(hint)
if isinstance(nextShown, MapView):
self.setCurrentMapView(nextShown)
def updateButtons(self, *args):
b = len(self.mMapViews) > 0
self.actionRemoveMapView.setEnabled(b)
self.actionApplyStyles.setEnabled(b)
self.actionHighlightMapView.setEnabled(b)
n = len(self.mMapViews) + 1
title = 'Map View {}'.format(n)
while title in [m.title() for m in self.mMapViews]:
n += 1
title = 'Map View {}'.format(n)
mapView.setTitle(title)
mapView.sigShowProfiles.connect(self.sigShowProfiles)