Newer
Older
# -*- coding: utf-8 -*-
"""
/***************************************************************************

Benjamin Jakimow
committed
EO Time Series Viewer
-------------------
begin : 2015-08-20
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
from qgis.core import *
from qgis.gui import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtXml import QDomDocument

Benjamin Jakimow
committed
from . import SETTINGS
from .utils import *
from .timeseries import TimeSeriesDatum
from .crosshair import CrosshairDialog, CrosshairStyle
from .maptools import *
class MapLayerInfo(object):
"""
A minimum description of a QgsMapLayer source.
"""
def __init__(self, srcOrMapLayer, isVisible, provider='gdal', renderer=None):
self.mSrc = ''
self.mLayer = None
self.mProvider = None
self.mRenderer = None
self.setRenderer(renderer)
if isinstance(srcOrMapLayer, QgsMapLayer):
self.mSrc = srcOrMapLayer.source()
self.mProvider = srcOrMapLayer.providerType()
self.mLayer = srcOrMapLayer
if isinstance(srcOrMapLayer, QgsVectorLayer):
self.mRenderer = srcOrMapLayer.renderer()
elif isinstance(srcOrMapLayer, QgsRasterLayer):
self.mRenderer = srcOrMapLayer.renderer()

Benjamin Jakimow
committed
assert provider in ['ogr','gdal','memory']
self.mIsVisible = isVisible
def isSameSource(self, other):
if not isinstance(other, MapLayerInfo):
return False
return self.mSrc == other.mSrc
def initMapLayer(self):
if self.mProvider == 'gdal':
self.mLayer = QgsRasterLayer(self.mSrc)
elif self.mProvider == 'ogr':
self.mLayer = QgsVectorLayer(self.mSrc,os.path.basename(self.mSrc), 'ogr', True)
self.setRenderer(self.mRenderer)
def setRenderer(self, renderer):
self.mRenderer = renderer
if self.mProvider == 'ogr' and isinstance(renderer, QgsFeatureRenderer) or \
self.mProvider == 'gdal' and isinstance(renderer, QgsRasterRenderer):
self.mRenderer = renderer
if self.isInitialized():
from timeseriesviewer.mapvisualization import cloneRenderer
copyRenderer(self.mRenderer, self.mLayer)
def setIsVisible(self, b):
self.mIsVisible = b
def isVisible(self):
return self.mIsVisible
def layer(self):
"""returns a QgsMapLayer object related to the specified source.
If not provided in the constructor, the QgsMapLayer will be initialized with first call of this method.
"""
if not self.isInitialized():
self.initMapLayer()
return self.mLayer
def isInitialized(self):
return isinstance(self.mLayer, QgsMapLayer)
def isRegistered(self):
if not self.isInitialized():
return None
ref = QgsProject.instance().mapLayer(self.mLayer.layerId())
return isinstance(ref, QgsMapLayer)
class MapCanvasLayerModel(QAbstractTableModel):
"""
A model to save a list of QgsMapLayers and additional properties.
"""
def __init__(self, parent=None):
super(MapCanvasLayerModel, self).__init__(parent=parent)
self.mColumnNames = ['layerID', 'isVisible', '']
self.mLayerInfos = []
def __len__(self):
return len(self.mLayerInfos)
def __iter__(self):
return iter(self.mLayerInfos)
def __repr__(self):
info = 'MapLayerModel::'
for li in self.mLayerInfos:
if li.isVisible():
info += '{}'.format(li.mSrc)
return info
def setRenderer(self, renderer):
for li in self.mLayerInfos:
assert isinstance(li, MapLayerInfo)
li.setRenderer(renderer)
def setVectorLayerSources(self, vectorSources, **kwds):
self.removeLayerInfos(self.vectorLayerInfos())
self.insertLayerInfos(0, vectorSources, provider='ogr', **kwds)
def setVectorLayerVisibility(self, b):
for li in self.vectorLayerInfos():
li.setIsVisible(b)
def setRasterLayerVisibility(self, b):
for li in self.rasterLayerInfos():
li.setIsVisible(b)
def setRasterLayerSources(self, rasterSources, **kwds):
self.removeLayerInfos(self.rasterLayerInfos())
self.addLayerInfos(rasterSources, provider='gdal', **kwds)
def vectorLayerInfos(self):

Benjamin Jakimow
committed
return [li for li in self.mLayerInfos if li.mProvider in ['ogr', 'memory']]
def rasterLayerInfos(self):
return [li for li in self.mLayerInfos if li.mProvider == 'gdal']
def addLayerInfo(self, mapLayer, **kwds):
self.addLayerInfos([mapLayer], **kwds)
def addLayerInfos(self, mapLayers, **kwds):
self.insertLayerInfos(len(self), mapLayers, **kwds)
def insertLayerInfo(self, i, mapLayer, **kwds):
self.insertLayerInfo(i, [mapLayer], **kwds)
def insertLayerInfos(self, i, mapLayers, isVisible=True, provider='gdal'):
for mapLayer in mapLayers:
if isinstance(mapLayer, QgsRasterLayer) and provider != 'gdal':
continue

Benjamin Jakimow
committed
if isinstance(mapLayer, QgsVectorLayer) and provider not in ['ogr', 'memory']:

Benjamin Jakimow
committed
if isinstance(mapLayer, QgsMapLayer):
li = MapLayerInfo(mapLayer, isVisible=isVisible, provider=mapLayer.dataProvider().name())
elif isinstance(mapLayer, QgsRasterLayer):
li = MapLayerInfo(mapLayer, isVisible=isVisible, provider=mapLayer.dataProvider().name())
elif isinstance(mapLayer, str):
li = MapLayerInfo(mapLayer, isVisible=isVisible, provider=provider)

Benjamin Jakimow
committed
if isinstance(li, MapLayerInfo):
self.mLayerInfos.insert(i, li)
i += 1
def removeLayerInfo(self, mapLayer):
self.removeLayerInfos([mapLayer])
def removeLayerInfos(self, mapLayers):
toRemove = []
sourcesToRemove = []
for ml in mapLayers:
if isinstance(ml, QgsMapLayer):
sourcesToRemove.append(ml.source())
else:
sourcesToRemove.append(ml)
toRemove = [li for li in self.mLayerInfos if li in sourcesToRemove]
for li in toRemove:
self.mLayerInfos.remove(li)
def layerSources(self):
return [li.mSrc for li in self.mLayerInfos]
def layers(self):
return [li.layer() for li in self.mLayerInfos]
def visibleLayers(self):
return [li.layer() for li in self.mLayerInfos if li.isVisible()]
def rowCount(self, QModelIndex_parent=None, *args, **kwargs):
return len(self.mLayers)
def columnCount(self, QModelIndex_parent=None, *args, **kwargs):
return self
class MapCanvas(QgsMapCanvas):
saveFileDirectories = dict()
sigShowProfiles = pyqtSignal(SpatialPoint, str)
sigSpatialExtentChanged = pyqtSignal(SpatialExtent)
sigChangeDVRequest = pyqtSignal(QgsMapCanvas, str)
sigChangeMVRequest = pyqtSignal(QgsMapCanvas, str)
sigChangeSVRequest = pyqtSignal(QgsMapCanvas, QgsRasterRenderer)

benjamin.jakimow@geo.hu-berlin.de
committed
sigDataLoadingFinished = pyqtSignal(np.timedelta64)

Benjamin Jakimow
committed
sigCrosshairPositionChanged = pyqtSignal(SpatialPoint)
sigCrosshairVisibilityChanged = pyqtSignal(bool)
from .crosshair import CrosshairStyle
sigCrosshairStyleChanged = pyqtSignal(CrosshairStyle)
def __init__(self, parent=None):
super(MapCanvas, self).__init__(parent=parent)
self.mLayerModel = MapCanvasLayerModel(parent=self)
#the canvas

benjamin.jakimow@geo.hu-berlin.de
committed
self.mRenderingFinished = False

benjamin.jakimow@geo.hu-berlin.de
committed
def onRenderingStarted(*args):
self.mRenderingFinished = False
self.mRenderStartTime = np.datetime64('now', 'ms')
def onRenderingFinished(*args):
self.mRenderingFinished = True

benjamin.jakimow@geo.hu-berlin.de
committed
dt = np.datetime64('now', 'ms') - self.mRenderStartTime
self.sigDataLoadingFinished.emit(dt)
self.renderStarting.connect(onRenderingStarted)
self.renderComplete.connect(onRenderingFinished)
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.setCanvasColor(SETTINGS.value('CANVAS_BACKGROUND_COLOR', QColor(0, 0, 0)))
self.setContextMenuPolicy(Qt.DefaultContextMenu)
#refreshTimer.timeout.connect(self.onTimerRefresh)
#self.extentsChanged.connect(lambda : self._setDataRefreshed())
self.extentsChanged.connect(lambda : self.sigSpatialExtentChanged.emit(self.spatialExtent()))
#self.mLazyRasterSources = []
#self.mLazyVectorSources = []
self.mRendererRaster = None
self.mRendererVector = None
from timeseriesviewer.crosshair import CrosshairMapCanvasItem

Benjamin Jakimow
committed
self.mCrosshairItem = CrosshairMapCanvasItem(self)
self.mMapTools = dict()
self.mMapTools['zoomOut'] = QgsMapToolZoom(self, True)
self.mMapTools['zoomIn'] = QgsMapToolZoom(self, False)
self.mMapTools['pan'] = QgsMapToolPan(self)
from timeseriesviewer.maptools import CursorLocationMapTool
mt = CursorLocationMapTool(self)
mt.sigLocationRequest.connect(lambda c: self.sigShowProfiles.emit(c, 'identifyTemporalProfile'))
self.mMapTools['identifyTemporalProfile'] = mt
mt = CursorLocationMapTool(self)
mt.sigLocationRequest.connect(lambda c : self.sigShowProfiles.emit(c, 'identifySpectralProfile'))
self.mMapTools['identifySpectralProfile'] = mt
mt = CursorLocationMapTool(self)
#mt.sigLocationRequest.connect(self.sigShowProfiles.emit)
mt.sigLocationRequest.connect(lambda c: self.sigShowProfiles.emit(c, 'identifyCursorLocationValues'))
self.mMapTools['identifyCursorLocationValues'] = mt
mt = CursorLocationMapTool(self)
mt.sigLocationRequest.connect(lambda pt: self.setCenter(pt))
self.mMapTools['moveCenter'] = mt
def renderingFinished(self)->bool:
"""
Returns whether the MapCanvas is processing a rendering task
:return: bool
"""
return self.mRenderingFinished

Benjamin Jakimow
committed
def mousePressEvent(self, event:QMouseEvent):
b = event.button() == Qt.LeftButton
if b and isinstance(self.mapTool(), QgsMapTool):
from timeseriesviewer.maptools import CursorLocationMapTool
b = isinstance(self.mapTool(), (QgsMapToolIdentify,
CursorLocationMapTool,
SpectralProfileMapTool, TemporalProfileMapTool))
super(MapCanvas, self).mousePressEvent(event)
if b:
ms = self.mapSettings()
pointXY = ms.mapToPixel().toMapCoordinates(event.x(), event.y())
spatialPoint = SpatialPoint(ms.destinationCrs(), pointXY)
self.setCrosshairPosition(spatialPoint)
def setMapView(self, mapView):
from timeseriesviewer.mapvisualization import MapView
assert isinstance(mapView, MapView)
self.mMapView = mapView

Benjamin Jakimow
committed
scope = self.expressionContextScope()
def setTSD(self, tsd):
from timeseriesviewer.timeseries import TimeSeriesDatum
assert isinstance(tsd, TimeSeriesDatum)
self.mTSD = tsd

Benjamin Jakimow
committed
scope = self.expressionContextScope()
scope.setVariable('map_date', str(tsd.date), isStatic=True)
scope.setVariable('map_doy', tsd.doy, isStatic=True)
scope.setVariable('map_sensor', tsd.sensor.name(), isStatic=False)
tsd.sensor.sigNameChanged.connect(lambda name : scope.setVariable('map_sensor', name))
s = ""
def setFixedSize(self, size):
assert isinstance(size, QSize)
if self.size() != size:
super(MapCanvas, self).setFixedSize(size)
if self.crs() != crs:
self.setDestinationCrs(crs)
"""
Shortcut to return self.mapSettings().destinationCrs()
:return: QgsCoordinateReferenceSystem
"""
return self.mapSettings().destinationCrs()
def mapSummary(self):
dom = QDomDocument()
root = dom.createElement('renderer')
dom.appendChild(root)
if self.mRendererVector:
self.mRendererVector.writeXML(dom, root)
if self.mRendererRaster:
self.mRendererRaster.writeXML(dom, root)
xml = dom.toString()
return (self.crs(), self.spatialExtent(), self.size(), self.mLayerModel.visibleLayers(), xml)
def layerModel(self):
return self.mLayerModel

benjamin.jakimow@geo.hu-berlin.de
committed
def setLayers(self, mapLayers):
"""
Set the map layers and, if necessary, registers the in a QgsMapLayerStore
:param mapLayers:
"""

benjamin.jakimow@geo.hu-berlin.de
committed
from .utils import MAP_LAYER_STORES
if len(MAP_LAYER_STORES) > 0:
store = MAP_LAYER_STORES[0]
store.addMapLayers(mapLayers)
print('MAPCANVAS without map layer store', file=sys.stderr)
super(MapCanvas, self).setLayers(mapLayers)
#self.refresh()
def IsViewportVisible(self)->bool:
return self.visibleRegion().boundingRect().isValid()
def refresh(self, force=False):
"""
low-level, only performed if MapCanvas is visible or force=True
:param force: bool
"""
isVisible = self.visibleRegion().boundingRect().isValid() and self.isVisible()
if isVisible or force:
mLyrs = self.layers()
vLyrs = self.mLayerModel.visibleLayers()
if mLyrs != vLyrs:
self.setLayers(vLyrs)
if self.renderFlag() or force:
super(MapCanvas, self).refresh()
def setCrosshairStyle(self, crosshairStyle:CrosshairStyle, emitSignal=True):
"""
Sets the CrosshairStyle
:param crosshairStyle: CrosshairStyle
:param emitSignal: Set to Fals to no emit a signal.
"""
from timeseriesviewer.crosshair import CrosshairStyle
if crosshairStyle is None:

Benjamin Jakimow
committed
self.mCrosshairItem.crosshairStyle.setShow(False)
self.mCrosshairItem.update()
else:
assert isinstance(crosshairStyle, CrosshairStyle)

Benjamin Jakimow
committed
self.mCrosshairItem.setCrosshairStyle(crosshairStyle)

Benjamin Jakimow
committed
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
if emitSignal:
self.sigCrosshairStyleChanged.emit(self.mCrosshairItem.crosshairStyle)
def crosshairStyle(self)->CrosshairStyle:
return self.mCrosshairItem.crosshairStyle
def setCrosshairPosition(self, spatialPoint:SpatialPoint, emitSignal=True):
"""
Sets the position of the Crosshair.
:param spatialPoint: SpatialPoint
:param emitSignal: True (default). Set False to avoid emitting sigCrosshairPositionChanged
:return:
"""
point = spatialPoint.toCrs(self.mapSettings().destinationCrs())
self.mCrosshairItem.setPosition(point)
if emitSignal:
self.sigCrosshairPositionChanged.emit(point)
def crosshairPosition(self)->SpatialPoint:
"""Returns the last crosshair position"""
return self.mCrosshairItem.mPosition
def setCrosshairVisibility(self, b:bool, emitSignal=True):
"""
Sets the Crosshair visbility
:param b: bool
"""
if b and self.mCrosshairItem.mPosition is None:
self.mCrosshairItem.setPosition(self.spatialCenter())
self.sigCrosshairPositionChanged.emit(self.spatialCenter())
if b != self.mCrosshairItem.visibility():
self.mCrosshairItem.setVisibility(b)
if emitSignal:
self.sigCrosshairVisibilityChanged.emit(b)
def layerPaths(self):
:return: [list-of-str]

benjamin.jakimow@geo.hu-berlin.de
committed
return [str(l.source()) for l in self.layers()]
def pixmap(self):
"""
Returns the current map image as pixmap
return self.grab()
def contextMenuEvent(self, event):
menu = QMenu()
# add general options
menu.addSeparator()
m = menu.addMenu('Stretch to current extent...')
action = m.addAction('Linear')
action.triggered.connect(lambda : self.stretchToExtent(self.spatialExtent(), 'linear_minmax', p=0.0))
action = m.addAction('Linear 5%')
action.triggered.connect(lambda: self.stretchToExtent(self.spatialExtent(), 'linear_minmax', p=0.05))
action = m.addAction('Gaussian')
action.triggered.connect(lambda: self.stretchToExtent(self.spatialExtent(), 'gaussian', n=3))
action = menu.addAction('Zoom to Layer')
action.triggered.connect(lambda : self.setSpatialExtent(self.spatialExtentHint()))
action = menu.addAction('Refresh')
action.triggered.connect(lambda: self.refresh(True))
menu.addSeparator()
action = menu.addAction('Change crosshair style')

