2 Scripts python

2.1 Scripter ses traitements

L’intérêt de sauvegarder ses traitements dans des scripts est la reproductibilité.

Que ce soit pour soi ou pour un tiers, immédiatement ou dans un temps plus ou moins long, avec les mêmes données ou avec d’autres.

Le script demande plus de temps de rédaction mais au final dès lors qu’il est réutilisé, les nombreux clics épargnés permettent de gagner du temps à un opérateur.

Il peut être fastidieux de reproduire une analyse 6 mois plus tard. Scripter permet de garder une trace écrite (et commentée !) de ce qui a été fait. Et donc de gagner du temps sur la nouvelle analyse.

QGIS fournit un éditeur de script accessible depuis la console python:

Lancer l’éditeur de script

Cela va faire apparaitre une fenêtre dans QGIS.

Editeur de script

L’éditeur de script fournit de nombreuses fonctionnalités facilitant la création de script python pour QGIS:

  • Charger un script
  • Édition dans un éditeur externe
  • Sauvegarde
  • Lancement
  • Copier/couper/coller
  • Recherche
  • Commenter/Décommenter
  • Inspecteur d’objet
  • Onglets
  • Autocomplétion
  • Coloration syntaxique

Fonctionnalités de l’éditeur de script

Quand un script est lancé, il est exécuté dans la console Python de QGIS.

Exécution d’un script

2.2 Création d’un script simple

Créons un script simple qui va trouver les stations de métro à moins de 1000 mètres de la gare de Lyon Part-Dieu.

2.2.1 Importation des bibliothèques

Pour réaliser notre tâche, nous allons avoir besoin d’accéder aux algorithmes de géotraitements et de certaines méthodes du projet QGIS.

# chargement des algorithmes de la boite à outils
import processing 
# chargement des méthodes spécifiques aux projets QGIS
from qgis.core import QgsProject

2.2.2 Chargement des données

Nous allons avoir besoin des couches des gares SNCF et des stations de métro TCL. Chargeons aussi les arrondissements de la ville de Lyon afin d’avoir un peu de contexte sur nos données.

## arrondissements
uri = "/home/niko/Téléchargements/lyon/arrondissements.shp"
arrondissements = iface.addVectorLayer(uri,"arrondissements", "ogr")

## gares
uri = "/home/niko/Téléchargements/lyon/gares_sncf.shp"
gares = iface.addVectorLayer(uri,"gares", "ogr")

## métros
uri = "/home/niko/Téléchargements/lyon/entrees_sorties_metro.shp"
metro = iface.addVectorLayer(uri,"entrees_sorties_metro", "ogr")

Chargement des couches

2.2.3 Contrôle des systèmes de référence de coordonnées

Nous allons faire des opérations sur la géométrie des entités, il faut vérifier que nos sources de données sont dans la même projection.

## Contrôle des projections

for layer in QgsProject.instance().mapLayers().values():
    crs = layer.crs().authid()
    print("{} : {}".format(layer.name(), crs))

Cette boucle va extraire les couches contenues dans l’instance du projet QGIS. La méthode mapLayers de l’instance du projet QGIS renvoie un tableau avec des informations sur les couches. Nous extrayons les valeurs contenues dans le tableau et pour chaque couche, nous appelons la méthode crs (qui renvoit le système de référence de coordonnées, *Coordinate Reference System – CRS –) et la méthode authid de l’objet crs qui retourne l’identifiant du système de référence de coordonnées.

Il apparaît qu’une couche n’est pas projetée en RGF93/Lambert93 comme les autres, il convient de la reprojeter.

Contrôle du SRC des couches

Note: Selon le catalogue utilisé (EPSG ou IGNF), la projection RGF93/Lambert93 pourra être désignée par EPSG:2154 ou IGNF:LAMB93.

## gares sncf n'est pas dans la même projection,
# il faut la reprojeter
gares_reproject = processing.runAndLoadResults(
    "native:reprojectlayer", 
    {'INPUT':gares,
    'TARGET_CRS':QgsCoordinateReferenceSystem('IGNF:LAMB93'),
    'OUTPUT':'TEMPORARY_OUTPUT'})['OUTPUT']

Une nouvelle couche portant le nom de Reprojeté a été chargée dans le projet.

