15

Following on from this question: How to turn on/off all labels of all layers in QGIS, OP mentioned in his comment that he uses rule-based labels. I tried searching online as to how these types of labels could be read and modified but only managed to find this post from lutraconsulting:

In order to facilitate addition of rule-based labelling, some internal changes were made to the QGIS labelling engine interface. The labelling is now driven by the new class QgsLabelingEngineV2 which may have several label providers associated with it.

Sounds great. However, when reading through the QgsLabelingEngineV2 class, it mentions:

this class is not a part of public API yet.

Is it currently possible to control rule-based labelling using python?

3

3 Answers 3

8

Below some help to setup rule based labeling from scratch with the new QGIS 3 API

#Configure label settings
settings = QgsPalLayerSettings()
settings.fieldName = 'myFieldName'
textFormat = QgsTextFormat()
textFormat.setSize(10)
settings.setFormat(textFormat)
#create and append a new rule
root = QgsRuleBasedLabeling.Rule(QgsPalLayerSettings())
rule = QgsRuleBasedLabeling.Rule(settings)
rule.setDescription(fieldName)
rule.setFilterExpression('myExpression')
root.appendChild(rule)
#Apply label configuration
rules = QgsRuleBasedLabeling(root)
myLayer.setLabeling(rules)
myLayer.triggerRepaint()

Unfortunately I can't find how to iterate over existing rules, the labeling() method available for vector layers return an object of QgsAbstractVectorLayerLabeling class but it seems there is no way to get the root rule (QgsRuleBasedLabeling) from this class, the only possibility I found is to get directly pal settings using providers ids but I can't access to rules tree. Anyone have a clue ?

EDIT

It's now fixed, labeling() function return a QgsRuleBasedLabeling() : https://github.com/qgis/QGIS/commit/4b365a8f47d96b35f7609859e580388927ae0606

2
  • Thanks for your answer, nicely worked out! Hope you don't mind but I edited your post slightly to include myLayer.triggerRepaint() to refresh the layer and allow the labels to show immediately after setting the rules :)
    – Joseph
    Commented Feb 5, 2018 at 11:11
  • It took me a while figuring out you may need to add a myLayer.setLabelsEnabled(True) to make the labels appearing...
    – juminet
    Commented Oct 21, 2022 at 14:36
4

From QGIS 3, there is a new QgsRuleBasedLabeling Class which would allow you to control rule-based labelling using the new API.

Rules can be added using QgsRuleBasedLabeling::Rule.


(Unfortunately, I cannot test the 2.99 version at the moment. But I would happily accept an answer if it provides a working example.)

3
+25

This is what I use to change a filter expression in the rule-based symbology under QGIS 2.18, not sure if that's what you're asking for. API reference at http://qgis.org/api/2.18/classQgsRuleBasedRendererV2.html

import re
lddLrs = qgis.utils.iface.legendInterface().layers()    #get all loaded layers
for lyr in lddLrs:
    if (lyr.type()==QgsMapLayer.VectorLayer and lyr.name()=='layer_with_rules'): rLyr = lyr

newType = 1
for child in rLyr.rendererV2().rootRule().children():
    oldFilter = child.filterExpression()  #you can print this to see what the old expression is
    print oldFilter

    newFilter = re.sub(r"type = (\d*)", r"type = {0}".format(newType), oldFilter)  #this is an example to substitute a rule-based filter to a new number
    print newFilter

    child.setFilterExpression(newFilter)
1
  • Thanks for your answer but as you said, I think this only applies to symbology and not labels :)
    – Joseph
    Commented Mar 15, 2017 at 9:40

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.