Benjamin Jakimow
committed
def onCrosshairChange(*args):
style = CrosshairDialog.getCrosshairStyle(parent=self,

benjamin.jakimow@geo.hu-berlin.de
committed
mapCanvas=self,

Benjamin Jakimow
committed
crosshairStyle=self.mCrosshairItem.crosshairStyle)
if isinstance(style, CrosshairStyle):
self.setCrosshairStyle(style)
action.triggered.connect(onCrosshairChange)

Benjamin Jakimow
committed
if self.mCrosshairItem.visibility():
action = menu.addAction('Hide crosshair')

Benjamin Jakimow
committed
action.triggered.connect(lambda : self.setCrosshairVisibility(False))
else:
action = menu.addAction('Show crosshair')

Benjamin Jakimow
committed
action.triggered.connect(lambda: self.setCrosshairVisibility(True))
menu.addSeparator()
m = menu.addMenu('Copy...')
action = m.addAction('Date')
action.triggered.connect(lambda: self.sigChangeDVRequest.emit(self, 'copy_date'))
action = m.addAction('Sensor')
action.triggered.connect(lambda: self.sigChangeDVRequest.emit(self, 'copy_sensor'))
action = m.addAction('Path')
action.triggered.connect(lambda: self.sigChangeDVRequest.emit(self, 'copy_path'))

