[GIS] How to define border colour for rule-based style using PyQGIS

pyqgispythonqgisstyle

I use the following to create a Rule-based style for a given layer which includes defining a label, expression and colour fill:

from PyQt4.QtGui import QColor

layer = qgis.utils.iface.activeLayer()
style_rules = (
    ('First', 'expression_1', '#dbffdb'),
    ('Second', 'expression_2', '#f0ab64'),        
)
symbol = QgsSymbolV2.defaultSymbol(layer.geometryType())
renderer = QgsRuleBasedRendererV2(symbol)
root_rule = renderer.rootRule()
for label, expression, color_name in style_rules:
    rule = root_rule.children()[0].clone()
    rule.setLabel(label)
    rule.setFilterExpression(expression)
    rule.symbol().setColor(QColor(color_name))
    root_rule.appendChild(rule)

root_rule.removeChildAt(0)
layer.setRendererV2(renderer)
layer.triggerRepaint()

Can I define the colour border using the above method? If not, how could I iterate through the symbol layers and apply a border colour after a rule-based style has been set?

I tried incorporating it into style_rules but not sure how to set it (in this case, I just want the border colour to match the polygon fill):

style_rules = (
    ('First', 'expression_1', '#dbffdb', '#dbffdb'),
    ('Second', 'expression_2', '#f0ab64', '#f0ab64'),        
)
for label, expression, color_name, color_border in style_rules:
    rule = root_rule.children()[0].clone()
    rule.setLabel(label)
    rule.setFilterExpression(expression)
    rule.symbol().setColor(QColor(color_name))
    root_rule.appendChild(rule)

EDIT:

I have looked at the QgsSymbolV2 and QgsRuleBasedRendererV2 classes but neither seems to have anything related to the border. The QgsSimpleFillSymbolLayerV2 class does have a borderColor function so I'm now wondering if it is even possible to define a border colour using the QgsRuleBasedRendererV2 class.


I'm using QGIS 2.18.0 for Win7 64-bit.

Best Answer

Since you want the border color to match the corresponding polygon fill, you can use the data defined property @symbol_color, which returns the fill color for each polygon. Then, for the default polygon symbol (which is the base of your QgsRuleBasedRendererV2) you set its color_border property to @symbol_color:

ddp = QgsDataDefined( True, True, "@symbol_color" ) # active, useExpression, expression
symbol.symbolLayer( 0 ).setDataDefinedProperty( "color_border", ddp )

Your script would become this:

from PyQt4.QtGui import QColor

layer = iface.activeLayer()
style_rules = (
    ('First', 'expression_1', '#dbffdb'),
    ('Second', 'expression_2', '#f0ab64'),
)
symbol = QgsSymbolV2.defaultSymbol(layer.geometryType())
ddp = QgsDataDefined( True, True, "@symbol_color" )
symbol.symbolLayer( 0 ).setDataDefinedProperty( "color_border", ddp )
renderer = QgsRuleBasedRendererV2(symbol)
root_rule = renderer.rootRule()
for label, expression, color_name in style_rules:
    rule = root_rule.children()[0].clone()
    rule.setLabel(label)
    rule.setFilterExpression(expression)
    rule.symbol().setColor(QColor(color_name))
    root_rule.appendChild(rule)

root_rule.removeChildAt(0)
layer.setRendererV2(renderer)
layer.triggerRepaint()

On the other hand, to set the same border color for all polygons in a Rule based renderer, you would use setBorderColor() in this way (after initializing symbol variable):

symbol.symbolLayer( 0 ).setBorderColor( QColor(255,0,0) )

Just tested it on QGIS v2.14.8. Let me know if it works on your QGIS installation.

Related Question