Index de l'article

Affichage personnalisé des attributs

Un autre exemple avec 3 fonctions séparées, dont une pour afficher les attributs de la couche dans un dock personnalisé.

Vous avez de grosses couches, ou plutôt des couches avec énormément d'entités, beaucoup de champs... ce qui rend votre projet peu lisible.
Ces couches sont liées entre elles par id. Il est possible de conditionner l'affichage des entités d'une couche sur un clic d'une entité d'une autre couche.
Le code suivant va va masquer les entités tierces, puis les filtrer et enfin zoomer sur l'entité cliquée, tout en affichant certains de ses attributs.

from qgis.PyQt.QtWidgets import QDockWidget, QTextEdit
from qgis.PyQt.QtCore import Qt, QTimer
 
layerA = QgsProject.instance().mapLayersByName("Ma couche A")[0]
layerB = QgsProject.instance().mapLayersByName("Ma couche B")[0]
 
# Cacher B par défaut
layer_tree = QgsProject.instance().layerTreeRoot().findLayer(layerB.id())
if layer_tree is not None:
    layer_tree.setItemVisibilityChecked(False)

 

# Dock d'affichage
dock = QDockWidget("Attributs de la couche A", iface.mainWindow())
dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
 
text_edit = QTextEdit()
text_edit.setReadOnly(True)
dock.setWidget(text_edit)
iface.addDockWidget(Qt.RightDockWidgetArea, dock)
dock.hide()

 

# Fonction affichage des attributs
def displayAttributes(features, layer):
    if not features:
        dock.hide()
        return
 
    feat = features[0]
    attrs = feat.attributes()
    fields = layer.fields()
 
    data = {field.name(): attrs[i] for i, field in enumerate(fields)}
 
    groupsFields = {
    "ID": {"id_a": "ID A", "foreign_key_layer_b": "Clé B"}, \
    "Bla bla bla...": {"area": "Surface", "len": "Longueur"}, \
    "Bla bla bla...": {"blablafield": "Igo", "anotherblablafield": "Wesh"}}
 
    used_fields = set()
 
    msg = ""
    for titre, champs in groupsFields.items():
        msg += f"{titre}"
        for champ, label in champs.items():
            valeur = data.get(champ, "–")
            msg += f"- {label}: {valeur}"
            used_fields.add(champ)
        msg += "BR"
 
    autres_champs = [k for k in data.keys() if k not in used_fields]
    if autres_champs:
        msg += "Champs restants"
        for champ in autres_champs:
            msg += f"- {champ}: {data[champ]}"
 
    text_edit.setHtml(msg)
    dock.show()

 

# Fonction zoom
def zoom_after_delay():
    matching_features = list(layerB.getFeatures())
    if not matching_features:
        return
 
    extent = matching_features[0].geometry().boundingBox()
    for f in matching_features[1:]:
        extent.combineExtentWith(f.geometry().boundingBox())
 
    if extent.isEmpty():
        return
 
    extent_buffered = extent.buffered(extent.width() * 0.1)
    iface.mapCanvas().setExtent(extent_buffered)
    iface.mapCanvas().refresh()
    iface.mapCanvas().update()

 

# Fonction filtre
def custom_filter():
    selected_features = layerA.selectedFeatures()
 
    displayAttributes(selected_features, layerA)
 
    if not selected_features:
        layerB.setSubsetString("")
        if layer_tree is not None:
            layer_tree.setItemVisibilityChecked(False)
        return
 
    # Filtrer "Ma couche B" à partir de "Ma couche A"
    id_cads = [f['foreign_key_layer_b'] for f in selected_features]
 
    if len(id_cads) == 1:
        expr = f"id_b = '{id_cads[0]}'"
    else:
        id_cads_str = ", ".join(f"'{id}'" for id in id_cads)
        expr = f"id_b IN ({id_cads_str})"
 
    layerB.setSubsetString(expr)
    if layer_tree is not None:
        layer_tree.setItemVisibilityChecked(True)
 
    QTimer.singleShot(50, zoom_after_delay)

 

layerA.selectionChanged.connect(custom_filter)

 

Liens ou pièces jointes
Télécharger ce fichier (data_BDTOPO_V3_Dep05_adresse.zip)data_BDTOPO_V3_Dep05_adresse.zip[ ]3889 Ko
Télécharger ce fichier (data_IRIS_2019.zip)data_IRIS_2019.zip[ ]45905 Ko
Télécharger ce fichier (decathlon_france.zip)decathlon_france.zip[308 magasins Décathlon français depuis OSM le 27 décembre 2020]11 Ko
Télécharger ce fichier (glaciers.zip)glaciers.zip[ ]231 Ko
Télécharger ce fichier (iso_iris.zip)iso_iris.zip[Des zones isochrones à 15 minutes autour de 308 POIs.]12125 Ko
Télécharger ce fichier (Koln GML.zip)Koln gml.zip[ ]2818 Ko
Télécharger ce fichier (peaks.zip)peaks.zip[ ]14 Ko
Télécharger ce fichier (peaks_selection.zip)peaks_selection.zip[ ]1 Ko
Télécharger ce fichier (simple_countries.zip)simple_countries.zip[ ]1880 Ko
Accéder à cette adresse URL (https://hg-map.fr/extern/data/shapes/france/sol.zip)sol.zip[ ]0 Ko
Accéder à cette adresse URL (https://hg-map.fr/extern/data/shapes/france/TRONCON_HYDROGRAPHIQUE.zip)TRONCON_HYDROGRAPHIQUE.zip[ ]0 Ko
Accéder à cette adresse URL (https://hg-map.fr/extern/data/shapes/france/TRONCON_ROUTE.zip)TRONCON_ROUTE.zip[ ]0 Ko
Accéder à cette adresse URL (https://hg-map.fr/extern/data/shapes/france/TRONCON_VOIE_FERREE.zip)TRONCON_VOIE_FERREE.zip[ ]0 Ko
Télécharger ce fichier (World Stats.xlsx)World Stats[ ]27 Ko