benjamin.jakimow@geo.hu-berlin.de
committed
action = m.addAction('Map')
action.triggered.connect(lambda: QApplication.clipboard().setPixmap(self.pixmap()))
m = menu.addMenu('Map Coordinates...')
ext = self.spatialExtent()
center = self.spatialExtent().spatialCenter()
action = m.addAction('Extent (WKT Coordinates)')
action.triggered.connect(lambda: QApplication.clipboard().setText(ext.asWktCoordinates()))
action = m.addAction('Extent (WKT Polygon)')
action.triggered.connect(lambda: QApplication.clipboard().setText(ext.asWktPolygon()))
m.addSeparator()
action = m.addAction('Map Center (WKT)')

benjamin.jakimow@geo.hu-berlin.de
committed
action.triggered.connect(lambda: QApplication.clipboard().setText(center.wellKnownText()))

benjamin.jakimow@geo.hu-berlin.de
committed
action.triggered.connect(lambda: QApplication.clipboard().setText(center.toString()))
action = m.addAction('Map Extent (WKT)')
action.triggered.connect(lambda: QApplication.clipboard().setText(ext.wellKnownText()))
action = m.addAction('Map Extent')
action.triggered.connect(lambda: QApplication.clipboard().setText(ext.toString()))

benjamin.jakimow@geo.hu-berlin.de
committed
m.addSeparator()
action = m.addAction('CRS (EPSG)')
action.triggered.connect(lambda: QApplication.clipboard().setText(self.crs().authid()))
action = m.addAction('CRS (WKT)')
action.triggered.connect(lambda: QApplication.clipboard().setText(self.crs().toWkt()))
action = m.addAction('CRS (Proj4)')
action.triggered.connect(lambda: QApplication.clipboard().setText(self.crs().toProj4()))
action = m.addAction('PNG')
action.triggered.connect(lambda : self.saveMapImageDialog('PNG'))
action = m.addAction('JPEG')
action.triggered.connect(lambda: self.saveMapImageDialog('JPG'))

