7

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.

2

3 Answers 3

5
+100

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.

3
  • This was exactly what I was looking for, many thanks!!! Funnily enough, I decided to use your second method instead by inserting it inside the for loop and changing it slightly to symbol.symbolLayer(0).setBorderColor(QColor(color_name)). This sets the outline to match the polygon without having to use the data defined property. But both methods work great!
    – Joseph
    Commented Dec 8, 2016 at 12:02
  • 1
    You're welcome. It would be interesting to determine whether there are performance issues by using my or your modified solution. Commented Dec 8, 2016 at 19:13
  • That would be interesting. For my use-case, I am only using about four symbol layers per virtual layer so the change is almost instantaneous. Will award you the bounty in a few days ;)
    – Joseph
    Commented Dec 9, 2016 at 10:09
4
+50

The general logic for setting border color is:

# black polygon with red border
symbol = QgsSymbolV2.defaultSymbol(layer.geometryType())
layer_style = {}
layer_style['color'] = '0, 0, 0'
layer_style['size'] = '2.5'
layer_style['color_border'] = '255, 0, 0'
symbol_layer = QgsSimpleFillSymbolLayerV2.create(layer_style)
1
  • Thanks for your answer, I am aware of this general logic (there's a good link describing this: Symbology of vector layers in QGIS Python Plugins). But I'm not sure how to apply this logic to that of a rule-based renderer or iterate through each symbol_layer once a rule-based style has been created and apply the logic.
    – Joseph
    Commented Jun 28, 2016 at 14:27
1

If you just want the border to go away, you can define the symbol to have no border and that way it will effectively make it so that you don't have to do anything with it.

from:

symbol = QgsSymbolV2.defaultSymbol(layer.geometryType())

to:

symbol = QgsFillSymbolV2.createSimple({'style': 'solid', 'color': '255,0,0,255', 'style_border':'no'})  

This does not change the geometry type of your original layer (tried it).

Hope this helps!

1
  • 1
    Thanks for your answer and that's a good tip. Problem with this is that you can see the canvas colour of where the borders should be (my features are a grid similar to this post) =)
    – Joseph
    Commented Dec 8, 2016 at 10:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.