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"
Example #2
0
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
Example #3
0
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
Example #4
0
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
Example #5
0
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