From 8531534f9ec77112f054a6905405daf0d68379eb Mon Sep 17 00:00:00 2001
From: Benjamin Jakimow <benjamin.jakimow@geo.hu-berlin.de>
Date: Thu, 1 Feb 2018 23:32:54 +0100
Subject: [PATCH] added cursorlocationvalue.py fixed map rendering error:
 changes in mapview & sensor specific render settings will be applied also on
 non-visible QgsMapCanvases

---
 timeseriesviewer/cursorlocationvalue.py | 597 ++++++++++++++++++++++++
 timeseriesviewer/mapcanvas.py           |  67 ++-
 timeseriesviewer/mapvisualization.py    |  10 +-
 timeseriesviewer/sandbox.py             |  16 +-
 4 files changed, 654 insertions(+), 36 deletions(-)
 create mode 100644 timeseriesviewer/cursorlocationvalue.py

diff --git a/timeseriesviewer/cursorlocationvalue.py b/timeseriesviewer/cursorlocationvalue.py
new file mode 100644
index 00000000..ea633ea3
--- /dev/null
+++ b/timeseriesviewer/cursorlocationvalue.py
@@ -0,0 +1,597 @@
+# -*- coding: utf-8 -*-
+# noinspection PyPep8Naming
+"""
+***************************************************************************
+    cursorlocationvalue.py
+    ---------------------
+    Date                 : August 2017
+    Copyright            : (C) 2017 by Benjamin Jakimow
+    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.                                   *
+*                                                                         *
+***************************************************************************
+"""
+from __future__ import absolute_import, unicode_literals
+
+import os, collections
+
+import numpy as np
+from qgis.core import *
+from qgis.gui import *
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+
+from timeseriesviewer.utils import loadUI, SpatialExtent, SpatialPoint
+from timeseriesviewer.trees import *
+
+
+class LoadWorker(QObject):
+    sigValueLoaded = pyqtSignal(str, dict)
+    sigLoadingStarted = pyqtSignal(int)
+    sigLoadingFinished = pyqtSignal()
+
+    def __init__(self, parent=None):
+        super(LoadWorker, self).__init__(parent)
+
+    def doWork(self, theUris, thePointWkt, theCrsDefinition):
+
+        spatialPoint = QgsGeometry.fromWkt(thePointWkt)
+        assert spatialPoint.wkbType() == QgsWKBTypes.Point
+
+
+        crs = QgsCoordinateReferenceSystem(theCrsDefinition)
+        assert isinstance(crs, QgsCoordinateReferenceSystem)
+
+        if len(theUris) > 0:
+            self.sigLoadingStarted.emit(len(theUris))
+
+            for uri in theUris:
+                values = CursorLocationValues.fromDataSource(spatialPoint, uri)
+
+                #values might be expressed as dict or list
+                self.sigValueLoaded.emit(uri, values)
+
+            self.sigLoadingFinished.emit()
+
+
+
+
+
+class SourceValueSet(object):
+    def __init__(self, source, crs, geoCoordinate):
+        assert isinstance(geoCoordinate, QgsPoint)
+        assert isinstance(crs, QgsCoordinateReferenceSystem)
+        self.source = source
+        self.point = geoCoordinate
+        self.wktCrs = crs.toWkt()
+
+    def baseName(self):
+        return os.path.basename(self.source)
+
+    def crs(self):
+        return QgsCoordinateReferenceSystem(self.wktCrs)
+
+class RasterValueSet(SourceValueSet):
+
+    class BandInfo(object):
+        def __init__(self, bandIndex, bandValue, bandName):
+            assert bandIndex >= 0
+            if bandValue is not None:
+                assert type(bandValue) in [float, int]
+            if bandName is not None:
+                assert type(bandName) in [str, unicode]
+
+            self.bandIndex = bandIndex
+            self.bandValue = bandValue
+            self.bandName = bandName
+
+
+    def __init__(self, source, crs, geoCoordinate, pxPosition):
+        assert isinstance(pxPosition, QPoint)
+        super(RasterValueSet, self).__init__(source, crs, geoCoordinate)
+        self.pxPosition = pxPosition
+        self.noDataValue = None
+        self.bandValues = []
+
+class VectorValueSet(SourceValueSet):
+    class FeatureInfo(object):
+        def __init__(self, fid):
+            assert isinstance(fid, int)
+            self.fid = fid
+            self.attributes = collections.OrderedDict()
+
+    def __init__(self, source, geoCoordinate, crs):
+        super(VectorValueSet, self).__init__(source, geoCoordinate, crs)
+        self.features = []
+
+    def addFeatureInfo(self, featureInfo):
+        assert isinstance(featureInfo, VectorValueSet.FeatureInfo)
+        self.features.append(featureInfo)
+
+
+class CursorLocationInfoModel(TreeModel):
+
+    ALWAYS_EXPAND = 'always'
+    NEVER_EXPAND = 'never'
+    REMAINDER = 'reminder'
+
+    def __init__(self, parent=None):
+        super(CursorLocationInfoModel, self).__init__(parent)
+
+        self.mColumnNames = ['Band/Field','Value','Description']
+        self.mExpandedNodeRemainder = {}
+        self.mNodeExpansion = CursorLocationInfoModel.REMAINDER
+
+    def setNodeExpansion(self, type):
+
+        assert type in [CursorLocationInfoModel.ALWAYS_EXPAND,
+                        CursorLocationInfoModel.NEVER_EXPAND,
+                        CursorLocationInfoModel.REMAINDER]
+        self.mNodeExpansion = type
+
+
+    def setExpandedNodeRemainder(self, node=None):
+        treeView = self.mTreeView
+        assert isinstance(treeView, QTreeView)
+        if node is None:
+            for n in self.mRootNode.childNodes():
+                self.setExpandedNodeRemainder(node = n)
+        else:
+            self.mExpandedNodeRemainder[self.weakNodeId(node)] = self.mTreeView.isExpanded(self.node2idx(node))
+            for n in node.childNodes():
+                self.setExpandedNodeRemainder(node = n)
+
+
+    def weakNodeId(self, node):
+        assert isinstance(node, TreeNode)
+        n = node.name()
+        while node.parentNode() != self.mRootNode:
+            node = node.parentNode()
+            n += '{}:{}'.format(node.name(), n)
+        return n
+
+
+
+    def flags(self, index):
+
+        return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
+
+    def addSourceValues(self, sourceValueSet):
+        if not isinstance(sourceValueSet, SourceValueSet):
+            return
+
+        #get-or-create node
+        def gocn(root, name):
+            assert isinstance(root, TreeNode)
+            n = TreeNode(root, name)
+            weakId = self.weakNodeId(n)
+
+
+            expand = False
+            if self.mNodeExpansion == CursorLocationInfoModel.REMAINDER:
+                expand = self.mExpandedNodeRemainder.get(weakId, False)
+            elif self.mNodeExpansion == CursorLocationInfoModel.NEVER_EXPAND:
+                expand = False
+            elif self.mNodeExpansion == CursorLocationInfoModel.ALWAYS_EXPAND:
+                expand = True
+
+            self.mTreeView.setExpanded(self.node2idx(n), expand)
+            return n
+
+        bn = os.path.basename(sourceValueSet.source)
+
+        if isinstance(sourceValueSet, RasterValueSet):
+            root = gocn(self.mRootNode, name=bn)
+            self.setColumnSpan(root, True)
+            root.setIcon(QIcon(':/enmapbox/icons/mIconRasterLayer.png'))
+
+            #add subnodes
+            n = gocn(root, 'Pixel')
+            n.setValues('{},{}'.format(sourceValueSet.pxPosition.x(), sourceValueSet.pxPosition.y()))
+
+            for bv in sourceValueSet.bandValues:
+                assert isinstance(bv, RasterValueSet.BandInfo)
+                n = gocn(root, 'Band {}'.format(bv.bandIndex+1))
+                n.setToolTip('Band {} {}'.format(bv.bandIndex+1, bv.bandName).strip())
+                n.setValues([bv.bandValue, bv.bandName])
+
+        if isinstance(sourceValueSet, VectorValueSet):
+            if len(sourceValueSet.features) == 0:
+                return
+            root = gocn(self.mRootNode, name=bn)
+            self.setColumnSpan(root, True)
+            refFeature = sourceValueSet.features[0]
+            assert isinstance(refFeature, QgsFeature)
+            typeName = refFeature.geometry().geometry().wktTypeStr().lower()
+            if 'polygon' in typeName: path = ':/enmapbox/icons/mIconPolygonLayer.png'
+            if 'line' in typeName: path = ':/enmapbox/icons/mIconLineLayer.png'
+            if 'point' in typeName: path = ':/enmapbox/icons/mIconLineLayer.png'
+            root.setIcon(QIcon(path))
+
+            for field in refFeature.fields():
+                assert isinstance(field, QgsField)
+
+                fieldNode = gocn(root, name=field.name())
+
+                for i, feature in enumerate(sourceValueSet.features):
+                    assert isinstance(feature, QgsFeature)
+                    nf = gocn(fieldNode, name='{}'.format(feature.id()))
+                    nf.setValues([feature.attribute(field.name()), field.typeName()])
+                    nf.setToolTip('Value of feature "{}" in field with name "{}"'.format(feature.id(), field.name()))
+
+        s = ""
+
+    def clear(self):
+        self.mRootNode.removeChildNodes(0, self.mRootNode.childCount())
+
+
+class ComboBoxOption(object):
+    def __init__(self, value, name=None, tooltip=None, icon=None):
+        self.value = value
+        self.name = str(value) if name is None else str(name)
+        self.tooltip = tooltip
+        self.icon = icon
+
+LUT_GEOMETRY_ICONS = {}
+
+RASTERBANDS = [
+    ComboBoxOption('VISIBLE', 'RGB', 'Visible bands only.'),
+    ComboBoxOption('ALL', 'All','All raster bands.'),
+
+]
+
+LAYERMODES = [
+    ComboBoxOption('ALL_LAYERS', 'All layers', 'Show values of all map layers.'),
+    ComboBoxOption('TOP_LAYER', 'Top layer', 'Show values of the top-most map layer only.')
+    ]
+
+LAYERTYPES = [
+    ComboBoxOption('ALL', 'Raster and Vector', 'Show values of both, raster and vector layers.'),
+    ComboBoxOption('VECTOR', 'Vector only', 'Show values of vector layers only.'),
+    ComboBoxOption('RASTER', 'Raster only', 'Show values of raster layers only.')
+    ]
+
+class ComboBoxOptionModel(QAbstractListModel):
+
+    def __init__(self, options, parent=None, ):
+        super(ComboBoxOptionModel, self).__init__(parent)
+        assert isinstance(options, list)
+
+        for o in options:
+            assert isinstance(o, ComboBoxOption)
+
+        self.mOptions = options
+
+    def rowCount(self, parent=None, *args, **kwargs):
+        return len(self.mOptions)
+
+    def columnCount(self, QModelIndex_parent=None, *args, **kwargs):
+        return 1
+
+
+
+    def index2option(self, index):
+
+        if isinstance(index, QModelIndex) and index.isValid():
+            return self.mOptions[index.row()]
+        elif isinstance(index, int):
+            return self.mOptions[index]
+        return None
+
+    def option2index(self, option):
+        assert option in self.mOptions
+        return self.mOptions.index(option)
+
+    def data(self, index, role=Qt.DisplayRole):
+        if not index.isValid():
+            return None
+
+        option = self.index2option(index)
+        assert isinstance(option, ComboBoxOption)
+        value = None
+        if role == Qt.DisplayRole:
+            value = option.name
+        if role == Qt.ToolTipRole:
+            value = option.tooltip
+        if role == Qt.DecorationRole:
+            value = option.icon
+        if role == Qt.UserRole:
+            value = option
+        return value
+
+
+class CursorLocationInfoDock(QDockWidget,
+                             loadUI('cursorlocationinfodock.ui')):
+
+    sigLocationRequest = pyqtSignal()
+    sigCursorLocationInfoAdded = pyqtSignal()
+
+    def __init__(self, parent=None):
+        """Constructor."""
+        QWidget.__init__(self, parent)
+        #super(CursorLocationValueWidget, self).__init__(parent)
+        # Set up the user interface from Designer.
+        # After setupUI you can access any designer object by doing
+        # self.<objectname>, and you can use autoconnect slots - see
+        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
+        # #widgets-and-dialogs-with-auto-connect
+        self.setupUi(self)
+
+        self.mMaxPoints = 1
+        self.mLocationHistory = []
+
+        self.mCrs = None
+        self.mCanvases = []
+
+        self.btnCrs.crsChanged.connect(self.setCrs)
+        self.btnCrs.setCrs(QgsCoordinateReferenceSystem())
+
+
+
+        self.mLocationInfoModel = CursorLocationInfoModel(parent=self.treeView)
+        self.treeView.setModel(self.mLocationInfoModel)
+
+        self.mLayerModeModel = ComboBoxOptionModel(LAYERMODES, parent=self)
+        self.mLayerTypeModel = ComboBoxOptionModel(LAYERTYPES, parent=self)
+        self.mRasterBandsModel = ComboBoxOptionModel(RASTERBANDS, parent=self)
+
+        self.cbLayerModes.setModel(self.mLayerModeModel)
+        self.cbLayerTypes.setModel(self.mLayerTypeModel)
+        self.cbRasterBands.setModel(self.mRasterBandsModel)
+        self.actionRequestCursorLocation.triggered.connect(self.sigLocationRequest)
+        self.actionReload.triggered.connect(self.reloadCursorLocation)
+
+        self.btnActivateMapTool.setDefaultAction(self.actionRequestCursorLocation)
+        self.btnReload.setDefaultAction(self.actionReload)
+
+
+        self.actionAllRasterBands.triggered.connect(lambda : self.btnRasterBands.setDefaultAction(self.actionAllRasterBands))
+        self.actionVisibleRasterBands.triggered.connect(lambda : self.btnRasterBands.setDefaultAction(self.actionVisibleRasterBands))
+
+
+    def options(self):
+
+
+
+        layerType = self.mLayerTypeModel.index2option(self.cbLayerTypes.currentIndex()).value
+        layerMode = self.mLayerModeModel.index2option(self.cbLayerModes.currentIndex()).value
+        rasterBands = self.mRasterBandsModel.index2option(self.cbRasterBands.currentIndex()).value
+
+        return (layerMode, layerType, rasterBands)
+
+    def loadCursorLocation(self, point, canvas):
+
+
+        assert isinstance(canvas, QgsMapCanvas)
+
+        crs = canvas.mapSettings().destinationCrs()
+        self.setCursorLocation(crs, point)
+        self.setCanvas(canvas)
+        self.reloadCursorLocation()
+
+
+    def reloadCursorLocation(self):
+
+        crsInfo, ptInfo = self.cursorLocation()
+
+        if ptInfo is None or len(self.mCanvases) == 0:
+            return
+
+        mode, type, rasterbands = self.options()
+
+        def layerFilter(canvas):
+            assert isinstance(canvas, QgsMapCanvas)
+            lyrs = canvas.layers()
+            if type == 'VECTOR':
+                lyrs = [l for l in lyrs if isinstance(l, QgsVectorLayer)]
+            if type == 'RASTER':
+                lyrs = [l for l in lyrs if isinstance(l, QgsRasterLayer)]
+
+            if len(lyrs) > 0 and mode == 'TOP_LAYER':
+                lyrs = [lyrs[0]]
+            return lyrs
+
+        lyrs = []
+        for c in self.mCanvases:
+            lyrs.extend(layerFilter(c))
+
+        #convert location of interest into WGS-84 GCS
+        crsWorld = QgsCoordinateReferenceSystem('EPSG:4326')
+
+
+
+        info2World = QgsCoordinateTransform(crsInfo, crsWorld)
+        pointWorld = info2World.transform(ptInfo)
+
+        self.mLocationInfoModel.setExpandedNodeRemainder()
+
+        self.mLocationInfoModel.clear()
+
+        for l in lyrs:
+            assert isinstance(l, QgsMapLayer)
+            lyr2World = QgsCoordinateTransform(l.crs(), crsWorld)
+            world2lyr = QgsCoordinateTransform(crsWorld, l.crs())
+
+            #check in GCS WGS-84 if the point-of-interest intersects with layer
+            lyrExt = lyr2World.transformBoundingBox(l.extent())
+            assert isinstance(lyrExt, QgsRectangle)
+            if not lyrExt.contains(pointWorld):
+                continue
+
+            #transform relquested location into layer CRS coordinates
+            pointLyr = world2lyr.transform(pointWorld)
+
+            from enmapbox.gui.utils import geo2px
+            if isinstance(l, QgsRasterLayer):
+                renderer = l.renderer()
+                ds = gdal.Open(l.source())
+                if ds.RasterCount == 0:
+                    continue
+                    
+                if isinstance(renderer, QgsRasterRenderer) and isinstance(ds, gdal.Dataset):
+                    #transform geo into pixel coodinates
+                    px = geo2px(pointLyr, ds.GetGeoTransform())
+                    if px.x() >= 0 and px.x() < ds.RasterXSize and \
+                       px.y() >= 0 and px.y() < ds.RasterYSize:
+
+                        v = RasterValueSet(l.source(), crsInfo, ptInfo, px)
+
+                        # !Note: b is not zero-based -> 1st band means b == 1
+                        if rasterbands == 'VISIBLE':
+                            bandNumbers = renderer.usesBands()
+                        elif rasterbands == 'ALL':
+                            bandNumbers = range(1, ds.RasterCount + 1)
+                        else:
+                            bandNumbers = [0]
+
+                        for i, b in enumerate(bandNumbers):
+
+                            band = ds.GetRasterBand(b)
+                            assert isinstance(band, gdal.Band)
+                            if i == 0:
+                                v.noDataValue = band.GetNoDataValue()
+
+                            value = band.ReadAsArray(px.x(), px.y(), 1,1)
+                            if value is None:
+                                s =""
+                            value = np.asscalar(value.flatten()[0])
+                            bandInfo = RasterValueSet.BandInfo(b-1, value, band.GetDescription())
+                            v.bandValues.append(bandInfo)
+
+                        self.mLocationInfoModel.addSourceValues(v)
+
+            if isinstance(l, QgsVectorLayer):
+                #searchRect = QgsRectangle(pt, pt)
+
+                #searchRadius = QgsTolerance.toleranceInMapUnits(1, l, self.mCanvas.mapRenderer(), QgsTolerance.Pixels)
+                searchRadius = QgsTolerance.toleranceInMapUnits(1, l, self.mCanvases[0].mapSettings(), QgsTolerance.Pixels)
+                #searchRadius = QgsTolerance.defaultTolerance(l, self.mCanvas.mapSettings())
+                #searchRadius = QgsTolerance.toleranceInProjectUnits(1, self.mCanvas.mapRenderer(), QgsTolerance.Pixels)
+                searchRect = QgsRectangle()
+                searchRect.setXMinimum(pointLyr.x() - searchRadius);
+                searchRect.setXMaximum(pointLyr.x() + searchRadius);
+                searchRect.setYMinimum(pointLyr.y() - searchRadius);
+                searchRect.setYMaximum(pointLyr.y() + searchRadius);
+
+                flags = QgsFeatureRequest.ExactIntersect
+                features = l.getFeatures(QgsFeatureRequest() \
+                                         .setFilterRect(searchRect) \
+                                         .setFlags(flags))
+                feature = QgsFeature()
+                s = VectorValueSet(l.source(), crsInfo, pointLyr)
+                while features.nextFeature(feature):
+                    s.features.append(QgsFeature(feature))
+
+                self.mLocationInfoModel.addSourceValues(s)
+                s = ""
+
+                pass
+
+    def setCursorLocation(self, crs, point):
+        """
+        :param crs:
+        :param point:
+        :return:
+        """
+        assert isinstance(point, QgsPoint)
+        assert isinstance(crs, QgsCoordinateReferenceSystem)
+        self.mLocationHistory.insert(0, (crs, point))
+        if len(self.mLocationHistory) > self.mMaxPoints:
+            del self.mLocationHistory[self.mMaxPoints:]
+
+        if self.mCrs is None:
+            self.setCrs(crs)
+
+        self.setCursorLocationInfo()
+
+
+    def setCursorLocationInfo(self):
+        # transform this point to targeted CRS
+        crs, pt = self.cursorLocation()
+        if isinstance(pt, QgsPoint):
+            if crs != self.mCrs:
+                trans = QgsCoordinateTransform(crs, self.mCrs)
+                pt = trans.transform(pt)
+
+            self.tbX.setText('{}'.format(pt.x()))
+            self.tbY.setText('{}'.format(pt.y()))
+
+    def setCanvas(self,  mapCanvas):
+        self.setCanvases([mapCanvas])
+
+    def setCanvases(self, mapCanvases):
+        assert isinstance(mapCanvases, list)
+        for c in mapCanvases:
+            assert isinstance(c, QgsMapCanvas)
+
+        if len(mapCanvases) == 0:
+            self.setCrs(None)
+        else:
+            setNew = True
+            for c in mapCanvases:
+                if c in self.mCanvases:
+                    setNew = False
+            if setNew:
+                self.setCrs(mapCanvases[0].mapSettings().destinationCrs())
+        self.mCanvases = mapCanvases
+
+    def setCrs(self, crs):
+        """
+        Set the coordinate reference system in which coordinates are shown
+        :param crs:
+        :return:
+        """
+        assert isinstance(crs, QgsCoordinateReferenceSystem)
+        if crs != self.mCrs:
+            self.mCrs = crs
+            self.btnCrs.setCrs(crs)
+        self.setCursorLocationInfo()
+
+
+    def cursorLocation(self):
+        """
+        Returns the last location that was set.
+        """
+        if len(self.mLocationHistory) > 0:
+            return self.mLocationHistory[0]
+        else:
+            return None, None
+
+
+
+class Resulthandler(QObject):
+
+    def __init__(self):
+        super(Resulthandler, self).__init__()
+
+    def onResult(self, *args):
+        print(args)
+
+
+R = Resulthandler()
+if __name__ == '__main__':
+    from enmapbox.gui.utils import initQgisApplication
+    qgsApp = initQgisApplication()
+
+    from enmapboxtestdata import enmap, landcover
+
+    canvas = QgsMapCanvas()
+    lyr = QgsRasterLayer(enmap)
+    shp = QgsVectorLayer(landcover, 'lc', 'ogr')
+    QgsMapLayerRegistry.instance().addMapLayers([lyr,shp])
+    canvas.setLayerSet([QgsMapCanvasLayer(shp), QgsMapCanvasLayer(lyr)])
+    canvas.setDestinationCrs(lyr.crs())
+    canvas.setExtent(lyr.extent())
+    canvas.show()
+
+    d = CursorLocationInfoDock()
+    d.show()
+    d.loadCursorLocation(lyr.extent().center(), canvas)
+    pass
+
+    qgsApp.exec_()
\ No newline at end of file
diff --git a/timeseriesviewer/mapcanvas.py b/timeseriesviewer/mapcanvas.py
index cc0d6b8a..e044c397 100644
--- a/timeseriesviewer/mapcanvas.py
+++ b/timeseriesviewer/mapcanvas.py
@@ -32,7 +32,6 @@ from timeseriesviewer import SETTINGS
 from timeseriesviewer.utils import *
 
 
-
 class MapTools(object):
     """
     Static class to support handling of nQgsMapTools.
@@ -229,18 +228,25 @@ class MapLayerInfo(object):
     A minimum description of a QgsMapLayer source.
     """
 
-    def __init__(self, mapLayer, isVisible, provider='gdal'):
+    def __init__(self, srcOrMapLayer, isVisible, provider='gdal', renderer=None):
 
         self.mSrc = ''
         self.mLayer = None
-        self.mProvider = provider
-
-        if isinstance(mapLayer, QgsMapLayer):
-            self.mSrc = mapLayer.source()
-            self.mProvider = mapLayer.providerType()
-            self.mLayer = mapLayer
+        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.rendererV2()
+            elif isinstance(srcOrMapLayer, QgsRasterLayer):
+                self.mRenderer = srcOrMapLayer.renderer()
         else:
-            self.mSrc = mapLayer
+            self.mSrc = srcOrMapLayer
+            assert provider in ['ogr','gdal']
+            self.mProvider = provider
 
 
         self.mIsVisible = isVisible
@@ -257,6 +263,16 @@ class MapLayerInfo(object):
         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, QgsFeatureRendererV2) or \
+           self.mProvider == 'gdal' and isinstance(renderer, QgsRasterRenderer):
+            self.mRenderer = renderer
+            if self.isInitialized():
+                copyRenderer(self.mRenderer, self.mLayer)
+                #self.mLayer.repaintRequested.emit()
 
     def setIsVisible(self, b):
         self.mIsVisible = b
