def testTransparency(self): myPath = os.path.join(unitTestDataPath('raster'), 'band1_float32_noct_epsg4326.tif') myFileInfo = QFileInfo(myPath) myBaseName = myFileInfo.baseName() myRasterLayer = QgsRasterLayer(myPath, myBaseName) myMessage = 'Raster not loaded: %s' % myPath assert myRasterLayer.isValid(), myMessage renderer = QgsSingleBandGrayRenderer(myRasterLayer.dataProvider(), 1) myRasterLayer.setRenderer(renderer) myRasterLayer.setContrastEnhancement( QgsContrastEnhancement.StretchToMinimumMaximum, QgsRasterMinMaxOrigin.MinMax) myContrastEnhancement = myRasterLayer.renderer().contrastEnhancement() # print ("myContrastEnhancement.minimumValue = %.17g" % # myContrastEnhancement.minimumValue()) # print ("myContrastEnhancement.maximumValue = %.17g" % # myContrastEnhancement.maximumValue()) # Unfortunately the minimum/maximum values calculated in C++ and Python # are slightly different (e.g. 3.3999999521443642e+38 x # 3.3999999521444001e+38) # It is not clear where the precision is lost. # We set the same values as C++. myContrastEnhancement.setMinimumValue(-3.3319999287625854e+38) myContrastEnhancement.setMaximumValue(3.3999999521443642e+38) #myType = myRasterLayer.dataProvider().dataType(1); #myEnhancement = QgsContrastEnhancement(myType); myTransparentSingleValuePixelList = [] rasterTransparency = QgsRasterTransparency() myTransparentPixel1 = \ QgsRasterTransparency.TransparentSingleValuePixel() myTransparentPixel1.min = -2.5840000772112106e+38 myTransparentPixel1.max = -1.0879999684602689e+38 myTransparentPixel1.percentTransparent = 50 myTransparentSingleValuePixelList.append(myTransparentPixel1) myTransparentPixel2 = \ QgsRasterTransparency.TransparentSingleValuePixel() myTransparentPixel2.min = 1.359999960575336e+37 myTransparentPixel2.max = 9.520000231087593e+37 myTransparentPixel2.percentTransparent = 70 myTransparentSingleValuePixelList.append(myTransparentPixel2) rasterTransparency.setTransparentSingleValuePixelList( myTransparentSingleValuePixelList) rasterRenderer = myRasterLayer.renderer() assert rasterRenderer rasterRenderer.setRasterTransparency(rasterTransparency) QgsProject.instance().addMapLayers([ myRasterLayer, ]) myMapSettings = QgsMapSettings() myMapSettings.setLayers([myRasterLayer]) myMapSettings.setExtent(myRasterLayer.extent()) myChecker = QgsRenderChecker() myChecker.setControlName("expected_raster_transparency") myChecker.setMapSettings(myMapSettings) myResultFlag = myChecker.runTest("raster_transparency_python") assert myResultFlag, "Raster transparency rendering test failed"
def setRasterStyle(theQgsRasterLayer, theStyle): """Set QGIS raster style based on InaSAFE style dictionary. This function will set both the colour map and the transparency for the passed in layer. .. note:: There is currently a limitation in QGIS in that pixel transparency values can not be specified in ranges and consequently the opacity is of limited value and seems to only work effectively with integer values. .. todo:: Get Tim to implement range based transparency in the core QGIS library. Input theQgsRasterLayer: Qgis layer style: Dictionary of the form as in the example below style_classes = [dict(colour='#38A800', quantity=2, transparency=0), dict(colour='#38A800', quantity=5, transparency=1), dict(colour='#79C900', quantity=10, transparency=1), dict(colour='#CEED00', quantity=20, transparency=1), dict(colour='#FFCC00', quantity=50, transparency=1), dict(colour='#FF6600', quantity=100, transparency=1), dict(colour='#FF0000', quantity=200, transparency=1), dict(colour='#7A0000', quantity=300, transparency=1)] Output Sets and saves style for theQgsRasterLayer """ theQgsRasterLayer.setDrawingStyle(QgsRasterLayer.PalettedColor) myClasses = theStyle['style_classes'] myRangeList = [] myTransparencyList = [] myLastValue = 0 for myClass in myClasses: myMax = myClass['quantity'] myColour = QtGui.QColor(myClass['colour']) myLabel = QtCore.QString() if 'label' in myClass: myLabel = QtCore.QString(myClass['label']) myShader = QgsColorRampShader.ColorRampItem(myMax, myColour, myLabel) myRangeList.append(myShader) # Create opacity entries for this range myTransparencyPercent = 0 if 'transparency' in myClass: myTransparencyPercent = int(myClass['transparency']) if myTransparencyPercent > 0: # Check if range extrema are integers so we know if we can # use them to calculate a value range if ((myLastValue == int(myLastValue)) and (myMax == int(myMax))): # Ensure that they are integers # (e.g 2.0 must become 2, see issue #126) myLastValue = int(myLastValue) myMax = int(myMax) # Set transparencies myRange = range(myLastValue, myMax) for myValue in myRange: myPixel = \ QgsRasterTransparency.TransparentSingleValuePixel() myPixel.pixelValue = myValue myPixel.percentTransparent = myTransparencyPercent myTransparencyList.append(myPixel) #myLabel = myClass['label'] # Apply the shading algorithm and design their ramp theQgsRasterLayer.setColorShadingAlgorithm(QgsRasterLayer.ColorRampShader) myFunction = theQgsRasterLayer.rasterShader().rasterShaderFunction() # Discrete will shade any cell between maxima of this break # and mamima of previous break to the colour of this break myFunction.setColorRampType(QgsColorRampShader.DISCRETE) myFunction.setColorRampItemList(myRangeList) # Now set the raster transparency theQgsRasterLayer.rasterTransparency().setTransparentSingleValuePixelList( myTransparencyList) theQgsRasterLayer.saveDefaultStyle() return myRangeList, myTransparencyList
def set_legacy_raster_style(raster_layer, style): """Set QGIS raster style based on InaSAFE style dictionary for QGIS < 2.0. This function will set both the colour map and the transparency for the passed in layer. :param raster_layer: A QGIS raster layer that will be styled. :type raster_layer: QgsVectorLayer :param style: Dictionary of the form as in the example below. :type style: dict Example:: style_classes = [dict(colour='#38A800', quantity=2, transparency=0), dict(colour='#38A800', quantity=5, transparency=50), dict(colour='#79C900', quantity=10, transparency=50), dict(colour='#CEED00', quantity=20, transparency=50), dict(colour='#FFCC00', quantity=50, transparency=34), dict(colour='#FF6600', quantity=100, transparency=77), dict(colour='#FF0000', quantity=200, transparency=24), dict(colour='#7A0000', quantity=300, transparency=22)] .. note:: There is currently a limitation in QGIS in that pixel transparency values can not be specified in ranges and consequently the opacity is of limited value and seems to only work effectively with integer values. :returns: A two tuple containing a range list and a transparency list. :rtype: (list, list) """ raster_layer.setDrawingStyle(QgsRasterLayer.PalettedColor) LOGGER.debug(style) myRangeList = [] myTransparencyList = [] # Always make 0 pixels transparent see issue #542 # noinspection PyCallingNonCallable myPixel = QgsRasterTransparency.TransparentSingleValuePixel() myPixel.pixelValue = 0.0 myPixel.percentTransparent = 100 myTransparencyList.append(myPixel) myLastValue = 0 for myClass in style: LOGGER.debug('Evaluating class:\n%s\n' % myClass) myMax = myClass['quantity'] myColour = QtGui.QColor(myClass['colour']) myLabel = QtCore.QString() if 'label' in myClass: myLabel = QtCore.QString(myClass['label']) # noinspection PyCallingNonCallable myShader = QgsColorRampShader.ColorRampItem(myMax, myColour, myLabel) myRangeList.append(myShader) if math.isnan(myMax): LOGGER.debug('Skipping class.') continue # Create opacity entries for this range myTransparencyPercent = 0 if 'transparency' in myClass: myTransparencyPercent = int(myClass['transparency']) if myTransparencyPercent > 0: # Always assign the transparency to the class' specified quantity # noinspection PyCallingNonCallable myPixel = QgsRasterTransparency.TransparentSingleValuePixel() myPixel.pixelValue = myMax myPixel.percentTransparent = myTransparencyPercent myTransparencyList.append(myPixel) # Check if range extrema are integers so we know if we can # use them to calculate a value range if (myLastValue == int(myLastValue)) and (myMax == int(myMax)): # Ensure that they are integers # (e.g 2.0 must become 2, see issue #126) myLastValue = int(myLastValue) myMax = int(myMax) # Set transparencies myRange = range(myLastValue, myMax) for myValue in myRange: # noinspection PyCallingNonCallable myPixel = \ QgsRasterTransparency.TransparentSingleValuePixel() myPixel.pixelValue = myValue myPixel.percentTransparent = myTransparencyPercent myTransparencyList.append(myPixel) # Apply the shading algorithm and design their ramp raster_layer.setColorShadingAlgorithm( QgsRasterLayer.ColorRampShader) myFunction = raster_layer.rasterShader().rasterShaderFunction() # Discrete will shade any cell between maxima of this break # and minima of previous break to the colour of this break myFunction.setColorRampType(QgsColorRampShader.DISCRETE) myFunction.setColorRampItemList(myRangeList) # Now set the raster transparency raster_layer.rasterTransparency()\ .setTransparentSingleValuePixelList(myTransparencyList) raster_layer.saveDefaultStyle() return myRangeList, myTransparencyList
def set_raster_style(raster_layer, style): """Set QGIS raster style based on InaSAFE style dictionary for QGIS >= 2.0. This function will set both the colour map and the transparency for the passed in layer. :param raster_layer: A QGIS raster layer that will be styled. :type raster_layer: QgsVectorLayer :param style: List of the form as in the example below. :type style: list Example:: style_classes = [dict(colour='#38A800', quantity=2, transparency=0), dict(colour='#38A800', quantity=5, transparency=50), dict(colour='#79C900', quantity=10, transparency=50), dict(colour='#CEED00', quantity=20, transparency=50), dict(colour='#FFCC00', quantity=50, transparency=34), dict(colour='#FF6600', quantity=100, transparency=77), dict(colour='#FF0000', quantity=200, transparency=24), dict(colour='#7A0000', quantity=300, transparency=22)] :returns: A two tuple containing a range list and a transparency list. :rtype: (list, list) """ # Note imports here to prevent importing on unsupported QGIS versions # pylint: disable=E0611 # pylint: disable=W0621 # pylint: disable=W0404 # noinspection PyUnresolvedReferences from qgis.core import (QgsRasterShader, QgsColorRampShader, QgsSingleBandPseudoColorRenderer, QgsRasterTransparency) # pylint: enable=E0611 # pylint: enable=W0621 # pylint: enable=W0404 ramp_item_list = [] transparency_list = [] LOGGER.debug(style) for style_class in style: LOGGER.debug('Evaluating class:\n%s\n' % style_class) if 'quantity' not in style_class: LOGGER.exception('Class has no quantity attribute') continue class_max = style_class['max'] if math.isnan(class_max): LOGGER.debug('Skipping class - max is nan.') continue class_min = style_class['min'] if math.isnan(class_min): LOGGER.debug('Skipping class - min is nan.') continue colour = QtGui.QColor(style_class['colour']) label = '' if 'label' in style_class: label = style_class['label'] # noinspection PyCallingNonCallable ramp_item = QgsColorRampShader.ColorRampItem(class_max, colour, label) ramp_item_list.append(ramp_item) # Create opacity entries for this range transparency_percent = 0 if 'transparency' in style_class: transparency_percent = int(style_class['transparency']) if transparency_percent > 0: # Check if range extrema are integers so we know if we can # use them to calculate a value range # noinspection PyCallingNonCallable pixel = QgsRasterTransparency.TransparentSingleValuePixel() pixel.min = class_min # We want it just a little bit smaller than max # so that ranges are discrete pixel.max = class_max # noinspection PyPep8Naming pixel.percentTransparent = transparency_percent transparency_list.append(pixel) # Always set transparent for value = 0. See #2529 zero_pixel = QgsRasterTransparency.TransparentSingleValuePixel() zero_pixel.min = 0 zero_pixel.max = 0 zero_pixel.percentTransparent = 100 transparency_list.append(zero_pixel) LOGGER.debug('Transparency list: (min, max, percentTransparent') for t in transparency_list: LOGGER.debug('%s %s %s' % (t.min, t.max, t.percentTransparent)) band = 1 # gdal counts bands from base 1 LOGGER.debug('Setting colour ramp list') raster_shader = QgsRasterShader() color_ramp_shader = QgsColorRampShader() color_ramp_shader.setColorRampType(QgsColorRampShader.INTERPOLATED) color_ramp_shader.setColorRampItemList(ramp_item_list) LOGGER.debug('Setting shader function') raster_shader.setRasterShaderFunction(color_ramp_shader) LOGGER.debug('Setting up renderer') renderer = QgsSingleBandPseudoColorRenderer(raster_layer.dataProvider(), band, raster_shader) LOGGER.debug('Assigning renderer to raster layer') raster_layer.setRenderer(renderer) LOGGER.debug('Setting raster transparency list') renderer = raster_layer.renderer() transparency = QgsRasterTransparency() transparency.setTransparentSingleValuePixelList(transparency_list) renderer.setRasterTransparency(transparency) # For interest you can also view the list like this: # pix = t.transparentSingleValuePixelList() # for px in pix: # print 'Min: %s Max %s Percent %s' % ( # px.min, px.max, px.percentTransparent) LOGGER.debug('Saving style as default') raster_layer.saveDefaultStyle() LOGGER.debug('Setting raster style done!') return ramp_item_list, transparency_list
def _setNewRasterStyle(theQgsRasterLayer, theClasses): """Set QGIS raster style based on InaSAFE style dictionary for QGIS >= 2.0. This function will set both the colour map and the transparency for the passed in layer. Args: * theQgsRasterLayer: QgsRasterLayer * theClasses: List of the form as in the example below. Returns: * list: RangeList * list: TransparencyList Example: style_classes = [dict(colour='#38A800', quantity=2, transparency=0), dict(colour='#38A800', quantity=5, transparency=50), dict(colour='#79C900', quantity=10, transparency=50), dict(colour='#CEED00', quantity=20, transparency=50), dict(colour='#FFCC00', quantity=50, transparency=34), dict(colour='#FF6600', quantity=100, transparency=77), dict(colour='#FF0000', quantity=200, transparency=24), dict(colour='#7A0000', quantity=300, transparency=22)] """ # Note imports here to prevent importing on unsupported QGIS versions # pylint: disable=E0611 # pylint: disable=W0621 # pylint: disable=W0404 from qgis.core import (QgsRasterShader, QgsColorRampShader, QgsSingleBandPseudoColorRenderer, QgsRasterTransparency) # pylint: enable=E0611 # pylint: enable=W0621 # pylint: enable=W0404 myRampItemList = [] myTransparencyList = [] LOGGER.debug(theClasses) for myClass in theClasses: LOGGER.debug('Evaluating class:\n%s\n' % myClass) if 'quantity' not in myClass: LOGGER.exception('Class has no quantity attribute') continue myMax = myClass['max'] if math.isnan(myMax): LOGGER.debug('Skipping class - max is nan.') continue myMin = myClass['min'] if math.isnan(myMin): LOGGER.debug('Skipping class - min is nan.') continue myColour = QtGui.QColor(myClass['colour']) myLabel = QtCore.QString() if 'label' in myClass: myLabel = QtCore.QString(myClass['label']) myRampItem = QgsColorRampShader.ColorRampItem(myMax, myColour, myLabel) myRampItemList.append(myRampItem) # Create opacity entries for this range myTransparencyPercent = 0 if 'transparency' in myClass: myTransparencyPercent = int(myClass['transparency']) if myTransparencyPercent > 0: # Check if range extrema are integers so we know if we can # use them to calculate a value range myPixel = QgsRasterTransparency.TransparentSingleValuePixel() myPixel.min = myMin # We want it just a leeetle bit smaller than max # so that ranges are discrete myPixel.max = myMax myPixel.percentTransparent = myTransparencyPercent myTransparencyList.append(myPixel) myBand = 1 # gdal counts bands from base 1 LOGGER.debug('Setting colour ramp list') myRasterShader = QgsRasterShader() myColorRampShader = QgsColorRampShader() myColorRampShader.setColorRampType(QgsColorRampShader.INTERPOLATED) myColorRampShader.setColorRampItemList(myRampItemList) LOGGER.debug('Setting shader function') myRasterShader.setRasterShaderFunction(myColorRampShader) LOGGER.debug('Setting up renderer') myRenderer = QgsSingleBandPseudoColorRenderer( theQgsRasterLayer.dataProvider(), myBand, myRasterShader) LOGGER.debug('Assigning renderer to raster layer') theQgsRasterLayer.setRenderer(myRenderer) LOGGER.debug('Setting raster transparency list') myRenderer = theQgsRasterLayer.renderer() myTransparency = QgsRasterTransparency() myTransparency.setTransparentSingleValuePixelList(myTransparencyList) myRenderer.setRasterTransparency(myTransparency) # For interest you can also view the list like this: #pix = t.transparentSingleValuePixelList() #for px in pix: # print 'Min: %s Max %s Percent %s' % ( # px.min, px.max, px.percentTransparent) LOGGER.debug('Saving style as default') theQgsRasterLayer.saveDefaultStyle() LOGGER.debug('Setting raster style done!') return myRampItemList, myTransparencyList