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()
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()