@@ -279,6 +295,7 @@ class MapLayerInfo(object):
         if not self.isInitialized():
             return None
         ref = QgsMapLayerRegistry.instance().mapLayer(self.mLayer.layerId())
+
         return isinstance(ref, QgsMapLayer)
 
 
@@ -294,6 +311,7 @@ class MapCanvasLayerModel(QAbstractTableModel):
         self.mColumnNames = ['layerID', 'isVisible', '']
         self.mLayerInfos = []
 
+
     def __len__(self):
         return len(self.mLayerInfos)
 
@@ -308,14 +326,13 @@ class MapCanvasLayerModel(QAbstractTableModel):
         return info
 
     def setRenderer(self, renderer):
-        from timeseriesviewer.utils import copyRenderer
-        #do we need to set a reference on the renderer????
-        return [copyRenderer(renderer, li.mLayer) for li in self.mLayerInfos if isinstance(li.mLayer, QgsMapLayer)]
-
+        for li in self.mLayerInfos:
+            assert isinstance(li, MapLayerInfo)
+            li.setRenderer(renderer)
 
-    def setVectorLayerSources(self, rasterSources, isVisible=True):
+    def setVectorLayerSources(self, vectorSources, **kwds):
         self.removeLayerInfos(self.vectorLayerInfos())