Vérifions que notre opération s’est bien déroulée:

## Contrôle de l'opération
for layer in QgsProject.instance().mapLayers().values():
    crs = layer.crs().authid()
    print("{} : {}".format(layer.name(), crs))

Contrôle de la réussite du traitement

2.2.4 Extraction de la gare de la Part-Dieu

Pour cette étape, nous allons utiliser une expression que nous utiliserons avec l’algorithme Extract by expression. Les expressions sont un moyen puissant pour accomplir de nombreuses choses. Il est possible de les utiliser pour sélectionner des entités, générer des géométries, faire varier des styles.

La documentation de QGIS à propos des expressions est très riche.

# Extraction de la gare de Part-Dieu
expression = "nom = 'Gare de Lyon Part-Dieu'"
partdieu = processing.runAndLoadResults(
    "native:extractbyexpression",
    {'INPUT':gares_reproject, 
     'EXPRESSION': expression,
     'OUTPUT':'TEMPORARY_OUTPUT'})['OUTPUT']

Une fois notre gare extraite, nous pouvons créer notre zone tampon de 1000 mètres.

2.2.5 Création de la zone tampon

# Création d'un tampon de 500m
buffer_partdieu = processing.runAndLoadResults(
    "native:buffer", 
    {'INPUT':partdieu,
     'DISTANCE':1000,
     'SEGMENTS':5,
     'END_CAP_STYLE':0,
     'JOIN_STYLE':0,
     'MITER_LIMIT':2,
     'DISSOLVE':False,
     'OUTPUT':'TEMPORARY_OUTPUT'})['OUTPUT']

Comme cette couche produit de nouvelles données, il peut être intéressant de la visualiser.

Nous pouvons maintenant intersecter cette zone tampon avec la couche contenant les entrées et sorties de métro.

# Intersection des stations de métros
metro_1000m = processing.runAndLoadResults(
    "native:intersection", 
    {'INPUT':metro,
    'OVERLAY':buffer_partdieu,
    'INPUT_FIELDS':[],
    'OVERLAY_FIELDS':[],
    'OUTPUT':'TEMPORARY_OUTPUT'})['OUTPUT']

2.2.6 Renommer la couche finale

Pour renommer une couche nous devons l’identifier puis la retrouver dans la liste des couches portant le nom ‘Intersection’. Par chance, nous n’avons fait qu’une intersection, c’est donc le premier élément de la liste.

# Renommer la couche intersectée
## identifier la couche
project =  QgsProject.instance()
print(project.mapLayers())
for id, layer in project.mapLayers().items():
        print(layer.name())

## renommer
project.mapLayersByName('Intersection')[0].setName("metro_1000m")

Une fois renommée, il est plus facile de l’identifier pour la sauvegarder par exemple.

2.2.7 Sauvegarde de la couche

Pour sauvegarder la couche, nous allons utiliser la méthode QgsVectorLayerExporter.exportLayer.

Cette méthode attend 4 arguments:

  • la couche vectorielle
  • un chemin vers un fichier (appelé uri)
  • un fournisseur (qui gère les entrées/sorties) : ici ogr
  • un système de coordonnées

Note: OGR était un utilitaire permettant de lire et d’écrire dans des fichiers vectoriels. OGR a été intégré au projet GDAL mais le nom est resté.

# sauvegarder une couche 
## Sélectionner une couche par son nom (premier élément de la liste retourné)
layer = project.mapLayersByName('metro_1000m')[0]

# Chemin de sauvegarde via une chaîne de caractères
output_path="/home/niko/Téléchargements/lyon/metro1000m.gpkg"

## Appel de la méthode avec précision du fournisseur 'ogr' et du SRC cible (RGF93/L93)
QgsVectorLayerExporter.exportLayer(
                                layer = layer, 
                                uri = output_path, 
                                providerKey = 'ogr', 
                                destCRS = QgsCoordinateReferenceSystem('EPSG:2154'))

2.2.8 Exercice

Avec les données fournies, trouver les zones de Lyon qui répondent aux critères suivants:

  • à moins d’1 kilomètre d’un gare SNCF
  • à moins de 300 mètres d’une station de métro
  • à moins de 200 mètres d’un espace vert
  • à moins de 500 mètres d’une piscine

