Outils Python pour la gestion des couches QGis

Cet article complète la série d’articles sur la création d’une base de données geopackage pour gérer les cartes marines ENC sous QGis ainsi que la symbologie des différentes couches de données. Le travail avec un petit nombre de cartes ne présente pas de problème particulier, mais dès que le nombre augmente il y a une série d’opérations qui deviennent soit compliquées, soit consommatrices de temps de travail.
Nous avons mis au point une série de script Python qui simplifient le travail sur des bases de données geopackage importantes. Dans cet article ces outils sont appliqués à une base de données Geopackage de cartes marines, mais ils peuvent être utilisés pour tout geopackage moyennant quelques modifications qui ne nécessitent aucune connaissance particulière en programmation ni en Python.

1- Chargement des couches

Le premier problème qu’on rencontre réside dans le nombre important de couches à charger dans le projet QGis. En effet, si une carte peut avoir une vingtaine de couches, dès que le nombre de cartes augmente on peut rapidement se retrouver avec plus d’une centaine de couches à charger.

QGis permet de charger en bloc toutes les couches d’un geopackage. On n’est pas obligé alors de charger une par une la centaine de couches. Mais une fois chargées, il y a deux tâches à réaliser:

  • enlever les couches non pertinentes telles les couches de métadonnées
  • ordonner l’affichage des couches pour éviter que certaines couches ne soient pas complètement invisibles pour cause de superposition avec d’autres couches. Des couches surfaciques comme DEPARE et LNDARE (profondeurs et terrain) doivent toujours être en dessous des objets marins et terrestres, si non ces objets ne sont pas visibles.

De plus, c’est toujours plus agréable de travailler avec des échelles minimales d’affichage de manière à n’avoir que certaines couches quand on zoome à de très petites échelles et de n’avoir l’affichage des informations détaillées que quand on zoome à une échelle plus grande.

Sélection des couches à charger

Nous mettons à votre disposition un script python qui résout à lui tout seul l’ensemble de ces problèmes Vous pouvez le télécharger à partir de ce lien..

Le script comprend une liste de 210 couches S57, ordonnées pour un affichage correct:

Les couches surfaciques représentées par des polygones pleins, puis les couches surfaciques représentées par des polygones vides (seuls les périmètres sont affichés), puis les couches de type linéaire et finalement les couches de type ponctuel. A l’intérieur de chaque catégorie l’ordre a été étudié pour éviter les masquages d’information.

Chaque couche est accompagnée avec une valeur d’échelle minimale d’affichage, par défaut 100000000.

Exemple:

