Controlando a rotulagem baseada em regras usando o PyQGIS?

15

Na sequência desta pergunta: Como ativar / desativar todos os rótulos de todas as camadas no QGIS , o OP mencionou em seu comentário que ele usa rótulos baseados em regras. Tentei pesquisar on-line sobre como esses tipos de etiquetas podiam ser lidos e modificados, mas só consegui encontrar esta postagem na lutraconsulting :

Para facilitar a adição de rotulagem baseada em regras, algumas alterações internas foram feitas na interface do mecanismo de rotulagem QGIS. A rotulagem agora é direcionada pela nova classe, QgsLabelingEngineV2que pode ter vários fornecedores de etiquetas associados a ela.

Parece bom. No entanto, ao ler a classe QgsLabelingEngineV2 , ele menciona:

essa classe ainda não faz parte da API pública.

Atualmente, é possível controlar a rotulagem baseada em regras usando python?

Joseph
fonte
1
Encontrei um problema em aberto aqui no projeto de documentação Qgis no Github, que também menciona isso . Não consegui encontrar uma ligação SIP para essa classe nos ramos MASTER ou 2.18, então suspeito que ainda esteja disponível apenas para o código C ++.
9607 Steven Fay
@StevenKay - Ótima descoberta, obrigado! Seria muito útil se eles fizeram uma API para isso ... Também graças para a edição, eu pensei que eu colado o link correto para a classe :)
Joseph
@StevenKay - Eu acho que eles fizeram uma API para isso agora, mais especificamente a classe QgsRuleBasedLabeling :)
Joseph

Respostas:

6

Abaixo, ajuda para configurar a etiquetagem baseada em regras do zero com a nova API do 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()

Infelizmente, não consigo encontrar como iterar sobre as regras existentes, o método labeling () disponível para as camadas vetoriais retorna um objeto da classe QgsAbstractVectorLayerLabeling, mas parece que não há como obter a regra raiz ( QgsRuleBasedLabeling ) dessa classe, a única possibilidade Eu descobri que é para obter configurações diretamente do pal usando IDs de provedores, mas não consigo acessar a árvore de regras. Alguém tem uma pista?

EDITAR

Agora está corrigida, a função labeling () retorna um QgsRuleBasedLabeling (): https://github.com/qgis/QGIS/commit/4b365a8f47d96b35f7609859e580388927ae0606

domlysz
fonte
Obrigado pela sua resposta, muito bem elaborado! Espero que você não se importa, mas eu editei um pouco o seu post para incluir myLayer.triggerRepaint()para atualizar a camada e permitir que os rótulos para mostrar imediatamente depois de definir as regras :)
Joseph
3

No QGIS 3 , existe uma nova classe QgsRuleBasedLabeling que permite controlar a rotulagem baseada em regras usando a nova API.

Regras podem ser adicionadas usando QgsRuleBasedLabeling :: Rule .


( Infelizmente, não posso testar a versão 2.99 no momento. Mas aceitaria com satisfação uma resposta se ela fornecer um exemplo de trabalho. )

Joseph
fonte
1

É isso que eu uso para alterar uma expressão de filtro na simbologia baseada em regras no QGIS 2.18, não tenho certeza se é isso que você está pedindo. Referência da API em 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
fonte
Obrigado pela sua resposta, mas como você disse, acho que isso se aplica apenas a simbologia e não etiquetas :)
Joseph