-        self.insertLayerInfos(0, rasterSources, isVisible=isVisible, provider='ogr')
+        self.insertLayerInfos(0, vectorSources, provider='ogr', **kwds)
 
     def setVectorLayerVisibility(self, b):
         for li in self.vectorLayerInfos():
@@ -326,9 +343,9 @@ class MapCanvasLayerModel(QAbstractTableModel):
             li.setIsVisible(b)
 
 
-    def setRasterLayerSources(self, rasterSources, isVisible=True):
+    def setRasterLayerSources(self, rasterSources, **kwds):
         self.removeLayerInfos(self.rasterLayerInfos())
-        self.addLayerInfos(rasterSources, isVisible=isVisible, provider='gdal')
+        self.addLayerInfos(rasterSources, provider='gdal', **kwds)
 
     def vectorLayerInfos(self):
         return [li for li in self.mLayerInfos if li.mProvider == 'ogr']
@@ -337,14 +354,14 @@ class MapCanvasLayerModel(QAbstractTableModel):
         return [li for li in self.mLayerInfos if li.mProvider == 'gdal']
 
 
-    def addLayerInfo(self, mapLayer, isVisible=True, provider='gdal'):
-        self.addLayerInfos([mapLayer], isVisible=isVisible, provider=provider)
+    def addLayerInfo(self, mapLayer, **kwds):
+        self.addLayerInfos([mapLayer], **kwds)
 
