2

I tried to represent objects of one layer in a different colours depending on a specific attribute. So I came across the rule-based renderer and also already found an algorithm how to use it. (How to programmatically set a rule-based renderer in QGIS?).

So I tried to do it the same way but switched the Classes QgsSymbolV2 and RendererV2 to QgsSymbol and Renderer because the other ones aren't existing in QGIS3. So my script is looking like this:

road_rules = ( ('Criteria_w_h', '"type" LIKE 'Maximum'', 'red', (2,3)), ('Restriktion_h', '"type" LIKE 'Summe_2'', 'orange', (200,)), ('Restriktion_m', '"type" LIKE 'Summe_2'', 'yellow', (60,199,)), ('Restriktion_l', '"type" LIKE 'Summe_2'', 'green', (1,59,)) )

# create a new rule-based renderer
symbol = QgsSymbol.defaultSymbol(layer.geometryType())
renderer = QgsRuleBasedRenderer(symbol)

# get the "root" rule
root_rule = renderer.rootRule()

for label, expression, color_name, scale in road_rules:
    # create a clone (i.e. a copy) of the default rule
    rule = root_rule.children()[0].clone()
    # set the label, expression and color
    rule.setLabel(label)
    rule.setFilterExpression(expression)
    rule.symbol().setColor(QColor(color_name))
    # set the scale limits if they have been specified
    if scale is not None:
        rule.setScaleMinDenom(scale[0])
        rule.setScaleMaxDenom(scale[1])
    # append the rule to the list of rules
    root_rule.appendChild(rule)

# delete the default rule
root_rule.removeChildAt(0)

# apply the renderer to the layer
layer.setRenderer(renderer)

It isn't working in this way. Does anyone have an idea what I am doing wrong?

1 Answer 1

6

This is the second time I've come across this code example in the last week. At least you included a link to the origin source; now I know where it's come from.

I think the main problem you have is that you are mixing double and single quotes without using backslashes as an escape character.

Also, if you want to set scale dependent visibility to you rules, make sure are defining reasonable values in your rules (in your second rule you have only one value and a comma). It also does not make any sense to have the minimum scale value smaller than the maximum. If you want to show the feature between a scale of 1:3 and 1:2 then minimum scale has to be 3 and maximum scale has to be 2. Thats because minimum scale is the most "zoomed out" scale at which the rule will be active.

Also the setScaleMinDenom() and setScaleMaxDenom() methods of QgsRuleBasedRenderer.Rule class have changed to:

setMinimumScale() and setMaximumScale().

Try this revised version of the script:

rules = ( 
    ('Criteria_w_h', "type LIKE 'Maximum'", 'red', (3, 2)), 
    ('Restriktion_h', "type LIKE 'Summe_2'", 'orange', (200, 0)), 
    ('Restriktion_m', "type LIKE 'Summe_2'", 'yellow', (199, 60)), 
    ('Restriktion_l', "type LIKE 'Summe_2'", 'green', (59, 1)) 
)
                
layer = iface.activeLayer()
# create a new rule-based renderer
symbol = QgsSymbol.defaultSymbol(layer.geometryType())
renderer = QgsRuleBasedRenderer(symbol)

# get the "root" rule
root_rule = renderer.rootRule()

for label, expression, color_name, scale in rules:
    # create a clone (i.e. a copy) of the default rule
    rule = root_rule.children()[0].clone()
    # set the label, expression and color
    rule.setLabel(label)
    rule.setFilterExpression(expression)
    rule.symbol().setColor(QColor(color_name))
    # set the scale limits if they have been specified
    if scale is not None:
        rule.setMinimumScale(scale[0])
        rule.setMaximumScale(scale[1])
    # append the rule to the list of rules
    root_rule.appendChild(rule)

# delete the default rule
root_rule.removeChildAt(0)

# apply the renderer to the layer
layer.setRenderer(renderer)
# refresh the layer on the map canvas
layer.triggerRepaint()
5
  • 2
    I was just about to write an answer to this one too :) let me just add that it absolutely does make sense to have three rules with same expression if you want to have different coloring at different scales. Can I propose an edit to your answer?
    – CodeBard
    Jul 8, 2022 at 7:56
  • 2
    @CodeBard, your comments are exactly right! I kept your edits and made a few extra ones. After reading your comments, I think the main problem was only the quotes in the filter expressions and the order of the minimum and maximum scale values. Cheers
    – Ben W
    Jul 8, 2022 at 8:38
  • Thank you both! For some reason i still get an error message because of the command .geometryType although i implemented the class QgsVectorLayer in which geometryType is a method.
    – Anni98
    Jul 8, 2022 at 13:05
  • @Anni98, what is the error message?
    – Ben W
    Jul 8, 2022 at 13:54
  • I figured out that the error message occured because of my input layer so it wasn't an issue with the script. Thanks again for your help.
    – Anni98
    Jul 8, 2022 at 14:13

Your Answer

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

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