benjamin.jakimow@geo.hu-berlin.de
committed
from timeseriesviewer.utils import qgisInstance
actionAddRaster2QGIS = menu.addAction('Add raster layers(s) to QGIS')
actionAddRaster2QGIS.triggered.connect(lambda : self.addLayers2QGIS(
[l for l in self.layers() if isinstance(l, QgsRasterLayer)]
)
)
# QGIS 3: action.triggered.connect(lambda: QgsProject.instance().addMapLayers([l for l in self.layers() if isinstance(l, QgsRasterLayer)]))
actionAddVector2QGIS = menu.addAction('Add vector layer(s) to QGIS')
actionAddRaster2QGIS.triggered.connect(lambda : self.addLayers2QGIS(
#QgsProject.instance().addMapLayers(
[l for l in self.layers() if isinstance(l, QgsVectorLayer)]
)
)
# QGIS 3: action.triggered.connect(lambda: QgsProject.instance().addMapLayers([l for l in self.layers() if isinstance(l, QgsVectorLayer)]))
b = isinstance(qgisInstance(), QgisInterface)
for a in [actionAddRaster2QGIS, actionAddVector2QGIS]:
a.setEnabled(b)
menu.addSeparator()
action = menu.addAction('Hide date')
action.triggered.connect(lambda : self.sigChangeDVRequest.emit(self, 'hide_date'))
action = menu.addAction('Remove date')
action.triggered.connect(lambda: self.sigChangeDVRequest.emit(self, 'remove_date'))
action = menu.addAction('Hide map view')
action.triggered.connect(lambda: self.sigChangeMVRequest.emit(self, 'hide_mapview'))
action = menu.addAction('Remove map view')
action.triggered.connect(lambda: self.sigChangeMVRequest.emit(self, 'remove_mapview'))
menu.exec_(event.globalPos())
def addLayers2QGIS(self, mapLayers):
from timeseriesviewer.utils import qgisInstance
iface = qgisInstance()
if isinstance(iface, QgisInterface):
grpNode= iface.layerTreeView().currentGroupNode()
assert isinstance(grpNode, QgsLayerTreeGroup)
for l in mapLayers:
if isinstance(l, QgsRasterLayer):
lqgis = iface.addRasterLayer(l.source(), l.name())
lqgis.setRenderer(l.renderer().clone())
lqgis = iface.addVectorLayer(l.source(), l.name(), 'ogr')
def stretchToCurrentExtent(self):
se = self.spatialExtent()
self.stretchToExtent(se)
def stretchToExtent(self, spatialExtent, stretchType='linear_minmax', **stretchArgs):
"""
:param spatialExtent: rectangle to get the image statistics for
:param stretchType: ['linear_minmax' (default), 'gaussian']
:param stretchArgs:
linear_minmax: 'p' percentage from min/max, e.g. +- 5 %
gaussian: 'n' mean +- n* standard deviations
:return:
"""
for l in self.layers():
if isinstance(l, QgsRasterLayer):
r = l.renderer()
dp = l.dataProvider()
newRenderer = None
assert isinstance(dp, QgsRasterDataProvider)
def getCE(band):
stats = dp.bandStatistics(band, QgsRasterBandStats.All, extent, 500)
# hist = dp.histogram(band,100, stats.minimumValue, stats.maximumValue, extent, 500, False)
ce = QgsContrastEnhancement(dp.dataType(band))
d = (stats.maximumValue - stats.minimumValue)
if stretchType == 'linear_minmax':
ce.setContrastEnhancementAlgorithm(QgsContrastEnhancement.StretchToMinimumMaximum)
ce.setMinimumValue(stats.minimumValue + d * stretchArgs.get('p', 0))
ce.setMaximumValue(stats.maximumValue - d * stretchArgs.get('p', 0))
elif stretchType == 'gaussian':
ce.setContrastEnhancementAlgorithm(QgsContrastEnhancement.StretchToMinimumMaximum)
ce.setMinimumValue(stats.mean - stats.stdDev * stretchArgs.get('n', 3))
ce.setMaximumValue(stats.mean + stats.stdDev * stretchArgs.get('n', 3))
else:
# stretchType == 'linear_minmax':
ce.setContrastEnhancementAlgorithm(QgsContrastEnhancement.StretchToMinimumMaximum)
ce.setMinimumValue(stats.minimumValue)
ce.setMaximumValue(stats.maximumValue)
return ce
if isinstance(r, QgsMultiBandColorRenderer):
#newRenderer = QgsMultiBandColorRenderer(None, r.redBand(), r.greenBand(), r.blueBand())
newRenderer = cloneRenderer(r)
ceR = getCE(r.redBand())
ceG = getCE(r.greenBand())
ceB = getCE(r.blueBand())
if False:
vMin = min(ceR.minimumValue(), ceG.minimumValue(), ceB.minimumValue())
vMax = max(ceR.maximumValue(), ceG.maximumValue(), ceB.maximumValue())
for ce in [ceR, ceG, ceB]:
assert isinstance(ce, QgsContrastEnhancement)
ce.setMaximumValue(vMax)
ce.setMinimumValue(vMin)
newRenderer.setRedContrastEnhancement(ceR)
newRenderer.setGreenContrastEnhancement(ceG)
newRenderer.setBlueContrastEnhancement(ceB)
elif isinstance(r, QgsSingleBandPseudoColorRenderer):
ce = getCE(newRenderer.band())
#stats = dp.bandStatistics(newRenderer.band(), QgsRasterBandStats.All, extent, 500)
shader = newRenderer.shader()
newRenderer.setClassificationMax(ce.maximumValue())
newRenderer.setClassificationMin(ce.minimumValue())
shader.setMaximumValue(ce.maximumValue())
shader.setMinimumValue(ce.minimumValue())
elif isinstance(r, QgsSingleBandGrayRenderer):
newRenderer = cloneRenderer(r)
s = ""
elif isinstance(r, QgsPalettedRasterRenderer):
s = ""
if newRenderer is not None:
self.sigChangeSVRequest.emit(self, newRenderer)
s = ""
def activateMapTool(self, key):
if key is None:
self.setMapTool(None)
elif key in self.mMapTools.keys():
super(MapCanvas, self).setMapTool(self.mMapTools[key])
else:
s = ""
#logger.error('unknown map tool key "{}"'.format(key))
def saveMapImageDialog(self, fileType):
lastDir = SETTINGS.value('CANVAS_SAVE_IMG_DIR', os.path.expanduser('~'))
from timeseriesviewer.utils import saveFilePath
from timeseriesviewer.mapvisualization import MapView
if isinstance(self.mTSD, TimeSeriesDatum) and isinstance(self.mMapView, MapView):
path = saveFilePath('{}.{}'.format(self.mTSD.date, self.mMapView.title()))
else:
path = 'mapcanvas'
path = jp(lastDir, '{}.{}'.format(path, fileType.lower()))
path, _ = QFileDialog.getSaveFileName(self, 'Save map as {}'.format(fileType), path)
if len(path) > 0:
self.saveAsImage(path, None, fileType)
SETTINGS.setValue('CANVAS_SAVE_IMG_DIR', os.path.dirname(path))