-    def addLayerInfos(self, mapLayers, isVisible=True, provider='gdal'):
-        self.insertLayerInfos(len(self), mapLayers, isVisible=isVisible, provider=provider)
+    def addLayerInfos(self, mapLayers, **kwds):
+        self.insertLayerInfos(len(self), mapLayers, **kwds)
 
-    def insertLayerInfo(self, i, mapLayer, isVisible=True, provider='gdal'):
-        self.insertLayerInfo(i, [mapLayer], isVisible=isVisible, provider=provider)
+    def insertLayerInfo(self, i, mapLayer, **kwds):
+        self.insertLayerInfo(i, [mapLayer], **kwds)
 
     def insertLayerInfos(self, i, mapLayers, isVisible=True, provider='gdal'):
         for mapLayer in mapLayers:
@@ -843,8 +860,8 @@ class MapCanvas(QgsMapCanvas):
     def setRenderer(self, renderer, refresh=True):
 
         success = self.layerModel().setRenderer(renderer)
-        if refresh and any(success):
-            self.refresh()
+        self.setRenderFlag(True)
+        #self.refresh()
 
 
     def setSpatialExtent(self, spatialExtent):
diff --git a/timeseriesviewer/mapvisualization.py b/timeseriesviewer/mapvisualization.py
index b780f100..b3e6da48 100644
--- a/timeseriesviewer/mapvisualization.py
+++ b/timeseriesviewer/mapvisualization.py
@@ -338,17 +338,18 @@ class MapView(QObject):
 
         #w.showSensorName(False)
         w = self.ui.addSensor(sensor)