Quel arrondissement offre le plus de surface répondant à ces critères ?

Étapes:

  • chargement des données
  • contrôle des projection et reprojection si nécessaire
  • création des zones tampon
  • intersection des zones tampon
  • jointure des attributs par localisation
  • regroupement sur l’attribut “arrondissement”
  • calcul de la surface intéressante pour chaque arrondissement

2.3 Créer un algorithme de géotraitement à partir d’un script

Depuis QGIS 3.4, il est possible de créer de nouveaux algorithmes de géotraitements sous la forme de scripts Python. Ces algorithmes pourront être appelés depuis la boîte à outils Traitements de la même manière que ceux fournis nativement par QGIS.

Si un ensemble d’opération doit être répété régulièrement avec des nouveaux paramètres, il est pertinent de créer un outil qu’il est possible d’appeler depuis la boite à outils de traitements. Vous pouvez alors relancer le script en faisant varier aisément ses paramètres avec un meilleur confort (pas d’édition de code, liste des couches chargées, boite de dialogue pour la sortie).

Pour cela, nous allons partir d’un modèle de script afin de nous faciliter le travail.

Aller dans la boite à outils de traitement, et cliquez sur l’icône Python. Un menu déroulant doit apparaître, choisissez l’option “Créer un nouveau script depuis un modèle”.

Créer un nouveau script à l’aide d’un modèle

Une nouvelle fenêtre d’édition de script devrait s’ouvrir avec un modèle de script.

Nouveau script depuis modèle

Il contient déjà un certain nombre de lignes de code que nous allons pouvoir utiliser pour créer notre script paramétrable.

# -*- coding: utf-8 -*-

"""
***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************
"""

from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
                       QgsFeatureSink,
                       QgsProcessingException,
                       QgsProcessingAlgorithm,
                       QgsProcessingParameterFeatureSource,
                       QgsProcessingParameterFeatureSink)
from qgis import processing


