¿Controlar el etiquetado basado en reglas usando PyQGIS?

15

Siguiendo con esta pregunta: Cómo activar / desactivar todas las etiquetas de todas las capas en QGIS , OP mencionó en su comentario que usa etiquetas basadas en reglas. Intenté buscar en línea cómo se podían leer y modificar estos tipos de etiquetas, pero solo logré encontrar esta publicación en lutraconsulting :

Para facilitar la adición de etiquetado basado en reglas, se realizaron algunos cambios internos en la interfaz del motor de etiquetado QGIS. El etiquetado ahora es impulsado por la nueva clase QgsLabelingEngineV2que puede tener varios proveedores de etiquetas asociados.

Suena genial. Sin embargo, al leer la clase QgsLabelingEngineV2 , menciona:

Esta clase aún no forma parte de una API pública.

¿Actualmente es posible controlar el etiquetado basado en reglas usando python?

José
fuente
1
Encontré un problema abierto aquí en el proyecto de documentación Qgis en Github que también menciona esto . No pude encontrar un enlace SIP para esa clase en las ramas MASTER o 2.18, por lo que sospecho que todavía solo está disponible para el código C ++.
Steven Kay
@StevenKay - Gran descubrimiento, gracias! Sería bastante útil si hicieran una API para ello ... También gracias por la edición, pensé que pegué el enlace correcto para la clase :)
Joseph
@StevenKay - Creo que hicieron una API para esto ahora, más específicamente la Clase QgsRuleBasedLabeling :)
Joseph

Respuestas:

6

A continuación, encontrará ayuda para configurar el etiquetado basado en reglas desde cero con la nueva 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()

Desafortunadamente, no puedo encontrar cómo iterar sobre las reglas existentes, el método labeling () disponible para capas vectoriales devuelve un objeto de la clase QgsAbstractVectorLayerLabeling , pero parece que no hay forma de obtener la regla raíz ( QgsRuleBasedLabeling ) de esta clase, la única posibilidad Lo que encontré es obtener configuraciones de pal directamente usando los identificadores de los proveedores, pero no puedo acceder al árbol de reglas. Alguien tiene una pista?

EDITAR

Ahora está arreglado, la función de etiquetado () devuelve un QgsRuleBasedLabeling (): https://github.com/qgis/QGIS/commit/4b365a8f47d96b35f7609859e580388927ae0606

domlysz
fuente
Gracias por su respuesta, bien trabajado! Espero que no te importe, pero edité tu publicación un poco para incluirla myLayer.triggerRepaint()para actualizar la capa y permitir que las etiquetas se muestren inmediatamente después de establecer las reglas :)
Joseph
3

Desde QGIS 3 , hay una nueva clase QgsRuleBasedLabeling que le permitiría controlar el etiquetado basado en reglas utilizando la nueva API.

Las reglas se pueden agregar usando QgsRuleBasedLabeling :: Rule .


( Desafortunadamente, no puedo probar la versión 2.99 en este momento. Pero me encantaría aceptar una respuesta si proporciona un ejemplo de trabajo ) .

José
fuente
1

Esto es lo que uso para cambiar una expresión de filtro en la simbología basada en reglas en QGIS 2.18, no estoy seguro de si eso es lo que está pidiendo. Referencia de API en 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
fuente
Gracias por tu respuesta, pero como dijiste, creo que esto solo se aplica a la simbología y no a las etiquetas :)
Joseph