benjamin.jakimow@geo.hu-berlin.de
committed
def setRenderer(self, renderer, refresh=True):
success = self.layerModel().setRenderer(renderer)
self.setRenderFlag(True)
#self.refresh()
def setSpatialExtent(self, spatialExtent):
assert isinstance(spatialExtent, SpatialExtent)
if self.spatialExtent() != spatialExtent:
b = self.crs() != spatialExtent.crs()
spatialExtent = spatialExtent.toCrs(self.crs())
ext = QgsRectangle(spatialExtent)
if b:
s = ""
self.setCenter(ext.center())
self.setExtent(ext)
s = ""

Benjamin Jakimow
committed
def spatialExtent(self)->SpatialExtent:
"""
Returns the map extent as SpatialExtent (extent + CRS)
:return: SpatialExtent
"""
return SpatialExtent.fromMapCanvas(self)

Benjamin Jakimow
committed
def spatialCenter(self)->SpatialPoint:
"""
Returns the map center as SpatialPoint (QgsPointXY + CRS)
:return: SpatialPoint
"""
return SpatialPoint.fromMapCanvasCenter(self)
def spatialExtentHint(self):
crs = self.crs()
ext = SpatialExtent.world()
for lyr in self.mLayerModel.layers()+ self.layers():
ext = SpatialExtent.fromLayer(lyr).toCrs(crs)
break
return ext
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
class CanvasBoundingBoxItem(QgsGeometryRubberBand):
def __init__(self, mapCanvas):
assert isinstance(mapCanvas, QgsMapCanvas)
super(CanvasBoundingBoxItem, self).__init__(mapCanvas)
self.canvas = mapCanvas
self.mCanvasExtents = dict()
self.mShow = True
self.mShowTitles = True
self.setIconType(QgsGeometryRubberBand.ICON_NONE)
def connectCanvas(self, canvas):
assert isinstance(canvas, QgsMapCanvas)
assert canvas != self.canvas
if canvas not in self.mCanvasExtents.keys():
self.mCanvasExtents[canvas] = None
canvas.extentsChanged.connect(lambda : self.onExtentsChanged(canvas))
canvas.destroyed.connect(lambda : self.disconnectCanvas(canvas))
self.onExtentsChanged(canvas)
def disconnectCanvas(self, canvas):
self.mCanvasExtents.pop(canvas)
def onExtentsChanged(self, canvas):
assert isinstance(canvas, QgsMapCanvas)
ext = SpatialExtent.fromMapCanvas(canvas)
ext = ext.toCrs(self.canvas.mapSettings().destinationCrs())
assert geom.fromWkt(ext.asWktPolygon())
self.mCanvasExtents[canvas] = (ext, geom)
self.refreshExtents()
def refreshExtents(self):
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
if self.mShow:
for canvas, t in self.mCanvasExtents.items():
ext, geom = t
multi.addGeometry(geom.clone())
self.setGeometry(multi)
def paint(self, painter, QStyleOptionGraphicsItem=None, QWidget_widget=None):
super(CanvasBoundingBoxItem, self).paint(painter)
if self.mShowTitles and self.mShow:
painter.setPen(Qt.blue);
painter.setFont(QFont("Arial", 30))
for canvas, t in self.mCanvasExtents.items():
ext, geom = t
ULpx = self.toCanvasCoordinates(ext.center())
txt = canvas.windowTitle()
painter.drawLine(0, 0, 200, 200);
painter.drawText(ULpx, txt)
def setShow(self, b):
assert isinstance(b, bool)
self.mShow = b
def setShowTitles(self, b):
assert isinstance(b, bool)
self.mShowTitles = b