class ExampleProcessingAlgorithm(QgsProcessingAlgorithm):
    """
    This is an example algorithm that takes a vector layer and
    creates a new identical one.

    It is meant to be used as an example of how to create your own
    algorithms and explain methods and variables used to do it. An
    algorithm like this will be available in all elements, and there
    is not need for additional work.

    All Processing algorithms should extend the QgsProcessingAlgorithm
    class.
    """

    # Constants used to refer to parameters and outputs. They will be
    # used when calling the algorithm from another algorithm, or when
    # calling from the QGIS console.

    INPUT = 'INPUT'
    OUTPUT = 'OUTPUT'

    def tr(self, string):
        """
        Returns a translatable string with the self.tr() function.
        """
        return QCoreApplication.translate('Processing', string)

    def createInstance(self):
        return ExampleProcessingAlgorithm()

    def name(self):
        """
        Returns the algorithm name, used for identifying the algorithm. This
        string should be fixed for the algorithm, and must not be localised.
        The name should be unique within each provider. Names should contain
        lowercase alphanumeric characters only and no spaces or other
        formatting characters.
        """
        return 'myscript'

    def displayName(self):
        """
        Returns the translated algorithm name, which should be used for any
        user-visible display of the algorithm name.
        """
        return self.tr('My Script')

    def group(self):
        """
        Returns the name of the group this algorithm belongs to. This string
        should be localised.
        """
        return self.tr('Example scripts')

    def groupId(self):
        """
        Returns the unique ID of the group this algorithm belongs to. This
        string should be fixed for the algorithm, and must not be localised.
        The group id should be unique within each provider. Group id should
        contain lowercase alphanumeric characters only and no spaces or other
        formatting characters.
        """
        return 'examplescripts'

    def shortHelpString(self):
        """
        Returns a localised short helper string for the algorithm. This string
        should provide a basic description about what the algorithm does and the
        parameters and outputs associated with it..
        """
        return self.tr("Example algorithm short description")

    def initAlgorithm(self, config=None):
        """
        Here we define the inputs and output of the algorithm, along
        with some other properties.
        """

        # We add the input vector features source. It can have any kind of
        # geometry.
        self.addParameter(
            QgsProcessingParameterFeatureSource(
                self.INPUT,
                self.tr('Input layer'),
                [QgsProcessing.TypeVectorAnyGeometry]
            )
        )

        # We add a feature sink in which to store our processed features (this
        # usually takes the form of a newly created vector layer when the
        # algorithm is run in QGIS).
        self.addParameter(
            QgsProcessingParameterFeatureSink(
                self.OUTPUT,
                self.tr('Output layer')
            )
        )

    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """

        # Retrieve the feature source and sink. The 'dest_id' variable is used
        # to uniquely identify the feature sink, and must be included in the
        # dictionary returned by the processAlgorithm function.
        source = self.parameterAsSource(
            parameters,
            self.INPUT,
            context
        )

        # If source was not found, throw an exception to indicate that the algorithm
        # encountered a fatal error. The exception text can be any string, but in this
        # case we use the pre-built invalidSourceError method to return a standard
        # helper text for when a source cannot be evaluated
        if source is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

        (sink, dest_id) = self.parameterAsSink(
            parameters,
            self.OUTPUT,
            context,
            source.fields(),
            source.wkbType(),
            source.sourceCrs()
        )

        # Send some information to the user
        feedback.pushInfo('CRS is {}'.format(source.sourceCrs().authid()))

        # If sink was not created, throw an exception to indicate that the algorithm
        # encountered a fatal error. The exception text can be any string, but in this
        # case we use the pre-built invalidSinkError method to return a standard
        # helper text for when a sink cannot be evaluated
        if sink is None:
            raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))

        # Compute the number of steps to display within the progress bar and
        # get features from source
        total = 100.0 / source.featureCount() if source.featureCount() else 0
        features = source.getFeatures()

        for current, feature in enumerate(features):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                break

            # Add a feature in the sink
            sink.addFeature(feature, QgsFeatureSink.FastInsert)

            # Update the progress bar
            feedback.setProgress(int(current * total))

        # To run another Processing algorithm as part of this algorithm, you can use
        # processing.run(...). Make sure you pass the current context and feedback
        # to processing.run to ensure that all temporary layer outputs are available
        # to the executed algorithm, and that the executed algorithm can send feedback
        # reports to the user (and correctly handle cancellation and progress reports!)
        if False:
            buffered_layer = processing.run("native:buffer", {
                'INPUT': dest_id,
                'DISTANCE': 1.5,
                'SEGMENTS': 5,
                'END_CAP_STYLE': 0,
                'JOIN_STYLE': 0,
                'MITER_LIMIT': 2,
                'DISSOLVE': False,
                'OUTPUT': 'memory:'
            }, context=context, feedback=feedback)['OUTPUT']

        # Return the results of the algorithm. In this case our only result is
        # the feature sink which contains the processed features, but some
        # algorithms may return multiple feature sinks, calculated numeric
        # statistics, etc. These should all be included in the returned
        # dictionary, with keys matching the feature corresponding parameter
        # or output names.
        return {self.OUTPUT: dest_id}

2.3.1 Modification du script

Le script importe un certain nombre de classes. Notamment les classes permettant les traitements et l’ajout de paramètres.

from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
                       QgsFeatureSink,
                       QgsProcessingException,
                       QgsProcessingAlgorithm,
                       QgsProcessingParameterFeatureSource,
                       QgsProcessingParameterFeatureSink)
from qgis import processing

Attention: pour QGIS 3.4, from qgis import processing devra être remplacé par import processing.

Ajoutez les classesQgsProcessingParameterVectorDestination et QgsProcessingParameterDistance aux imports depuis qgis.core

Le script fournit aussi une classe ExampleProcessingAlgorithm().

class ExampleProcessingAlgorithm(QgsProcessingAlgorithm):
     # Constants used to refer to parameters and outputs. They will be
    # used when calling the algorithm from another algorithm, or when
    # calling from the QGIS console.

    INPUT = 'INPUT'
    OUTPUT = 'OUTPUT'

 ### Définitions de fonctions

Le modèle fournit de nombreuses fonctions, nous n’allons en modifier que quelques unes.

Commençons par renommer notre algorithme avec le nom ProximiteAlgorithm(QgsProcessingAlgorithm).

class ProximiteAlgorithm(QgsProcessingAlgorithm):
    """
    Retourne les objets d'une couche à proximité d'une autre couche.
    """

Modifier les constantes:

    OUTPUT = 'OUTPUT'  # couche en sortie
    SOURCE = 'SOURCE'  # couche qui sera intersectée:
    SUPERPOSITION = 'SUPERPOSITION' # couche qui servira à créer le buffer 
    BUFFER_OUTPUT = 'BUFFER_OUTPUT' # stockage du buffer

Modifiez les méthodes suivantes pour adapter les chaînes de caractères à notre algorithme.

    def tr(self, string):
        """
        Returns a translatable string with the self.tr() function.
        """
        return QCoreApplication.translate('Processing', string)

    def createInstance(self):
        return ProximiteAlgorithm()

    def name(self):
        """
        Returns the algorithm name, used for identifying the algorithm. 
        """
        return 'proximite'

    def displayName(self):
        """
        Returns the translated algorithm name, which should be used for any
        user-visible display of the algorithm name.
        """
        return self.tr('Objets à proximité')

Il peut être utile de classer ses algorithmes dans des groupes spécifiques, la modification des méthodes groupet groupIdpermettent cela.

    def group(self):
        """
        Returns the name of the group this algorithm belongs to. This string
        should be localised.
        """
        return self.tr('Scripts PyQGIS')

    def groupId(self):
        """
        Returns the unique ID of the group this algorithm belongs to. This
        string should be fixed for the algorithm, and must not be localised.
        The group id should be unique within each provider. Group id should
        contain lowercase alphanumeric characters only and no spaces or other
        formatting characters.
        """
        return 'scriptspyqgis'

Laissez les autres méthodes inchangées et rendez-vous à la méthode initAlgorithm(). C’est cette méthode qui va permettre de récupérer les paramètres.

Nous allons avoir besoin de charger 2 couches vectorielles, récupérer la taille de la zone tampon et la destination du résultat.

Supprimez les lignes contenues dans InitAlgorithm et saisissez les nouvelles lignes suivantes:

    def initAlgorithm(self, config=None):
        """
        Initialisation de l'algorithme: définition des
        paramètres en entrée et en sortie
        """

        # Données source
        self.addParameter(
            QgsProcessingParameterFeatureSource(
                self.SOURCE,
                self.tr('Couche d\'intérêt'),
                [QgsProcessing.TypeVectorAnyGeometry]
            )
        )
        
        # Données superposées
        self.addParameter(
            QgsProcessingParameterFeatureSource(
                self.SUPERPOSITION,
                self.tr('Couche sur laquelle sera faite le tampon'),
                [QgsProcessing.TypeVectorAnyGeometry]
            )
        )
            
        # Distance du tampon
        self.addParameter(
            QgsProcessingParameterDistance(
                'BUFFERDIST',
                self.tr('Distance du tampon'),
                defaultValue = 1000.0,
                # Make distance units match the INPUT layer units:
                parentParameterName='SUPERPOSITION'
            )
        )
        # Récupération de la destination.
        self.addParameter(
            QgsProcessingParameterVectorDestination(
                self.OUTPUT,
                self.tr('Sortie')
            )
        )

Le paramètre parentParameterName permet d’hériter de certaines informations d’un autre paramètre. Dans cet exemple, le tampon sera créé avec les mêmes unités de mesures que la couche passée dans le paramètre `SUPERPOSITION’. Notre couche étant en RGF93/Lambert93, le tampon sera calculé en mètres.

Une fois nos paramètres obtenus, nous pouvons passer à l’algorithme. Pour cela, nous devons modifier la méthode processAlgorithm.

Dans un premier temps, nous récupérons les informations concernant le fichier de sortie outputFile et de la taille du tampon bufferdist.

Puis nous insérons le traitement de la zone tampon puis celui faisant l’intersection entre la couche source et la zone tampon.

Enfin le résultat est retourné.

    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """

        # récupération des paramètres
        source = self.parameterAsSource(parameters, self.SOURCE, context)
        superposition = self.parameterAsSource(parameters, self.SUPERPOSITION, context)
        outputFile = self.parameterAsOutputLayer(parameters,self.OUTPUT, context)
        bufferdist = self.parameterAsDouble(parameters, 'BUFFERDIST', context)

        # Vérification qu'il y a bien deux couches en entrée
        # des erreurs sont levées si une couche est manquante
        if source is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.SOURCE))
        if superposition is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.SUPERPOSITION))

        # Il est possible d'afficher des informations
        # à destination de l'utilisateur
        feedback.pushInfo('Source CRS is {}'.format(source.sourceCrs().authid()))
        feedback.pushInfo('Superposition CRS is {}'.format(superposition.sourceCrs().authid()))

        # Vérification que les couches ont un SRC compatibles
        if source.sourceCrs().authid() != superposition.sourceCrs().authid():
            # Si SRC différents, QGIS lève une exception et arrête l'algorithme.
            raise QgsProcessingException(
                    self.tr('les couches doivent être dans le même système de référence de coordonnées.')
                    )
                    
        # Calcul du tampon            
        tampon = processing.run(
            "native:buffer",{
                'INPUT': parameters['SUPERPOSITION'],
                'DISTANCE' : bufferdist,
                'SEGMENTS' :5,
                'END CAP STYLE' : 0,
                'JOIN STYLE': 0,
                'MITER LIMIT' :2,
                'DISSOLVE' : False,
                'OUTPUT' : 'TEMPORARY_OUTPUT'
                },
            context=context,
            feedback=feedback)
            
        ## Intersection du tampon et de la couche source
        intersection = processing.run(
                "native:intersection", 
                {'INPUT': parameters['SOURCE'],
                'OVERLAY': tampon['OUTPUT'],
                'INPUT_FIELDS':[],
                'OVERLAY_FIELDS':[],
                'OUTPUT':outputFile})['OUTPUT']

        
        # Return the results of the algorithm. In this case our only result is
        # the intersection.
        return {self.OUTPUT: intersection}