-        w.sigSensorRendererChanged.connect(self.onSensorRenderingChanged)
+        #w.sigSensorRendererChanged.connect(self.onSensorRenderingChanged)
         self.sensorViews[sensor] = w
         s  =""
 
+    """
     def onSensorRenderingChanged(self, renderer):
         sensorSettings = self.sender()
         assert isinstance(sensorSettings, MapViewSensorSettings)
         for mapCanvas in sensorSettings.mapCanvases():
             mapCanvas.setRenderer(renderer)
             #mapCanvas.refresh()
-
+    """
     def getSensorWidget(self, sensor):
         assert type(sensor) is SensorInstrument
         return self.sensorViews[sensor]
@@ -574,7 +575,8 @@ class MapViewSensorSettings(QObject):
         r = self.rasterLayerRenderer()
         for mapCanvas in self.mMapCanvases:
             assert isinstance(mapCanvas, MapCanvas)
-            mapCanvas.setRenderer(r)
+            mapCanvas.layerModel().setRenderer(r)
+            mapCanvas.refresh()
 
     def onClipboardChange(self):
         utils = TsvMimeDataUtils(QApplication.clipboard().mimeData())
@@ -1365,7 +1367,7 @@ class DateViewCollection(QObject):
         for tsdv in self.views:
             tsdv.ui.setUpdatesEnabled(True)
 
