Esempio n. 1
0
def set_vector_graduated_style(vector_layer, style):
    """Set graduated QGIS vector style based on InaSAFE style dictionary.

    For **opaque** a value of **0** can be used. For **fully transparent**, a
    value of **100** can be used. The calling function should take care to
    scale the transparency level to between 0 and 100.

    :param vector_layer: A QGIS vector layer that will be styled.
    :type vector_layer: QgsVectorLayer, QgsMapLayer

    :param style: Dictionary of the form as in the example below
    :type style: dict

    :returns: None - Sets and saves style for vector_layer

    Example style::

        {'target_field': 'DMGLEVEL',
        'style_classes':
        [{'transparency': 1, 'max': 1.5, 'colour': '#fecc5c',
          'min': 0.5, 'label': '[0.5 - 1.5] Low damage', 'size' : 1},
        {'transparency': 55, 'max': 2.5, 'colour': '#fd8d3c',
         'min': 1.5, 'label': '[1.5 - 2.5] Medium damage', 'size' : 1},
        {'transparency': 80, 'max': 3.5, 'colour': '#f31a1c',
         'min': 2.5, 'label': '[2.5 - 3.5] High damage', 'size' : 1}]}

    .. note:: The transparency and size keys are optional. Size applies
       to points only.

    .. note:: you can optionally pass border_color also, if not color will be
        used

    .. note:: you can optionally pass data_defined also, this has to be a
        dictionary of property: expressions like
        {'color': 'color_hsv(%s, "pop"/%s*100, %s)' % (hue, max, val)}
    """
    target_field = style['target_field']
    style_classes = style['style_classes']
    geometry_type = vector_layer.geometryType()

    range_list = []
    for style_class in style_classes:
        # Transparency 100: transparent
        # Transparency 0: opaque
        size = 2  # mm
        if 'size' in style_class:
            size = style_class['size']
        transparency_percent = 0
        if 'transparency' in style_class:
            transparency_percent = style_class['transparency']

        if 'min' not in style_class:
            raise StyleError('Style info should provide a "min" entry')
        if 'max' not in style_class:
            raise StyleError('Style info should provide a "max" entry')

        try:
            min_val = float(style_class['min'])
        except TypeError:
            raise StyleError('Class break lower bound should be a number.'
                             'I got %s' % style_class['min'])

        try:
            max_val = float(style_class['max'])
        except TypeError:
            raise StyleError('Class break upper bound should be a number.'
                             'I got %s' % style_class['max'])

        color = style_class['colour']
        label = style_class['label']
        color = QtGui.QColor(color)
        # noinspection PyArgumentList
        symbol = QgsSymbolV2.defaultSymbol(geometry_type)
        # We need to create a custom symbol layer as
        # the border colour of a symbol can not be set otherwise
        # noinspection PyArgumentList
        try:
            value = style_class['border_color']
            border_color = QtGui.QColor(value)
        except KeyError:
            border_color = color

        if geometry_type == QGis.Point:
            symbol_layer = QgsSimpleMarkerSymbolLayerV2()
            symbol_layer.setBorderColor(border_color)
            symbol_layer.setSize(size)
            symbol.changeSymbolLayer(0, symbol_layer)
        elif geometry_type == QGis.Polygon:
            symbol_layer = QgsSimpleFillSymbolLayerV2()
            symbol_layer.setBorderColor(border_color)
            symbol.changeSymbolLayer(0, symbol_layer)
        else:
            # for lines we do nothing special as the property setting
            # below should give us what we require.
            pass

        try:
            value = style_class['border_wdth']
            symbol_layer.setBorderWidth(value)
        except (NameError, KeyError):
            # use QGIS default border size
            # NameError is when symbol_layer is not defined (lines for example)
            # KeyError is when borderWidth is not defined
            if hasattr(symbol_layer, 'setBorderWidth') and \
                    geometry_type == QGis.Polygon:
                symbol_layer.setBorderWidth(0)

        # set data defined properties
        try:
            for prop, expr in style_class['data_defined'].iteritems():
                symbol_layer.setDataDefinedProperty(prop, expr)
        except (NameError, KeyError):
            # NameError is when symbol_layer is not defined (lines for example)
            # KeyError is when data_defined is not defined
            pass

        symbol.setColor(color)
        # .. todo:: Check that vectors use alpha as % otherwise scale TS
        # Convert transparency % to opacity
        # alpha = 0: transparent
        # alpha = 1: opaque
        alpha = 1 - transparency_percent / 100.0
        symbol.setAlpha(alpha)
        range_renderer = QgsRendererRangeV2(min_val, max_val, symbol, label)
        range_list.append(range_renderer)

    renderer = QgsGraduatedSymbolRendererV2('', range_list)
    renderer.setMode(QgsGraduatedSymbolRendererV2.EqualInterval)
    renderer.setClassAttribute(target_field)
    vector_layer.setRendererV2(renderer)
    vector_layer.saveDefaultStyle()