Attention: suivant la version de QGIS, 'TEMPORARY_BUFFER' devra être remplacer par 'BUFFER_OUTPUT'.

2.3.2 Test du script

Tester votre script avec les couches suivantes:

  • entrees_sorties_metro
  • gare_partdieu
    • extraction de la gare de la Part-Dieu
    • reprojection en 2154
    • à préparer avant de lancer l’algorithme
  • taille du tampon: 1000 mètres

Depuis l’outil de script, cliquez sur la flèche verte pour lancer le script.

Lancement du script

Le script doit fournir une interface utilisable:

Interface de l’outil

Le résultat devrait ressembler à cela:

Résultat du traitement

2.3.3 Ajout du script dans la boite à outils

Maintenant que nous avons un script fonctionnel, nous pouvons l’ajouter à la boite à outil pour le réutiliser quand nous en aurons besoin.

Pour cela, depuis la boite à outils, dépliez le menu déroulant situé sous l’icône Python. Cliquez sur Ajouter un script à la boite à outils

Ajouter un script à la boite à outils

Puis allez chercher le script proximite.py et cliquez sur Ouvrir.

Charger le script proximite.py

Le script est maintenant accessible depuis la boite à outils, depuis le menu Scripts -> Scripts PyQGIS.

Script Objets à proximité disponible dans la boite à outils.

Pour plus d’informations sur la manière d’écrire des scripts dans le QGIS user manual

Il est possible d’écrire des scripts plus courts, à l’aide du décorateur @alg néanmoins les scripts utilisant les décorateurs ne peuvent être utilisés qu’à travers la boîte à outils Traitements. Il n’est alors pas possible de les utiliser dans un plugin.

2.3.4 Exercice

A partir d’un modèle, créez l’outil permettant de définir la zone la plus propice suivant les critères vus précédemment (distances aux métros, piscines, gares, etc.).

Le script prend en entrée 4 couches vectorielles et pour chaque couche une distance en mètres.

Par commodité, ne fournissez que des couches dans la même projection.

Le script fournit en résultat une couche intersectant tous les tampons.

2.4 Depuis le modeleur

Il est possible d’exporter un modèle de traitement vers du code Python. Toutefois cette fonctionnalité a été désactivée lors du passage à QGIS 3.0 et n’a été réactivé qu’à partir de QGIS 3.6.

Cette fonctionnalité n’est pas abordée dans ce cours. Essayez-la !