Contrôler l'étiquetage basé sur des règles à l'aide de PyQGIS?

15

Suite à cette question: comment activer / désactiver toutes les étiquettes de toutes les couches dans QGIS , OP a mentionné dans son commentaire qu'il utilise des étiquettes basées sur des règles. J'ai essayé de rechercher en ligne comment ces types d'étiquettes pouvaient être lus et modifiés, mais j'ai seulement réussi à trouver ce message de lutraconsulting :

Afin de faciliter l'ajout d'un étiquetage basé sur des règles, certaines modifications internes ont été apportées à l'interface du moteur d'étiquetage QGIS. L'étiquetage est désormais piloté par la nouvelle classe QgsLabelingEngineV2qui peut être associée à plusieurs fournisseurs d'étiquettes.

Super. Cependant, lors de la lecture de la classe QgsLabelingEngineV2 , il mentionne:

cette classe ne fait pas encore partie de l'API publique.

Est-il actuellement possible de contrôler l'étiquetage basé sur des règles à l'aide de python?

Joseph
la source
1
J'ai trouvé un problème ouvert ici sur le projet de documentation Qgis dans Github qui le mentionne également . Je n'ai pas pu trouver de liaison SIP pour cette classe dans les branches MASTER ou 2.18, donc je soupçonne qu'elle n'est toujours disponible qu'en code C ++.
Steven Kay
@StevenKay - Super trouvaille, merci! Serait très utile s'ils faisaient une API pour cela ... Merci aussi pour la modification, je pensais avoir collé le lien correct pour la classe :)
Joseph
@StevenKay - Je pense qu'ils ont créé une API pour cela maintenant, plus précisément la classe QgsRuleBasedLabeling :)
Joseph

Réponses:

6

Ci-dessous une aide pour configurer l'étiquetage basé sur des règles à partir de zéro avec la nouvelle API QGIS 3

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

Malheureusement, je ne trouve pas comment itérer sur les règles existantes, la méthode étiquetage () disponible pour les couches vectorielles renvoie un objet de la classe QgsAbstractVectorLayerLabeling mais il semble qu'il n'y ait aucun moyen d'obtenir la règle racine ( QgsRuleBasedLabeling ) de cette classe, la seule possibilité J'ai trouvé que j'obtenais directement les paramètres de pal en utilisant les identifiants des fournisseurs mais je ne peux pas accéder à l'arborescence des règles. Quelqu'un a une idée?

ÉDITER

Il est maintenant corrigé, la fonction labellisation () renvoie un QgsRuleBasedLabeling (): https://github.com/qgis/QGIS/commit/4b365a8f47d96b35f7609859e580388927ae0606

domlysz
la source
Merci pour votre réponse, bien travaillé! J'espère que cela ne vous dérange pas, mais j'ai légèrement modifié votre message pour inclure myLayer.triggerRepaint()pour actualiser le calque et permettre aux étiquettes de s'afficher immédiatement après avoir défini les règles :)
Joseph
3

Depuis QGIS 3 , il existe une nouvelle classe QgsRuleBasedLabeling qui vous permettrait de contrôler l'étiquetage basé sur des règles à l'aide de la nouvelle API.

Les règles peuvent être ajoutées à l'aide de QgsRuleBasedLabeling :: Rule .


( Malheureusement, je ne peux pas tester la version 2.99 pour le moment. Mais j'accepterais volontiers une réponse si elle fournit un exemple de travail. )

Joseph
la source
1

C'est ce que j'utilise pour changer une expression de filtre dans la symbologie basée sur des règles sous QGIS 2.18, je ne sais pas si c'est ce que vous demandez. Référence de l'API sur 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)
weiji14
la source
Merci pour votre réponse, mais comme vous l'avez dit, je pense que cela ne s'applique qu'à la symbologie et non aux étiquettes :)
Joseph