Skip to content
Snippets Groups Projects
mapvisualization.py 98.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • class MapView(QObject):
    
        sigRemoveMapView = pyqtSignal(object)
        sigMapViewVisibility = pyqtSignal(bool)
    
        #sigVectorVisibility = pyqtSignal(bool)
        #sigRasterVisibility = pyqtSignal(bool)
    
        sigTitleChanged = pyqtSignal(str)
    
        sigSensorRendererChanged = pyqtSignal(SensorInstrument, QgsRasterRenderer)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
        sigCrosshairStyleChanged = pyqtSignal(CrosshairStyle)
        sigShowCrosshair = pyqtSignal(bool)
        sigVectorLayerChanged = pyqtSignal()
    
    
        sigShowProfiles = pyqtSignal(SpatialPoint, MapCanvas, str)
    
        def __init__(self, mapViewCollectionDock, name='Map View', recommended_bands=None, parent=None):
    
            assert isinstance(mapViewCollectionDock, MapViewCollectionDock)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
            self.ui = MapViewUI(mapViewCollectionDock.stackedWidget)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.ui.show()
            self.ui.cbQgsVectorLayer.setFilters(QgsMapLayerProxyModel.VectorLayer)
    
            self.ui.cbQgsVectorLayer.layerChanged.connect(self.setVectorLayer)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.ui.tbName.textChanged.connect(self.sigTitleChanged)
            from timeseriesviewer.crosshair import getCrosshairStyle
            self.ui.actionSetCrosshairStyle.triggered.connect(
                lambda : self.setCrosshairStyle(getCrosshairStyle(
                    parent=self.ui,
                    crosshairStyle=self.mCrosshairStyle))
            )
    
    
            self.mapViewCollection = mapViewCollectionDock
    
            self.mSensorViews = collections.OrderedDict()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.mCrosshairStyle = CrosshairStyle()
            self.mShowCrosshair = True
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.mIsVisible = True
    
    
            self.ui.actionToggleVectorVisibility.toggled.connect(self.setVectorVisibility)
            self.ui.actionToggleRasterVisibility.toggled.connect(self.setRasterVisibility)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.ui.actionToggleCrosshairVisibility.toggled.connect(self.setShowCrosshair)
    
    benjamin.jakimow@geo.hu-berlin.de's avatar
    benjamin.jakimow@geo.hu-berlin.de committed
            self.ui.actionToggleMapViewHidden.toggled.connect(lambda b: self.setIsVisible(not b))
    
    benjamin.jakimow@geo.hu-berlin.de's avatar
    benjamin.jakimow@geo.hu-berlin.de committed
            self.ui.actionToggleVectorVisibility.setChecked(False)
    
            self.ui.actionToggleRasterVisibility.setChecked(True)
    
    
            self.ui.actionSetVectorStyle.triggered.connect(self.setVectorLayerStyle)
    
    
            for sensor in self.mapViewCollection.TS.Sensors:
                self.addSensor(sensor)
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.setTitle(name)
            #forward actions with reference to this band view
    
        def dummy(self, *args):
            print(args)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def setIsVisible(self, b):
            assert isinstance(b, bool)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    benjamin.jakimow@geo.hu-berlin.de's avatar
    benjamin.jakimow@geo.hu-berlin.de committed
            for mapCanvas in self.mapCanvases():
                assert isinstance(mapCanvas, MapCanvas)
    
    benjamin.jakimow@geo.hu-berlin.de's avatar
    benjamin.jakimow@geo.hu-berlin.de committed
                if not mapCanvas.isVisible() == b:
    
    benjamin.jakimow@geo.hu-berlin.de's avatar
    benjamin.jakimow@geo.hu-berlin.de committed
                    mapCanvas.setVisible(b)
    
            if self.ui.actionToggleMapViewHidden.isChecked() == b:
                self.ui.actionToggleMapViewHidden.setChecked(not b)
    
    
    benjamin.jakimow@geo.hu-berlin.de's avatar
    benjamin.jakimow@geo.hu-berlin.de committed
            if changed:
                self.sigMapViewVisibility.emit(b)
    
    
        def isVisible(self):
    
            return not self.ui.actionToggleMapViewHidden.isChecked()
    
            for sensor, sensorView in self.mSensorViews.items():
    
                m.extend(sensorView.mapCanvases())
            return m
    
    
    
    
    
        def setVectorLayerStyle(self, *args):
            if isinstance(self.mVectorLayer, QgsVectorLayer):
                d = QgsRendererPropertiesDialog(self.mVectorLayer, QgsStyle.defaultStyle())
    
    
                mc = self.mapCanvases()
                if len(mc) > 0:
                    d.setMapCanvas(mc[0])
    
                s = ""
    
        def vectorLayerRenderer(self):
            if isinstance(self.mVectorLayer, QgsVectorLayer):
    
        def setVectorLayerRenderer(self, renderer):
    
            if isinstance(renderer, QgsFeatureRenderer) and \
    
                isinstance(self.mVectorLayer, QgsVectorLayer):
                self.mVectorLayer.setRendererV2(renderer)
    
    
            if isinstance(lyr, QgsVectorLayer) and self.ui.gbVectorRendering.isChecked():
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
                #add vector layer
                self.mVectorLayer = lyr
                self.mVectorLayer.rendererChanged.connect(self.sigVectorLayerChanged)
    
                for mapCanvas in self.mapCanvases():
                    assert isinstance(mapCanvas, MapCanvas)
    
                    mapCanvas.layerModel().setVectorLayerSources([self.mVectorLayer])
                    #mapCanvas.setLayers([l for l in mapCanvas.layers() if isinstance(l, QgsRasterLayer)])
                    #mapCanvas.setLazyVectorSources([lyr])
    
                #remove vector layers
                self.mVectorLayer = None
                for mapCanvas in self.mapCanvases():
    
                    mapCanvas.layerModel().setVectorLayerSources([])
                    #mapCanvas.setLayers([l for l in mapCanvas.mLayers if not isinstance(l, QgsVectorLayer)])
                    mapCanvas.refresh()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.sigVectorLayerChanged.emit()
    
            for sensorView in self.mSensorViews.values():
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            old = self.title()
            if old != title:
                self.ui.tbName.setText(title)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            return self.ui.tbName.text()
    
        def refreshMapView(self, sensor=None):
    
            if isinstance(sensor, SensorInstrument):
                sensorSettings = [self.mSensorViews[sensor]]
            else:
                #update all sensors
                sensorSettings = self.mSensorViews.values()
    
            for renderSetting in sensorSettings:
                assert isinstance(renderSetting, MapViewRenderSettings)
                renderSetting.applyStyle()
    
    
            #for mapCanvas in self.mapCanvases():
            #    assert isinstance(mapCanvas, MapCanvas)
            #    mapCanvas.refresh()
    
            if isinstance(crosshairStyle, CrosshairStyle):
                old = self.mCrosshairStyle
                self.mCrosshairStyle = crosshairStyle
                if old != self.mCrosshairStyle:
                    self.sigCrosshairStyleChanged.emit(self.mCrosshairStyle)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
        def setHighlighted(self, b=True, timeout=1000):
            styleOn = """.MapCanvas {
                        border: 4px solid red;
                        border-radius: 4px;
                    }"""
            styleOff = """"""
            if b is True:
                for mapCanvas in self.mapCanvases():
                    mapCanvas.setStyleSheet(styleOn)
                if timeout > 0:
                    QTimer.singleShot(timeout, lambda : self.setHighlighted(False))
            else:
                for mapCanvas in self.mapCanvases():
                    mapCanvas.setStyleSheet(styleOff)
    
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            assert isinstance(b, bool)
            self.mShowCrosshair = b
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def showCrosshair(self):
            return self.mShowCrosshair and self.mCrosshairStyle is not None
    
    
    
        def rasterVisibility(self):
    
    benjamin.jakimow@geo.hu-berlin.de's avatar
    benjamin.jakimow@geo.hu-berlin.de committed
            return self.ui.actionToggleRasterVisibility.isChecked()
    
    
        def vectorVisibility(self):
    
    benjamin.jakimow@geo.hu-berlin.de's avatar
    benjamin.jakimow@geo.hu-berlin.de committed
            return self.ui.actionToggleVectorVisibility.isChecked()
    
    
        def setRasterVisibility(self, b):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            assert isinstance(b, bool)
    
    
            self.mRastersVisible = b
            self.ui.actionToggleRasterVisibility.setChecked(b)
    
            for mapCanvas in self.mapCanvases():
                assert isinstance(mapCanvas, MapCanvas)
                mapCanvas.layerModel().setRasterLayerVisibility(b)
                mapCanvas.refresh()
    
    
    
        def setVectorVisibility(self, b):
            assert isinstance(b, bool)
    
            self.mVectorsVisible = b
            self.ui.actionToggleVectorVisibility.setChecked(b)
    
            for mapCanvas in self.mapCanvases():
                assert isinstance(mapCanvas, MapCanvas)
                mapCanvas.layerModel().setVectorLayerVisibility(self.mVectorsVisible)
                mapCanvas.refresh()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
            assert sensor in self.mSensorViews.keys()
            self.mSensorViews.pop(sensor)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.ui.removeSensor(sensor)
            return True
    
    
        def hasSensor(self, sensor):
            assert type(sensor) is SensorInstrument
    
            return sensor in self.mSensorViews.keys()
    
        def registerMapCanvas(self, sensor, mapCanvas):
            from timeseriesviewer.mapcanvas import MapCanvas
            assert isinstance(mapCanvas, MapCanvas)
            assert isinstance(sensor, SensorInstrument)
    
    
            mapViewRenderSettings = self.mSensorViews[sensor]
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            assert isinstance(mapViewRenderSettings, MapViewRenderSettings)
    
            mapViewRenderSettings.registerMapCanvas(mapCanvas)
    
            mapCanvas.setRenderer(mapViewRenderSettings.rasterRenderer())
    
            mapCanvas.setRenderer(self.vectorLayerRenderer())
    
            #register non-sensor specific signals for this mpa view
    
            self.sigMapViewVisibility.connect(mapCanvas.refresh)
            self.sigCrosshairStyleChanged.connect(mapCanvas.setCrosshairStyle)
            self.sigShowCrosshair.connect(mapCanvas.setShowCrosshair)
            self.sigVectorLayerChanged.connect(mapCanvas.refresh)
    
    #        self.sigVectorVisibility.connect(mapCanvas.refresh)
    
            if isinstance(sensor, SensorInstrument) and sensor not in self.mSensorViews.keys():
    
                #w.showSensorName(False)
                w = self.ui.addSensor(sensor)
    
                w.sigRendererChanged.connect(lambda s=sensor : self.refreshMapView(sensor=s))
    
                #w.sigSensorRendererChanged.connect(self.onSensorRenderingChanged)
                self.mSensorViews[sensor] = w
                s  =""
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
        def onSensorRenderingChanged(self, renderer):
            sensorSettings = self.sender()
            assert isinstance(sensorSettings, MapViewSensorSettings)
            for mapCanvas in sensorSettings.mapCanvases():
                mapCanvas.setRenderer(renderer)
                #mapCanvas.refresh()
    
        def sensorWidget(self, sensor):
    
            return self.mSensorViews[sensor]
    
    def displayBandNames(provider_or_dataset, bands=None):
        results = None
        if isinstance(provider_or_dataset, QgsRasterLayer):
            return displayBandNames(provider_or_dataset.dataProvider())
        elif isinstance(provider_or_dataset, QgsRasterDataProvider):
            if provider_or_dataset.name() == 'gdal':
                ds = gdal.Open(provider_or_dataset.dataSourceUri())
                results = displayBandNames(ds, bands=bands)
            else:
                # same as in QgsRasterRendererWidget::displayBandName
                results = []
                if bands is None:
                    bands = range(1, provider_or_dataset.bandCount() + 1)
                for band in bands:
                    result = provider_or_dataset.generateBandName(band)
                    colorInterp ='{}'.format(provider_or_dataset.colorInterpretationName(band))
                    if colorInterp != 'Undefined':
                        result += '({})'.format(colorInterp)
                    results.append(result)
    
        elif isinstance(provider_or_dataset, gdal.Dataset):
            results = []
            if bands is None:
                bands = range(1, provider_or_dataset.RasterCount+1)
            for band in bands:
                b = provider_or_dataset.GetRasterBand(band)
                descr = b.GetDescription()
                if len(descr) == 0:
                    descr = 'Band {}'.format(band)
                results.append(descr)
    
        return results
    
    
    class RasterDataProviderMockup(QgsRasterDataProvider):
    
        def __init__(self):
            super(RasterDataProviderMockup, self).__init__('')
    
    
    
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    class MapViewRenderSettings(QgsCollapsibleGroupBox, loadUI('mapviewrendersettings.ui')):
    
    
    
        LUT_RENDERER = {QgsMultiBandColorRenderer:QgsMultiBandColorRendererWidget,
                        QgsSingleBandGrayRenderer:QgsSingleBandGrayRendererWidget,
                        QgsSingleBandPseudoColorRenderer:QgsSingleBandPseudoColorRendererWidget,
                        QgsPalettedRasterRenderer:QgsPalettedRendererWidget}
        LUT_RENDERER[QgsMultiBandColorRenderer]=MultiBandColorRendererWidget
        LUT_RENDERER[QgsSingleBandPseudoColorRenderer]=SingleBandPseudoColorRendererWidget
        LUT_RENDERER[QgsSingleBandGrayRenderer]=SingleBandGrayRendererWidget
    
        LUT_RENDERER[QgsPalettedRasterRenderer] = PalettedRendererWidget
    
        def __init__(self, sensor, parent=None):
            """Constructor."""
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            super(MapViewRenderSettings, 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)
    
            QApplication.clipboard().dataChanged.connect(self.onClipboardChanged)
    
            assert isinstance(sensor, SensorInstrument)
            self.mSensor = sensor
            self.mSensor.sigNameChanged.connect(self.onSensorNameChanged)
            self.setTitle(self.mSensor.name())
    
            from timeseriesviewer.models import OptionListModel, Option
            rasterRendererModel = OptionListModel()
            #rasterRendererModel.addOption(Option(QgsMultiBandColorRendererWidget, name='multibandcolor (QGIS)', mRenderType = QgsMultiBandColorRenderer))
            #rasterRendererModel.addOption(Option(QgsPalettedRendererWidget, name='paletted (QGIS)', mRenderType = QgsPalettedRasterRenderer))
            #rasterRendererModel.addOption(Option(QgsSingleBandGrayRendererWidget, name='singlegray (QGIS)', mRenderType = QgsSingleBandGrayRenderer))
            #rasterRendererModel.addOption(Option(QgsSingleBandPseudoColorRendererWidget, name='singlebandpseudocolor (QGIS)', mRenderType = QgsSingleBandPseudoColorRenderer))
    
    
            rasterRendererModel.addOption(Option(MultiBandColorRendererWidget, name='Multibandcolor', mRenderType=QgsMultiBandColorRenderer))
            rasterRendererModel.addOption(Option(SingleBandGrayRendererWidget, name='Singlegray', mRenderType=QgsSingleBandGrayRenderer))
            rasterRendererModel.addOption(Option(SingleBandPseudoColorRendererWidget, name='Singleband Pseudocolor', mRenderType=QgsSingleBandPseudoColorRenderer))
            rasterRendererModel.addOption(Option(PalettedRendererWidget, name='Paletted', mRenderType=QgsPalettedRasterRenderer))
    
            self.mRasterRendererModel = rasterRendererModel
    
            self.cbRenderType.setModel(self.mRasterRendererModel)
            assert isinstance(self.stackedWidget, QStackedWidget)
    
            self.mMockupCanvas = QgsMapCanvas()
            self.mMockupRasterLayer = QgsRasterLayer(self.mSensor.pathImg)
            self.mMockupCanvas.setLayers([self.mMockupRasterLayer])
            for func in rasterRendererModel.optionValues():
    
                #extent = self.canvas.extent()
                #w = func.create(self.mMockupRasterLayer, self.mMockupRasterLayer.extent())
                w = func(self.mMockupRasterLayer, self.mMockupRasterLayer.extent())
                #w = func(QgsRasterLayer(), QgsRectangle())
    
                w.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred))
                #w.sizeHint = lambda : QSize(300, 50)
                w.setMapCanvas(self.mMockupCanvas)
    
                self.stackedWidget.addWidget(w)
    
    
            self.mMapCanvases = []
    
            self.initActions()
    
        def initActions(self):
    
    
            self.btnPasteStyle.setDefaultAction(self.actionPasteStyle)
            self.btnCopyStyle.setDefaultAction(self.actionCopyStyle)
            self.btnApplyStyle.setDefaultAction(self.actionApplyStyle)
    
            clipboardRenderer = rendererFromXml(QApplication.clipboard().mimeData())
            self.actionPasteStyle.setEnabled(isinstance(clipboardRenderer, QgsRasterRenderer))
            self.actionPasteStyle.triggered.connect(self.pasteStyleFromClipboard)
            self.actionCopyStyle.triggered.connect(self.pasteStyleToClipboard)
    
            self.actionApplyStyle.triggered.connect(self.applyStyle)
    
    
        def mapCanvases(self):
            return self.mMapCanvases[:]
    
        def registerMapCanvas(self, mapCanvas):
    
            assert isinstance(mapCanvas, MapCanvas)
            self.mMapCanvases.append(mapCanvas)
            mapCanvas.sigChangeSVRequest.connect(self.onMapCanvasRendererChangeRequest)
    
    
        def onMapCanvasRendererChangeRequest(self, mapCanvas, renderer):
            self.setRasterRenderer(renderer)
            self.applyStyle()
    
    
        def onSensorNameChanged(self, newName):
    
            self.setTitle(self.mSensor.name())
            self.actionApplyStyle.setToolTip('Apply style to all map view images from "{}"'.format(self.mSensor.name()))
    
    
    
        def currentRenderWidget(self):
            """
            Returns the current QgsRasterRendererWidget
            :return: QgsRasterRendererWidget
            """
            return self.stackedWidget.currentWidget()
    
    
        def setRasterRenderer(self, renderer):
            assert isinstance(renderer, QgsRasterRenderer)
            assert isinstance(self.stackedWidget, QStackedWidget)
    
            self.mMockupRasterLayer.setRenderer(renderer)
    
            #find the widget class that fits
            cls = None
    
            for option in self.mRasterRendererModel:
                if type(renderer) == option.mRenderType:
                    cls = option.value()
                    break
            if cls == None:
                return
    
            widgets = []
            for i in range(self.stackedWidget.count()):
                w = self.stackedWidget.widget(i)
                if isinstance(w, cls):
                    widgets.append(w)
    
            if len(widgets) > 0:
                for w in widgets:
                    assert isinstance(w, QgsRasterRendererWidget)
    
    
                    #w.setRasterLayer(self.mMockupRasterLayer)
                    #w.setFromRenderer(cloneRenderer(renderer))
                    w.setFromRenderer(renderer)
                    #w.doComputations()
    
    
                w = widgets[0]
                self.stackedWidget.setCurrentWidget(w)
    
                self.cbRenderType.setCurrentIndex(self.stackedWidget.currentIndex())
    
    
        def rasterRenderer(self):
    
            return self.stackedWidget.currentWidget().renderer()
    
    
        def apply(self):
    
            mRendererWidget = self.currentRenderWidget()
            mRendererWidget.doComputations()
    
        def onClipboardChanged(self):
            mimeData = QApplication.clipboard().mimeData()
            renderer = rendererFromXml(mimeData)
            b = isinstance(renderer, QgsRasterRenderer)
            #if b == False:
            #    print(mimeData.formats())
            #    s = ""
            self.actionPasteStyle.setEnabled(b)
    
    
    
        def pasteStyleFromClipboard(self):
            mimeData = QApplication.clipboard().mimeData()
            renderer = rendererFromXml(mimeData)
            if isinstance(renderer, QgsRasterRenderer):
                self.setRasterRenderer(renderer)
    
        def pasteStyleToClipboard(self):
            xml = rendererToXml(self.rasterRenderer())
            assert isinstance(xml, QDomDocument)
            md = QMimeData()
            #['application/qgis.style', 'text/plain']
    
            md.setData('application/qgis.style', xml.toByteArray())
            md.setData('text/plain', xml.toByteArray())
            QApplication.clipboard().setMimeData(md)
    
        def applyStyle(self, *args):
    
    
            r = self.rasterRenderer()
    
            for mapCanvas in self.mMapCanvases:
                assert isinstance(mapCanvas, MapCanvas)
                mapCanvas.layerModel().setRenderer(r)
                mapCanvas.refresh()
    
    
    
    
    RENDER_CLASSES = {}
    RENDER_CLASSES['rasterrenderer'] = {
        'singlebandpseudocolor':QgsSingleBandPseudoColorRenderer,
        'singlebandgray': QgsSingleBandGrayRenderer,
        'paletted':QgsPalettedRasterRenderer,
        'multibandcolor': QgsMultiBandColorRenderer,
        'hillshade': QgsHillshadeRenderer
    }
    RENDER_CLASSES['renderer-v2'] = {
        'categorizedSymbol':QgsCategorizedSymbolRenderer,
        'singleSymbol':QgsSingleSymbolRenderer
    }
    
    
    
    def rendererToXml(renderer):
    
        """
        Returns a renderer XML representation
        :param renderer: QgsRasterRender | QgsFeatureRenderer
        :return: QDomDocument
        """
    
        doc = QDomDocument()
    
        if isinstance(renderer, QgsRasterRenderer):
    
            #create a dummy raster layer
            import uuid
            from timeseriesviewer.virtualrasters import write_vsimem, read_vsimem
            xml = """<VRTDataset rasterXSize="1" rasterYSize="1">
                      <GeoTransform>  0.0000000000000000e+00,  1.0000000000000000e+00,  0.0000000000000000e+00,  0.0000000000000000e+00,  0.0000000000000000e+00, -1.0000000000000000e+00</GeoTransform>
                      <VRTRasterBand dataType="Float32" band="1">
                        <Metadata>
                          <MDI key="STATISTICS_MAXIMUM">0</MDI>
                          <MDI key="STATISTICS_MEAN">0</MDI>
                          <MDI key="STATISTICS_MINIMUM">0</MDI>
                          <MDI key="STATISTICS_STDDEV">0</MDI>
                        </Metadata>
                        <Description>Band 1</Description>
                        <Histograms>
                          <HistItem>
                            <HistMin>0</HistMin>
                            <HistMax>0</HistMax>
                            <BucketCount>1</BucketCount>
                            <IncludeOutOfRange>0</IncludeOutOfRange>
                            <Approximate>0</Approximate>
                            <HistCounts>0</HistCounts>
                          </HistItem>
                        </Histograms>
                      </VRTRasterBand>
                    </VRTDataset>
                    """
    
            path = '/vsimem/{}.vrt'.format(uuid.uuid4())
    
            drv = gdal.GetDriverByName('VRT')
            assert isinstance(drv, gdal.Driver)
            write_vsimem(path, xml)
    
            lyr = QgsRasterLayer(path)
    
            assert lyr.isValid()
    
            lyr.setRenderer(renderer.clone())
    
            lyr.exportNamedStyle(doc, err)
            #remove dummy raster layer
            lyr = None
            drv.Delete(path)
    
    
        elif isinstance(renderer, QgsFeatureRenderer):
            #todo: distinguish vector type from requested renderer
            lyr = QgsVectorLayer('Point?crs=epsg:4326&field=id:integer', 'dummy', 'memory')
            lyr.setRenderer(renderer.clone())
    
            lyr.exportNamedStyle(doc, err)
            lyr = None
    
        else:
            raise NotImplementedError()
    
        return doc
    
    
    def rendererFromXml(xml):
        """
        Reads a string `text` and returns the first QgsRasterRenderer or QgsFeatureRenderer (if defined).
        :param text:
        :return:
        """
    
        if isinstance(xml, QMimeData):
            for format in ['application/qgis.style', 'text/plain']:
                if format in xml.formats():
                    dom  = QDomDocument()
                    dom.setContent(xml.data(format))
                    return rendererFromXml(dom)
            return None
    
        elif isinstance(xml, str):
            dom = QDomDocument()
            dom.setContent(xml)
            return rendererFromXml(dom)
    
        assert isinstance(xml, QDomDocument)
        root = xml.documentElement()
        for baseClass, renderClasses in RENDER_CLASSES.items():
            elements = root.elementsByTagName(baseClass)
            if elements.count() > 0:
                elem = elements.item(0).toElement()
                typeName = elem.attributes().namedItem('type').nodeValue()
                if typeName in renderClasses.keys():
                    rClass = renderClasses[typeName]
                    if baseClass == 'rasterrenderer':
    
                        return rClass.create(elem, DUMMY_RASTERINTERFACE)
                    elif baseClass == 'renderer-v2':
                        context = QgsReadWriteContext()
                        return rClass.load(elem, context)
                        #return rClass.create(elem)
                else:
                    print(typeName)
                    s =""
        return None
    
    
    
    
    class DatumViewUI(QFrame, loadUI('timeseriesdatumview.ui')):
    
    benjamin.jakimow@geo.hu-berlin.de's avatar
    benjamin.jakimow@geo.hu-berlin.de committed
        """
        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())
    
    benjamin.jakimow@geo.hu-berlin.de's avatar
    benjamin.jakimow@geo.hu-berlin.de committed
                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())
    
    benjamin.jakimow@geo.hu-berlin.de's avatar
    benjamin.jakimow@geo.hu-berlin.de committed
            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
    
    
    """
    
    
    
    
    class DatumView(QObject):
    
    
        sigRenderProgress = pyqtSignal(int,int)
        sigLoadingStarted = pyqtSignal(MapView, TimeSeriesDatum)
        sigLoadingFinished = pyqtSignal(MapView, TimeSeriesDatum)
        sigVisibilityChanged = pyqtSignal(bool)
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def __init__(self, timeSeriesDatum, stv, parent=None):
    
            assert isinstance(timeSeriesDatum, TimeSeriesDatum)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            assert isinstance(stv, SpatialTemporalVisualization)
    
    
            super(DatumView, self).__init__()
    
    benjamin.jakimow@geo.hu-berlin.de's avatar
    benjamin.jakimow@geo.hu-berlin.de committed
            self.ui = DatumViewUI(parent=parent)
    
            self.showLoading(False)
    
            self.wOffset = self.ui.layout().count()-1
    
            #self.minWidth = 50
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            assert isinstance(stv, SpatialTemporalVisualization)
            self.STV = stv
    
            self.TSD = timeSeriesDatum
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.scrollArea = stv.scrollArea
    
            self.mSensor = self.TSD.sensor
            self.mSensor.sigNameChanged.connect(lambda :self.setColumnInfo())
    
            self.TSD.sigVisibilityChanged.connect(self.setVisibility)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.MVC = stv.MVC
            self.DVC = stv.DVC
    
            self.mMapCanvases = dict()
    
            self.mRenderState = dict()
    
            labelTxt = '{}\n{}'.format(str(self.TSD.date), self.TSD.sensor.name())
            tooltip = '{}'.format(self.TSD.pathImg)
    
        def setVisibility(self, b):
            self.ui.setVisible(b)
            self.sigVisibilityChanged.emit(b)
    
    
        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)
    
    
            canvas = self.mMapCanvases.pop(mapView)
    
            self.ui.layout().removeWidget(canvas)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            #self.adjustBaseMinSize()
    
                for c in self.mMapCanvases.values():
    
    
        def insertMapView(self, mapView):
            assert isinstance(mapView, MapView)
    
            from timeseriesviewer.mapcanvas import MapCanvas
    
            mapCanvas = MapCanvas(self.ui)
    
            mapCanvas.setObjectName('MapCanvas {} {}'.format(mapView.title(), self.TSD.date))
    
            mapCanvas.blockSignals(True)
    
            mapCanvas.setMapView(mapView)
    
            mapCanvas.setTSD(self.TSD)
    
            self.registerMapCanvas(mapView, mapCanvas)
    
            # register MapCanvas on MV level
    
            mapView.registerMapCanvas(self.mSensor, mapCanvas)
    
            # register MapCanvas on STV level
            self.STV.registerMapCanvas(mapCanvas)
    
            mapCanvas.blockSignals(False)
    
            mapCanvas.renderComplete.connect(lambda : self.onRenderingChange(False))
            mapCanvas.renderStarting.connect(lambda : self.onRenderingChange(True))
    
    
                lambda dt: self.STV.TSV.ui.dockSystemInfo.addTimeDelta('Map {}'.format(self.mSensor.name()), dt))
    
            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.mMapCanvases.values()]
            drawFlags = [m.isDrawing() for m in self.mMapCanvases.values()]
    
            isLoading = any(renderFlags)
    
            self.showLoading(isLoading)
    
            s = ""
    
        def registerMapCanvas(self, mapView, mapCanvas):
    
            from timeseriesviewer.mapcanvas import MapCanvas
            assert isinstance(mapCanvas, MapCanvas)
    
            assert isinstance(mapView, MapView)
    
            self.mMapCanvases[mapView] = 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.layout().insertWidget(self.ui.layout().count() - 1, 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)
    
        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))
    
        def __lt__(self, other):
            assert isinstance(other, DatumView)
            return self.TSD < other.TSD
    
            assert isinstance(other, DatumView)
            return self.TSD == other.TSD
    
        sigLoadingStarted = pyqtSignal(DatumView, MapView)
        sigLoadingFinished = pyqtSignal(DatumView, MapView)
    
        sigShowProfiles = pyqtSignal(SpatialPoint, MapCanvas, str)
    
        sigShowMapLayerInfo = pyqtSignal(dict)
        sigSpatialExtentChanged = pyqtSignal(SpatialExtent)
    
        sigMapSizeChanged = pyqtSignal(QSize)
    
        sigCRSChanged = pyqtSignal(QgsCoordinateReferenceSystem)
    
        sigActivateMapTool = pyqtSignal(str)
    
    
        def __init__(self, timeSeriesViewer):
            super(SpatialTemporalVisualization, self).__init__()
    
            #assert isinstance(timeSeriesViewer, TimeSeriesViewer), timeSeriesViewer
    
            self.mBlockCanvasSignals = False
    
            self.mSpatialExtent = SpatialExtent.world()
    
            self.mCRS = self.mSpatialExtent.crs()
            self.mSize = QSize(200,200)
            self.mColor = Qt.black
    
            self.mMapCanvases = []
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
            #map-tool handling
            self.mMapToolActivator = None
            self.mMapTools = []
    
            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)
    
            self.TSV = timeSeriesViewer
            self.TS = timeSeriesViewer.TS
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.ui.dockMapViews.setTimeSeries(self.TS)
    
            self.targetLayout = self.ui.scrollAreaSubsetContent.layout()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            #self.MVC = MapViewCollection(self)
            #self.MVC.sigShowProfiles.connect(self.sigShowProfiles.emit)
    
            self.MVC = self.ui.dockMapViews
    
    benjamin.jakimow@geo.hu-berlin.de's avatar
    benjamin.jakimow@geo.hu-berlin.de committed
            assert isinstance(self.MVC, MapViewCollectionDock)
    
            self.MVC.sigShowProfiles.connect(self.sigShowProfiles.emit)
    
            self.MVC.sigMapViewAdded.connect(self.onMapViewAdded)
    
            self.DVC = DateViewCollection(self)
    
            self.DVC.sigResizeRequired.connect(self.adjustScrollArea)
    
            #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)
    
            self.DVC.addDates(self.TS[:])
    
            if len(self.TS) > 0:
                self.setSpatialExtent(self.TS.getMaxSpatialExtent())
    
            #self.setSubsetSize(QSize(100,50))
    
        def onMapViewAdded(self, *args):
            self.adjustScrollArea()
            s = ""
    
        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))
    
    
    
    
            from timeseriesviewer.mapcanvas import MapCanvas
            for mapCanvas in self.mMapCanvases:
                assert isinstance(mapCanvas, MapCanvas)
                mapCanvas.setCrosshairStyle(crosshairStyle)
    
            #self.MVC.setCrosshairStyle(crosshairStyle)
    
    
        def setShowCrosshair(self, b):
            self.MVC.setShowCrosshair(b)
    
        def setVectorLayer(self, lyr):
            self.MVC.setVectorLayer(lyr)
    
    
    
    
        def setMapSize(self, size):
    
            self.mSize = size
    
            from timeseriesviewer.mapcanvas import MapCanvas
            for mapCanvas in self.mMapCanvases:
                assert isinstance(mapCanvas, MapCanvas)
                mapCanvas.setFixedSize(size)
    
            self.sigMapSizeChanged.emit(self.mSize)