Esempio n. 2
0
def set_vector_categorized_style(vector_layer, style):
    """Set categorized QGIS vector style based on InaSAFE style dictionary.

    For **opaque** a value of **0** can be used. For **fully transparent**, a
    value of **100** can be used. The calling function should take care to
    scale the transparency level to between 0 and 100.

    :param vector_layer: A QGIS vector layer that will be styled.
    :type vector_layer: QgsVectorLayer

    :param style: Dictionary of the form as in the example below.
    :type style: dict

    :returns: None - Sets and saves style for vector_layer

    Example::

        {'target_field': 'DMGLEVEL',
        'style_classes':
        [{'transparency': 1, 'value': 1, 'colour': '#fecc5c',
          'label': 'Low damage', 'size' : 1},
        {'transparency': 55, 'value': 2, 'colour': '#fd8d3c',
         'label': 'Medium damage', 'size' : 1},
        {'transparency': 80, 'value': 3, 'colour': '#f31a1c',
         'label': 'High damage', 'size' : 1}]}

    .. note:: The transparency and size keys are optional. Size applies
        to points only.

    .. note:: We should change 'value' in style classes to something more
        meaningful e.g. discriminant value

    .. note:: you can optionally pass border_color also, if not color will be
        used

    .. note:: you can optionally pass border_width also, if not QGIS defaults
        will be used

    .. note:: you can optionally pass data_defined also, this has to be a
        dictionary of property: expressions like
        {'color': 'color_hsv(%s, "pop"/%s*100, %s)' % (hue, max, val)}
    """
    target_field = style['target_field']
    style_classes = style['style_classes']
    geometry_type = vector_layer.geometryType()

    category_list = []
    for style_class in style_classes:
        # Transparency 100: transparent
        # Transparency 0: opaque
        size = 2  # mm
        if 'size' in style_class:
            size = style_class['size']
        transparency_percent = 0
        if 'transparency' in style_class:
            transparency_percent = style_class['transparency']

        if 'value' not in style_class:
            raise StyleError('Style info should provide a "value" entry')

        value = style_class['value']
        colour = style_class['colour']
        label = style_class['label']
        colour = QtGui.QColor(colour)
        try:
            border_color = QtGui.QColor(style_class['border_color'])
        except KeyError:
            border_color = colour

        # noinspection PyArgumentList
        symbol = QgsSymbolV2.defaultSymbol(geometry_type)
        # We need to create a custom symbol layer as
        # the border colour of a symbol can not be set otherwise
        # noinspection PyArgumentList
        if geometry_type == QGis.Point:
            symbol_layer = QgsSimpleMarkerSymbolLayerV2()
            symbol_layer.setBorderColor(border_color)
            symbol_layer.setSize(size)
            symbol.changeSymbolLayer(0, symbol_layer)
        elif geometry_type == QGis.Polygon:
            symbol_layer = QgsSimpleFillSymbolLayerV2()
            symbol_layer.setBorderColor(border_color)
            symbol.changeSymbolLayer(0, symbol_layer)
        else:
            # for lines we do nothing special as the property setting
            # below should give us what we require.
            symbol_layer = None

        try:
            symbol_layer.setBorderWidth(style_class['border_width'])
        except (NameError, KeyError, AttributeError):
            # use QGIS default border size
            # NameError is when symbol_layer is not defined (lines for example)
            # KeyError is when border_width is not defined
            # AttributeError is when setBorderWidth is not defined
            # (QgsSimpleMarkerSymbolLayerV2)
            if hasattr(symbol_layer, 'setBorderWidth') and \
                    geometry_type == QGis.Polygon:
                symbol_layer.setBorderWidth(0)

        # set data defined properties
        try:
            for prop, expr in style_class['data_defined'].iteritems():
                symbol_layer.setDataDefinedProperty(prop, expr)
        except (NameError, KeyError):
            # NameError is when symbol_layer is not defined (lines for example)
            # KeyError is when data_defined is not defined
            pass

        symbol.setColor(colour)
        # .. todo:: Check that vectors use alpha as % otherwise scale TS
        # Convert transparency % to opacity
        # alpha = 0: transparent
        # alpha = 1: opaque
        alpha = 1 - transparency_percent / 100.0
        symbol.setAlpha(alpha)
        category = QgsRendererCategoryV2(value, symbol, label)
        category_list.append(category)

    renderer = QgsCategorizedSymbolRendererV2('', category_list)
    renderer.setClassAttribute(target_field)
    vector_layer.setRendererV2(renderer)
    vector_layer.saveDefaultStyle()