-        mapView.sigSensorRendererChanged.connect(lambda *args : self.setRasterRenderer(mapView, *args))
+        #mapView.sigSensorRendererChanged.connect(lambda *args : self.setRasterRenderer(mapView, *args))
         mapView.sigMapViewVisibility.connect(lambda: self.sigResizeRequired.emit())
         mapView.sigShowProfiles.connect(self.sigShowProfiles.emit)
         w.setUpdatesEnabled(True)
diff --git a/timeseriesviewer/sandbox.py b/timeseriesviewer/sandbox.py
index 2b1c2aad..c0fa3e32 100644
--- a/timeseriesviewer/sandbox.py
+++ b/timeseriesviewer/sandbox.py
@@ -287,18 +287,20 @@ def sandboxTestdata():
     S.run()
 
     S.spatialTemporalVis.MVC.createMapView()
-    #import example.Images
-    #searchDir = jp(DIR_EXAMPLES, 'Images')
-    #imgs = file_search(searchDir, '*.tif', recursive=True)#[0:1]  # [0:5]
+    S.spatialTemporalVis.MVC.createMapView()
+
     import example.Images
+    if True:
+        S.loadExampleTimeSeries()
+    else:
+        imgs = [example.Images.Img_2014_08_11_LC82270652014223LGN00_BOA,
+                example.Images.re_2014_08_26]
 
-    imgs = [example.Images.Img_2014_08_11_LC82270652014223LGN00_BOA,
-            example.Images.re_2014_08_26]
 
-    from example import exampleEvents
 
-    S.addTimeSeriesImages(imgs)
+        S.addTimeSeriesImages(imgs)
 
+    from example import exampleEvents
     ml  = QgsVectorLayer(exampleEvents, 'labels', 'ogr', True)
     QgsMapLayerRegistry.instance().addMapLayer(ml)
 
-- 
GitLab