#Liste des couches dans l’ordre de chargement
couches_a_charger = [
(‘pl_DEPARE’, 100000000),
(‘pl_UNSARE’, 100000000),
(‘pl_TIDEWY’, 100000000),
(‘pl_DAMCON’, 100000000),

Pour que le script ne charge pas des couches qui ne vous intéressent pas, vous pouvez tout simplement mettre en commentaire la ligne correspondante en ajoutant un ‘#’ en début de ligne:

#Liste des couches dans l’ordre de chargement
couches_a_charger = [
(‘pl_DEPARE’, 100000000),
(‘pl_UNSARE’, 100000000),
#(‘pl_TIDEWY’, 100000000),
#(‘pl_DAMCON’, 100000000),

Dans cet exemple, les couches TIDEWY et DAMCON ne seront pas chargées.

De plus, si vous souhaitez définir une échelle minimale d’affichage pour une couche, il suffit de modifier la valeur correspondante:

‘pl_DEPARE’, 100000000),
(‘pl_UNSARE’, 100000000),
(‘pl_TIDEWY’, 100000),
#(‘pl_DAMCON’, 100000000),
(‘pl_OBSTRN’, 50000),

Dans cet exemple la couche TIDEWY ne sera affichée que quand le zoom de la fenêtre cartographique aura une valeur inférieure à 100000 et la couche OBSTRN quand la valeur sera inférieure à 50000.

Pour utiliser le script:

  • téléchargez le fichier.py,
  • enregistrez-le dans un répertoire de votre choix
  • Ouvrez la console Python de QGis (Extensions ->Console Python)

  • Ouvrez la fenêtre d’Éditeur (1)
  • Cliquez sur l’icône Parcourir (2) et pointez sur le fichier .py téléchargé
  • Modifiez le chemin du geopackage avec le chemin et nom de votre geopackage (3)
  • Exécutez le script (4)

Avant de l’exécuter vous pouvez effectuer les modifications pour ne pas charger des couches ou pour leur affecter une échelle minimale différente. N’oubliez pas d’enregistrer ces modifications avant de fermer votre projet.

Le code du script est le suivant:

load_layers.py

from qgis.core import QgsProject

# Chemin vers le geopackage
chemin_geopackage = 'c:/testgpkgV3/ENC2.gpkg'

## Liste des couches dans l'ordre de chargement
couches_a_charger = [
    ('pl_DEPARE', 100000000),
    ('pl_UNSARE', 100000000),
    ('pl_TIDEWY', 100000000),
    ('pl_DAMCON', 100000000),
    ('pl_CAUSWY', 100000000),
    ('pl_HULKES', 100000000),
    ('pl_LOKBSN', 100000000),
    ('pl_OBSTRN', 100000000),
    ('pl_PONTON', 100000000),
    ('pl_PYLONS', 100000000),
    ('pl_SBDARE', 100000000),
    ('pl_DRGARE', 100000000),
    ('pl_TSEZNE', 100000000),
    ('pl_WRECKS', 100000000),
    ('pl_FLODOC', 100000000),
    ('pl_LNDARE', 100000000),
    ('pl_CANALS', 100000000),
    ('pl_LAKARE', 100000000),
    ('pl_RIVERS', 100000000),
    ('pl_BUAARE', 100000000),
    ('pl_BUISLG', 100000000),
    ('pl_CHKPNT', 100000000),
    ('pl_CONVYR', 100000000),
    ('pl_DOCARE', 100000000),
    ('pl_ROADWY', 100000000),
    ('pl_RUNWAY', 100000000),
    ('pl_DRYDOC', 100000000),
    ('pl_DYKCON', 100000000),
    ('pl_FORSTC', 100000000),
    ('pl_GATCON', 100000000),
    ('pl_LNDMRK', 100000000),
    ('pl_SLCONS', 100000000),
    ('pl_BRIDGE', 100000000),
    ('pl_WEDKLP', 100000000),
    ('pl_WATTUR', 100000000),
    ('pl_VEGATN', 100000000),
    ('pl_TWRTPT', 100000000),
    ('pl_TUNNEL', 100000000),
    ('pl_TSSLPT', 100000000),
    ('pl_TESARE', 100000000),
    ('pl_SWPARE', 100000000),
    ('pl_SPLARE', 100000000),
    ('pl_SNDWAV', 100000000),
    ('pl_SMCFAC', 100000000),
    ('pl_SLOGRD', 100000000),
    ('pl_SILTNK', 100000000),
    ('pl_SEAARE', 100000000),
    ('pl_RESARE', 100000000),
    ('pl_RCTLPT', 100000000),
    ('pl_PRDARE', 100000000),
    ('pl_PRCARE', 100000000),
    ('pl_PIPARE', 100000000),
    ('pl_PILBOP', 100000000),
    ('pl_OSPARE', 100000000),
    ('pl_OFSPLF', 100000000),
    ('pl_MORFAC', 100000000),
    ('pl_MIPARE', 100000000),
    ('pl_MARCUL', 100000000),
    ('pl_LOGPON', 100000000),
    ('pl_LNDRGN', 100000000),
    ('pl_ISTZNE', 100000000),
    ('pl_ICEARE', 100000000),
    ('pl_HRBFAC', 100000000),
    ('pl_HRBARE', 100000000),
    ('pl_GRIDRN', 100000000),
    ('pl_FSHZNE', 100000000),
    ('pl_FSHGRD', 100000000),
    ('pl_FSHFAC', 100000000),
    ('pl_FRPARE', 100000000),
    ('pl_FERYRT', 100000000),
    ('pl_FAIRWY', 100000000),
    ('pl_EXEZNE', 100000000),
    ('pl_DWRTPT', 100000000),
    ('pl_DMPGRD', 100000000),
    ('pl_CTSARE', 100000000),
    ('pl_CTNARE', 100000000),
    ('pl_CBLARE', 100000000),
    ('pl_BERTHS', 100000000),
    ('pl_AIRARE', 100000000),
    ('pl_ADMARE', 100000000),
    ('pl_ACHBRT', 100000000),
    ('pl_ACHARE', 100000000),
    ('pl_CRANES', 100000000),
	('li_RAPIDS', 100000000),
	('li_MARCUL', 100000000),
	('li_FLODOC', 100000000),
	('li_LNDMRK', 100000000),
	('li_FERYRT', 100000000),
	('li_CBLSUB', 100000000),
	('li_COALNE', 100000000),
	('li_DEPARE', 100000000),
	('li_DEPCNT', 100000000),
	('li_LNDARE', 100000000),
	('li_RIVERS', 100000000),
	('li_SLCONS', 100000000),
	('li_PIPOHD', 100000000),
	('li_MAGVAR', 100000000),
	('li_RECTRC', 100000000),
	('li_PIPSOL', 100000000),
	('li_BRIDGE', 100000000),
	('li_CONVYR', 100000000),
	('li_SBDARE', 100000000),
	('li_LNDELV', 100000000),
	('li_SLOTOP', 100000000),
	('li_DAMCON', 100000000),
	('li_OBSTRN', 100000000),
	('li_RADLNE', 100000000),
	('li_RAILWY', 100000000),
	('li_ROADWY', 100000000),
	('li_CAUSWY', 100000000),
	('li_WATFAL', 100000000),
	('li_CBLOHD', 100000000),
	('li_TSSBND', 100000000),
	('li_WATTUR', 100000000),
	('li_MORFAC', 100000000),
	('li_GATCON', 100000000),
	('li_TSELNE', 100000000),
	('li_DYKCON', 100000000),
	('li_VEGATN', 100000000),
	('li_RUNWAY', 100000000),
	('li_FNCLNE', 100000000),
	('li_RDOCAL', 100000000),
	('li_STSLNE', 100000000),
	('li_NAVLNE', 100000000),
	('li_OILBAR', 100000000),
	('li_CANALS', 100000000),
	('li_FORSTC', 100000000),
	('li_DWRTCL', 100000000),
	('li_TIDEWY', 100000000),
	('li_TUNNEL', 100000000),
	('li_BERTHS', 100000000),
	('li_RCRTCL', 100000000),
	('li_FSHFAC', 100000000),
	('li_PONTON', 100000000),
	('pt_ROADWY', 100000000),
	('pt_BUAARE', 100000000),
	('pt_DMPGRD', 100000000),
	('pt_BOYCAR', 100000000),
	('pt_BOYSAW', 100000000),
	('pt_ACHARE', 100000000),
	('pt_BOYINB', 100000000),
	('pt_PILBOP', 100000000),
	('pt_OFSPLF', 100000000),
	('pt_BOYSPP', 100000000),
	('pt_FOGSIG', 100000000),
	('pt_LNDARE', 100000000),
	('pt_LNDELV', 100000000),
	('pt_SPLARE', 100000000),
	('pt_LNDRGN', 100000000),
	('pt_LIGHTS', 100000000),
	('pt_SILTNK', 100000000),
	('pt_WATTUR', 100000000),
	('pt_ICNARE', 100000000),
	('pt_MIPARE', 100000000),
	('pt_TS_TIS', 100000000),
	('pt_OBSTRN', 100000000),
	('pt_PILPNT', 100000000),
	('pt_RTPBCN', 100000000),
	('pt_SBDARE', 100000000),
	('pt_RETRFL', 100000000),
	('pt_SOUNDG', 100000000),
	('pt_TOPMAR', 100000000),
	('pt_HULKES', 100000000),
	('pt_LOGPON', 100000000),
	('pt_WEDKLP', 100000000),
	('pt_WRECKS', 100000000),
	('pt_NEWOBJ', 100000000),
	('pt_UWTROC', 100000000),
	('pt_AIRARE', 100000000),
	('pt_CURENT', 100000000),
	('pt_LNDMRK', 100000000),
	('pt_LOCMAG', 100000000),
	('pt_SEAARE', 100000000),
	('pt_LITFLT', 100000000),
	('pt_BOYISD', 100000000),
	('pt_CTNARE', 100000000),
	('pt_FSHFAC', 100000000),
	('pt_HRBFAC', 100000000),
	('pt_MORFAC', 100000000),
	('pt_VEGATN', 100000000),
	('pt_PIPSOL', 100000000),
	('pt_GATCON', 100000000),
	('pt_SMCFAC', 100000000),
	('pt_BUISGL', 100000000),
	('pt_BCNLAT', 100000000),
	('pt_BCNSPP', 100000000),
	('pt_CTRPNT', 100000000),
	('pt_FORSTC', 100000000),
	('pt_RDOSTA', 100000000),
	('pt_DAMCON', 100000000),
	('pt_LITVES', 100000000),
	('pt_BCNCAR', 100000000),
	('pt_RUNWAY', 100000000),
	('pt_PYLONS', 100000000),
	('pt_CGUSTA', 100000000),
	('pt_RCTLPT', 100000000),
	('pt_TS_FEB', 100000000),
	('pt_BRIDGE', 100000000),
	('pt_SPRING', 100000000),
	('pt_ACHBRT', 100000000),
	('pt_RDOCAL', 100000000),
	('pt_BOYLAT', 100000000),
	('pt_TS_PAD', 100000000),
	('pt_TS_PRH', 100000000),
	('pt_DISMAR', 100000000),
	('pt_SLOGRD', 100000000),
	('pt_SNDWAV', 100000000),
	('pt_PRDARE', 100000000),
	('pt_SISTAW', 100000000),
	('pt_RADSTA', 100000000),
	('pt_CRANES', 100000000),
	('pt_MARCUL', 100000000),
	('pt_BERTHS', 100000000),
	('pt_RSCSTA', 100000000),
	('pt_BCNSAW', 100000000),
	('pt_SISTAT', 100000000),
	('pt_SLCONS', 100000000),
	('pt_BCNISD', 100000000),
	('pt_DAYMAR', 100000000),
	('pt_WATFAL', 100000000)

    # Ajoutez d'autres noms de couche avec leur échelle minimale dans le même format
]

# Récupérer le projet en cours
projet = QgsProject.instance()

# Charger chaque couche dans l'ordre spécifié
for nom_couche, echelle_min in couches_a_charger:
    # Construire le chemin complet de la couche
    chemin_couche = '{}|layername={}'.format(chemin_geopackage, nom_couche)
    # Charger la couche
    couche = QgsVectorLayer(chemin_couche, nom_couche, 'ogr')
    # Vérifier si la couche est valide
    if couche.isValid():
        # Ajouter la couche au projet
        projet.addMapLayer(couche)
        # Définir l'échelle minimale pour la couche
        couche.setScaleBasedVisibility(True)
        couche.setMinimumScale(echelle_min)
        print(f"L'échelle d'affichage de la couche {nom_couche} a été définie sur {echelle_min}.")
    else:
        print("Impossible de charger la couche :", nom_couche)

print("Chargement des couches terminé.")

Gestion de l’échelle d’affichage

Le script précédent permet de définir une échelle minimum au moment du premier chargement des couches dans le projet. Quand vous sauvegardez votre projet, c’est la valeur présente dans le champ Min_scale de la couche qui est sauvegardé. A l’ouverture du projet, ce sont les paramètres d’affichage au moment de la fermeture du projet qui sont pris en comte. Vous n’utiliserez donc le script précédent qu’au début du travail sur un projet. Mais les échelles définies dans le script load_layers peuvent ne pas être adaptés à votre zone de travail. Vous pourrez donc être amené à modifier les valeurs d’échelle min pour certaines couches.

Nous mettons à votre disposition un script Python qui permet de définir l’échelle minimum d’affichage pour toutes les couches sélectionnées dans le panneau Couches. Une fois enregistré votre projet, ces paramètres seront utilisés à chaque ouverture du projet.

Pour l’utiliser, commencez par le charger dans la console Python de QGis, sélectionnez (mettez en surbrillance) les couches que vous souhaitez modifier dans le panneau Couches, et, surtout, modifiez la ligne

#Définir l’échelle minimale (par exemple, 1:50000)
min_scale = 250000

par la valeur souhaitée pour l’échelle minimale d’affichage.

Le script Python pour définir l’échelle minimum d’affichage des couches sélectionnées est le suivant:

setminscale.py

# Récupérer la vue des couches
layer_tree_view = iface.layerTreeView()

# Récupérer les couches sélectionnées
selected_layers = layer_tree_view.selectedLayers()

# Définir l'échelle minimale pour chaque couche sélectionnée
for layer in selected_layers:
    # Définir l'échelle minimale (par exemple, 1:50000)
    min_scale = 250000
    
    # Définir l'échelle minimale d'affichage pour la couche
    layer.setScaleBasedVisibility(True)
    layer.setMinimumScale(min_scale)
    print(f"L'échelle d'affichage de la couche {layer.name()} a été définie sur {min_scale}.")


[/stextbox]

Vous pouvez le télécharger ici.

Un script Python pour filtrer les couches par « purpose »

Les tables de votre geopackage comportent un attribut nommé « purpose » .C’est une valeur comprise entre 1 et 6 et qui correspond à l’objectif principal de la carte:

  • 1 : Vue d’ensemble
  • 2 : Généralités
  • 3 : Côtière
  • 4 : Approche
  • 5 : Port
  • 6 : Accostage

Si vous avez des cartes avec des finalités différentes qui couvrent une même zone, par exemple une carte de type Généralités et une carte de type Approche,vous aurez des informations en double. Si les entités de deux cartes ne sont pas de même type (une entité surfacique d’une carte Approche correspondra à une entité ponctuelle de la carte Généralités, par exemple) le rendu peut devenir rapidement très brouillon. La solution proposée est simple, appliquer un filtre aux couches du projet pour n’afficher que celles qui ont la même valeur de « purpose ». Pour filtrer l’affichage de toutes les couches chargées dans le projet QGis, vous pouvez utiliser le script suivant:

filter_purpose.py

# Importer le module QGIS
from qgis.core import QgsProject, QgsMapLayerType

# Définir le valeur de l’attribut « purpose » à filtrer
valeur_purpose = 3

# Obtenir le projet actif
projet = QgsProject.instance()

# Obtenir la liste des couches chargées dans le projet
couches = projet.mapLayers().values()

# Parcourir toutes les couches
for couche in couches:
# Vérifier si la couche est de type vecteur
if couche.type() == QgsMapLayerType.VectorLayer:
# Vérifier si la couche a un champ nommé « purpose »
if couche.fields().indexFromName(‘purpose’) != -1:
# Vérifier si le nom de la couche commence par l’un des préfixes spécifiés
if couche.name().startswith((‘pt_’, ‘li_’, ‘pl_’)):
# Définir le filtre sur l’attribut « purpose » égal à la valeur spécifiée
filtre = f' »purpose » = {valeur_purpose}’
couche.setSubsetString(filtre)
print(f »Filtre défini pour la couche {couche.name()} »)
else:
print(f »La couche {couche.name()} ne commence pas par ‘pt_’, ‘li_’, ou ‘pl_' »)
else:
print(f »La couche {couche.name()} n’a pas d’attribut ‘purpose' »)
else:
print(f »La couche {couche.name()} n’est pas une couche vecteur »)

Vous pouvez télécharger le script ici.

Chargez le script dans la console python, modifiez la ligne:

#Définir le valeur de l’attribut « purpose » à filtrer
valeur_purpose = 5

par la valeur de purpose souhaitée, puis exécutez le script. Toutes les couches présentes dans le panneau Couches du projet seront filtrées.

Si vous souhaitez utiliser ce script pour filtrer sur un autre attribut que purpose, simplement modifiez la ligne:

filtre = f' »purpose » = {valeur_purpose}’

en remplaçant f' »purpose » par f' »autre_attribut » .

Si vous voulez supprimer tous les filtres actifs sur toutes les couches du projet, le script suivant vous permet de le faire:

unfilter.py

# Importer le module QGIS
from qgis.core import QgsProject

# Obtenir le projet actif
projet = QgsProject.instance()

# Obtenir la liste des couches chargées dans le projet
couches = projet.mapLayers().values()

# Parcourir toutes les couches
for couche in couches:
    # Vérifier si la couche est une couche vectorielle
    if couche.type() == QgsMapLayer.VectorLayer:
        # Supprimer le filtre de la couche
        couche.setSubsetString('')
        print(f"Filtre supprimé pour la couche {couche.name()}")

Vous pouvez télécharger le script ici.

Si cet article vous a intéressé et que vous pensez qu'il pourrait bénéficier à d'autres personnes, n'hésitez pas à le partager sur vos réseaux sociaux en utilisant les boutons ci-dessous. Votre partage est apprécié !

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *