Les extraits de code sur cette page nécessitent les importations suivantes si vous êtes en dehors de la console pyqgis :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from qgis.core import (
  QgsApplication,
  QgsDataSourceUri,
  QgsCategorizedSymbolRenderer,
  QgsClassificationRange,
  QgsPointXY,
  QgsProject,
  QgsExpression,
  QgsField,
  QgsFields,
  QgsFeature,
  QgsFeatureRequest,
  QgsFeatureRenderer,
  QgsGeometry,
  QgsGraduatedSymbolRenderer,
  QgsMarkerSymbol,
  QgsMessageLog,
  QgsRectangle,
  QgsRendererCategory,
  QgsRendererRange,
  QgsSymbol,
  QgsVectorDataProvider,
  QgsVectorLayer,
  QgsVectorFileWriter,
  QgsWkbTypes,
  QgsSpatialIndex,
)

from qgis.core.additions.edit import edit

from qgis.PyQt.QtGui import (
    QColor,
)

6. Utilisation de couches vectorielles

Cette section résume les diverses actions possibles sur les couches vectorielles.

La plupart des exemples de cette section sont basés sur des méthodes de la classe <qgis.core.QgsVectorLayer>

6.1. Récupérer les informations relatives aux attributs

Vous pouvez récupérer les informations associées aux champs d’une couche vecteur en appelant la méthode fields() d’un objet QgsVectorLayer

vlayer = QgsVectorLayer("testdata/airports.shp", "airports", "ogr")
for field in vlayer.fields():
    print(field.name(), field.typeName())
1
2
3
4
5
ID Integer64
fk_region Integer64
ELEV Real
NAME String
USE String

6.2. Itérer sur une couche vecteur

Parcourir les enregistrement d’une couche vecteur est l’une des tache les plus basique. L’exemple de code ci dessous vous montre comment le faire pour montrer quelques informations de chaque enregistrement. Ici, la variable layer doit être une instance de l’objet QgsVectorLayer.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# "layer" is a QgsVectorLayer instance
layer = iface.activeLayer()
features = layer.getFeatures()

for feature in features:
    # retrieve every feature with its geometry and attributes
    print("Feature ID: ", feature.id())
    # fetch geometry
    # show some information about the feature geometry
    geom = feature.geometry()
    geomSingleType = QgsWkbTypes.isSingleType(geom.wkbType())
    if geom.type() == QgsWkbTypes.PointGeometry:
        # the geometry type can be of single or multi type
        if geomSingleType:
            x = geom.asPoint()
            print("Point: ", x)
        else:
            x = geom.asMultiPoint()
            print("MultiPoint: ", x)
    elif geom.type() == QgsWkbTypes.LineGeometry:
        if geomSingleType:
            x = geom.asPolyline()
            print("Line: ", x, "length: ", geom.length())
        else:
            x = geom.asMultiPolyline()
            print("MultiLine: ", x, "length: ", geom.length())
    elif geom.type() == QgsWkbTypes.PolygonGeometry:
        if geomSingleType:
            x = geom.asPolygon()
            print("Polygon: ", x, "Area: ", geom.area())
        else:
            x = geom.asMultiPolygon()
            print("MultiPolygon: ", x, "Area: ", geom.area())
    else:
        print("Unknown or invalid geometry")
    # fetch attributes
    attrs = feature.attributes()
    # attrs is a list. It contains all the attribute values of this feature
    print(attrs)
    # for this test only print the first feature
    break
Feature ID:  1
Point:  <QgsPointXY: POINT(7 45)>
[1, 'First feature']

6.3. Sélection des entités

Dans QGIS Desktop, vous pouvez sélectionner des enregistrements de différentes façons : vous pouvez cliquer sur un objet, dessiner un rectangle sur la carte ou encore filtrer une couche avec des expressions. Les objets sélectionnés apparaissent normalement en surbrillance dans une couleur différente (le jaune par défaut) pour permettre à l’utilisateur de les distinguer.

Parfois, il peut être utile de sélectionner des enregistrement à l’aide de code ou de changer la couleur de sélection par défaut.

pour sélectionner tous les enregistrement d’une couche vecteur, vous pouvez utiliser la méthode selectAll()

# Get the active layer (must be a vector layer)
layer = iface.activeLayer()
layer.selectAll()

Pour séléctionner des enregistrement à l’aide d’une expression, utilisez la méthode selectByExpression()

# Assumes that the active layer is points.shp file from the QGIS test suite
# (Class (string) and Heading (number) are attributes in points.shp)
layer = iface.activeLayer()
layer.selectByExpression('"Class"=\'B52\' and "Heading" > 10 and "Heading" <70', QgsVectorLayer.SetSelection)

Pour changer la couleur par défaut des objets séléctionnés, vous pouvez utiliser la méthode setSelectionColor() de la classe QgsMapCanvas, comme montré dans l’exemple suivant :

iface.mapCanvas().setSelectionColor( QColor("red") )

Pour ajouter des enregistrement à ceux déjà séléctionésn vous pouvez appeler la méthode select() en lui passant une liste d’ID d’enregistrements :

1
2
3
4
5
6
7
8
9
selected_fid = []

# Get the first feature id from the layer
for feature in layer.getFeatures():
    selected_fid.append(feature.id())
    break

# Add these features to the selected list
layer.select(selected_fid)

Pour vider votre sélection :

layer.removeSelection()

6.3.1. Accès aux attributs

Les attributs peuvent être invoqués par leur nom :

print(feature['name'])
First feature

D’une autre façon, les attributs peuvent être invoqués par le ID. Cette méthode est légèrement plus rapide que d’utiliser le nom. Par exemple, pour récupérer le second attribut :

print(feature[1])
First feature

6.3.2. Itérer sur une sélection d’entités

Si vous avez besoin uniquement de sélectionner des enregistrements, vous pouvez utiliser la méthode selectedFeatures() depuis une couche vecteur :

selection = layer.selectedFeatures()
for feature in selection:
    # do whatever you need with the feature
    pass

6.3.3. Itérer sur un sous-ensemble d’entités

Si vous voulez parcourir un sous ensemble d’enregistrements d’une couche, ar exemple avec sur une zone donnée, vous devez ajouter une classe QgsFeatureRequest à l’appel de la méthode getFeatures(). Par exemple :

1
2
3
4
5
6
7
areaOfInterest = QgsRectangle(450290,400520, 450750,400780)

request = QgsFeatureRequest().setFilterRect(areaOfInterest)

for feature in layer.getFeatures(request):
    # do whatever you need with the feature
    pass

Pour des questions de rapidité, la recherche d’intersection est souvent réalisée à partir du rectangle d’encombrement minimum des objets. Il existe toutefois l’option ExactIntersect qui permet de s’assurer que seul les objets intersectés soit renvoyés.

request = QgsFeatureRequest().setFilterRect(areaOfInterest) \
                             .setFlags(QgsFeatureRequest.ExactIntersect)

Avec la méthode setLimit(), vous pouvez limiter le nombre d’enregistrement sélectionnés. Par exemple :

request = QgsFeatureRequest()
request.setLimit(2)
for feature in layer.getFeatures(request):
    print(feature)
<qgis._core.QgsFeature object at 0x7f9b78590948>

Si vous avez besoin d’un filtre basé sur des attributs à la place (ou en plus) d’un filtre spatial, comme montré dans les exemples précédents, vous pouvez construire un objet QgsExpression et le passer à la classe constructeur QgsFeatureRequest :

# The expression will filter the features where the field "location_name"
# contains the word "Lake" (case insensitive)
exp = QgsExpression('location_name ILIKE \'%Lake%\'')
request = QgsFeatureRequest(exp)

Vous pouvez vous référer à la section Expressions, Filtrage et Calcul de valeurs pour plus de détails sur la syntaxe employée dans QgsExpression.

La requête peut être utilisée pour définir les données à récupérer de chaque entité, de manière à ce que l’itérateur ne retourne que des données partielles pour toutes les entités.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Only return selected fields to increase the "speed" of the request
request.setSubsetOfAttributes([0,2])

# More user friendly version
request.setSubsetOfAttributes(['name','id'],layer.fields())

# Don't return geometry objects to increase the "speed" of the request
request.setFlags(QgsFeatureRequest.NoGeometry)

# Fetch only the feature with id 45
request.setFilterFid(45)

# The options may be chained
request.setFilterRect(areaOfInterest).setFlags(QgsFeatureRequest.NoGeometry).setFilterFid(45).setSubsetOfAttributes([0,2])

6.4. Modifier des couches vecteur

La plupart des sources vectorielles supportent les fonctions d’édition. Parfois, ces possibilités sont limitées. Vous pouvez utiliser la fonction capabilities() pour voir quelles fonctionnalités sont supportées.

caps = layer.dataProvider().capabilities()
# Check if a particular capability is supported:
if caps & QgsVectorDataProvider.DeleteFeatures:
    print('The layer supports DeleteFeatures')
The layer supports DeleteFeatures

Pour une liste complète des possibilités, merci de se référer à la documentation de l’API QgsVectorDataProvider.

Pour afficher les possibilités d’édition d’une couche dans une liste séparé par des virgules, vous pouvez utiliser la méthode capabilitiesString() comme montré dans l’exemple suivant :

1
2
3
4
5
6
caps_string = layer.dataProvider().capabilitiesString()
# Print:
# 'Add Features, Delete Features, Change Attribute Values, Add Attributes,
# Delete Attributes, Rename Attributes, Fast Access to Features at ID,
# Presimplify Geometries, Presimplify Geometries with Validity Check,
# Transactions, Curved Geometries'

En utilisant l’une des méthodes qui suivent pour l’édition de couches vectorielles, les changements sont directement validés dans le dispositif de stockage d’informations sous-jacent (base de données, fichier, etc.). Si vous désirez uniquement faire des changements temporaires, passez à la section suivante qui explique comment réaliser des modifications à l’aide d’un tampon d’édition.

Note

Si vous travaillez dans QGIS (soit à partir de la console, soit à partir d’une extension), il peut être nécessaire de forcer la mise à jour du canevas de cartes pour pouvoir voir les changements que vous avez effectués aux géométries, au style ou aux attributs

1
2
3
4
5
6
# If caching is enabled, a simple canvas refresh might not be sufficient
# to trigger a redraw and you must clear the cached image for the layer
if iface.mapCanvas().isCachingEnabled():
    layer.triggerRepaint()
else:
    iface.mapCanvas().refresh()

6.4.1. Ajout d’Entités

Create some QgsFeature instances and pass a list of them to provider’s addFeatures() method. It will return two values: result (true/false) and list of added features (their ID is set by the data store).

To set up the attributes of the feature, you can either initialize the feature passing a QgsFields object (you can obtain that from the fields() method of the vector layer) or call initAttributes() passing the number of fields you want to be added.

1
2
3
4
5
6
7
8
if caps & QgsVectorDataProvider.AddFeatures:
    feat = QgsFeature(layer.fields())
    feat.setAttributes([0, 'hello'])
    # Or set a single attribute by key or by index:
    feat.setAttribute('name', 'hello')
    feat.setAttribute(0, 'hello')
    feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(123, 456)))
    (res, outFeats) = layer.dataProvider().addFeatures([feat])

6.4.2. Suppression d’Entités

To delete some features, just provide a list of their feature IDs.

if caps & QgsVectorDataProvider.DeleteFeatures:
    res = layer.dataProvider().deleteFeatures([5, 10])

6.4.3. Modifier des Entités

It is possible to either change feature’s geometry or to change some attributes. The following example first changes values of attributes with index 0 and 1, then it changes the feature’s geometry.

1
2
3
4
5
6
7
8
9
fid = 100   # ID of the feature we will modify

if caps & QgsVectorDataProvider.ChangeAttributeValues:
    attrs = { 0 : "hello", 1 : 123 }
    layer.dataProvider().changeAttributeValues({ fid : attrs })

if caps & QgsVectorDataProvider.ChangeGeometries:
    geom = QgsGeometry.fromPointXY(QgsPointXY(111,222))
    layer.dataProvider().changeGeometryValues({ fid : geom })

Astuce

Favor QgsVectorLayerEditUtils class for geometry-only edits

If you only need to change geometries, you might consider using the QgsVectorLayerEditUtils which provides some useful methods to edit geometries (translate, insert or move vertex, etc.).

6.4.4. Modifier des couches vecteur à l’aide d’un tampon d’édition

When editing vectors within QGIS application, you have to first start editing mode for a particular layer, then do some modifications and finally commit (or rollback) the changes. All the changes you make are not written until you commit them — they stay in layer’s in-memory editing buffer. It is possible to use this functionality also programmatically — it is just another method for vector layer editing that complements the direct usage of data providers. Use this option when providing some GUI tools for vector layer editing, since this will allow user to decide whether to commit/rollback and allows the usage of undo/redo. When changes are commited, all changes from the editing buffer are saved to data provider.

The methods are similar to the ones we have seen in the provider, but they are called on the QgsVectorLayer object instead.

For these methods to work, the layer must be in editing mode. To start the editing mode, use the startEditing() method. To stop editing, use the commitChanges() or rollBack() methods. The first one will commit all your changes to the data source, while the second one will discard them and will not modify the data source at all.

To find out whether a layer is in editing mode, use the isEditable() method.

Here you have some examples that demonstrate how to use these editing methods.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from qgis.PyQt.QtCore import QVariant

feat1 = feat2 = QgsFeature(layer.fields())
fid = 99
feat1.setId(fid)

# add two features (QgsFeature instances)
layer.addFeatures([feat1,feat2])
# delete a feature with specified ID
layer.deleteFeature(fid)

# set new geometry (QgsGeometry instance) for a feature
geometry = QgsGeometry.fromWkt("POINT(7 45)")
layer.changeGeometry(fid, geometry)
# update an attribute with given field index (int) to a given value
fieldIndex =1
value ='My new name'
layer.changeAttributeValue(fid, fieldIndex, value)

# add new field
layer.addAttribute(QgsField("mytext", QVariant.String))
# remove a field
layer.deleteAttribute(fieldIndex)

In order to make undo/redo work properly, the above mentioned calls have to be wrapped into undo commands. (If you do not care about undo/redo and want to have the changes stored immediately, then you will have easier work by editing with data provider.)

Here is how you can use the undo functionality:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
layer.beginEditCommand("Feature triangulation")

# ... call layer's editing methods ...

if problem_occurred:
  layer.destroyEditCommand()
  # ... tell the user that there was a problem
  # and return

# ... more editing ...

layer.endEditCommand()

The beginEditCommand() method will create an internal « active » command and will record subsequent changes in vector layer. With the call to endEditCommand() the command is pushed onto the undo stack and the user will be able to undo/redo it from GUI. In case something went wrong while doing the changes, the destroyEditCommand() method will remove the command and rollback all changes done while this command was active.

Vous pouvez également utiliser le: code: with edit (layer) -déclaration pour envelopper l’acceptation et l’annulation dans un bloc de code plus sémantique comme illustré dans l’exemple ci-dessous:

with edit(layer):
  feat = next(layer.getFeatures())
  feat[0] = 5
  layer.updateFeature(feat)

This will automatically call commitChanges() in the end. If any exception occurs, it will rollBack() all the changes. In case a problem is encountered within commitChanges() (when the method returns False) a QgsEditError exception will be raised.

6.4.5. Ajout et Suppression de Champs

Pour ajouter des champs (attributs) vous devez indiquer une liste de définitions de champs. Pour la suppression de champs, fournissez juste une liste des index des champs.

1
2
3
4
5
6
7
8
9
from qgis.PyQt.QtCore import QVariant

if caps & QgsVectorDataProvider.AddAttributes:
    res = layer.dataProvider().addAttributes(
        [QgsField("mytext", QVariant.String),
        QgsField("myint", QVariant.Int)])

if caps & QgsVectorDataProvider.DeleteAttributes:
    res = layer.dataProvider().deleteAttributes([0])
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Alternate methods for removing fields
# first create temporary fields to be removed (f1-3)
layer.dataProvider().addAttributes([QgsField("f1",QVariant.Int),QgsField("f2",QVariant.Int),QgsField("f3",QVariant.Int)])
layer.updateFields()
count=layer.fields().count() # count of layer fields
ind_list=list((count-3, count-2)) # create list

# remove a single field with an index
layer.dataProvider().deleteAttributes([count-1])

# remove multiple fields with a list of indices
layer.dataProvider().deleteAttributes(ind_list)

Après l’ajout ou la suppression de champs dans le pilote de données, les champs de la couche doivent être rafraîchis car les changements ne sont pas automatiquement propagés.

layer.updateFields()

Astuce

Directly save changes using with based command

Using with edit(layer): the changes will be commited automatically calling commitChanges() at the end. If any exception occurs, it will rollBack() all the changes. See Modifier des couches vecteur à l’aide d’un tampon d’édition.

6.5. Utilisation des index spatiaux

Les index spatiaux peuvent améliorer fortement les performances de votre code si vous réalisez de fréquentes requêtes sur une couche vecteur. Imaginez par exemple que vous écrivez un algorithme d’interpolation et que pour une position donnée, vous devez déterminer les 10 points les plus proches dans une couche de points, dans l’objectif d’utiliser ces points pour calculer une valeur interpolée. Sans index spatial, la seule méthode pour QGIS de trouver ces 10 points est de calculer la distance entre tous les points de la couche et l’endroit indiqué et de comparer ces distances entre-elles. Cela peut prendre beaucoup de temps spécialement si vous devez répeter l’opération sur plusieurs emplacements. Si index spatial existe pour la couche, l’opération est bien plus efficace.

Vous pouvez vous représenter une couche sans index spatial comme un annuaire dans lequel les numéros de téléphone ne sont pas ordonnés ou indexés. Le seul moyen de trouver le numéro de téléphone d’une personne est de lire l’annuaire en commençant du début jusqu’à ce que vous le trouviez.

Les index spatiaux ne sont pas créés par défaut pour une couche vectorielle QGIS, mais vous pouvez les créer facilement. C’est ce que vous devez faire:

  • create spatial index using the QgsSpatialIndex() class:

    index = QgsSpatialIndex()
    
  • add features to index — index takes QgsFeature object and adds it to the internal data structure. You can create the object manually or use one from a previous call to the provider’s getFeatures() method.

    index.addFeature(feat)
    
  • Alternativement, vous pouvez charger toutes les entités de la couche en une fois en utilisant un chargement en volume.

    index = QgsSpatialIndex(layer.getFeatures())
    
  • Une fois que l’index est rempli avec des valeurs, vous pouvez lancer vos requêtes:

    1
    2
    3
    4
    5
    # returns array of feature IDs of five nearest features
    nearest = index.nearestNeighbor(QgsPointXY(25.4, 12.7), 5)
    
    # returns array of IDs of features which intersect the rectangle
    intersect = index.intersects(QgsRectangle(22.5, 15.3, 23.1, 17.2))
    

6.6. Creating Vector Layers

There are several ways to generate a vector layer dataset:

  • the QgsVectorFileWriter class: A convenient class for writing vector files to disk, using either a static call to writeAsVectorFormat() which saves the whole vector layer or creating an instance of the class and issue calls to addFeature(). This class supports all the vector formats that OGR supports (GeoPackage, Shapefile, GeoJSON, KML and others).

  • the QgsVectorLayer class: instantiates a data provider that interprets the supplied path (url) of the data source to connect to and access the data. It can be used to create temporary, memory-based layers (memory) and connect to OGR datasets (ogr), databases (postgres, spatialite, mysql, mssql) and more (wfs, gpx, delimitedtext…).

6.6.1. From an instance of QgsVectorFileWriter

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# SaveVectorOptions contains many settings for the writer process
save_options = QgsVectorFileWriter.SaveVectorOptions()
transform_context = QgsProject.instance().transformContext()
# Write to a GeoPackage (default)
error = QgsVectorFileWriter.writeAsVectorFormatV2(layer,
                                                  "testdata/my_new_file.gpkg",
                                                  transform_context,
                                                  save_options)
if error[0] == QgsVectorFileWriter.NoError:
    print("success!")
else:
  print(error)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Write to an ESRI Shapefile format dataset using UTF-8 text encoding
save_options = QgsVectorFileWriter.SaveVectorOptions()
save_options.driverName = "ESRI Shapefile"
save_options.fileEncoding = "UTF-8"
transform_context = QgsProject.instance().transformContext()
error = QgsVectorFileWriter.writeAsVectorFormatV2(layer,
                                                  "testdata/my_new_shapefile",
                                                  transform_context,
                                                  save_options)
if error[0] == QgsVectorFileWriter.NoError:
    print("success again!")
else:
  print(error)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Write to an ESRI GDB file
save_options = QgsVectorFileWriter.SaveVectorOptions()
save_options.driverName = "FileGDB"
# if no geometry
save_options.overrideGeometryType = QgsWkbTypes.Unknown
save_options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer
save_options.layerName = 'my_new_layer_name'
transform_context = QgsProject.instance().transformContext()
gdb_path = "testdata/my_example.gdb"
error = QgsVectorFileWriter.writeAsVectorFormatV2(layer,
                                                gdb_path,
                                                transform_context,
                                                save_options)
if error[0] == QgsVectorFileWriter.NoError:
  print("success!")
else:
  print(error)

You can also convert fields to make them compatible with different formats by using the FieldValueConverter. For example, to convert array variable types (e.g. in Postgres) to a text type, you can do the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
LIST_FIELD_NAME = 'xxxx'

class ESRIValueConverter(QgsVectorFileWriter.FieldValueConverter):

  def __init__(self, layer, list_field):
    QgsVectorFileWriter.FieldValueConverter.__init__(self)
    self.layer = layer
    self.list_field_idx = self.layer.fields().indexFromName(list_field)

  def convert(self, fieldIdxInLayer, value):
    if fieldIdxInLayer == self.list_field_idx:
      return QgsListFieldFormatter().representValue(layer=vlayer,
                                                    fieldIndex=self.list_field_idx,
                                                    config={},
                                                    cache=None,
                                                    value=value)
    else:
      return value

  def fieldDefinition(self, field):
    idx = self.layer.fields().indexFromName(field.name())
    if idx == self.list_field_idx:
      return QgsField(LIST_FIELD_NAME, QVariant.String)
    else:
      return self.layer.fields()[idx]

converter = ESRIValueConverter(vlayer, LIST_FIELD_NAME)
opts = QgsVectorFileWriter.SaveVectorOptions()
opts.fieldValueConverter = converter

A destination CRS may also be specified — if a valid instance of QgsCoordinateReferenceSystem is passed as the fourth parameter, the layer is transformed to that CRS.

For valid driver names please call the supportedFiltersAndFormats method or consult the supported formats by OGR — you should pass the value in the « Code » column as the driver name.

Optionally you can set whether to export only selected features, pass further driver-specific options for creation or tell the writer not to create attributes… There are a number of other (optional) parameters; see the QgsVectorFileWriter documentation for details.

6.6.2. Directly from features

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from qgis.PyQt.QtCore import QVariant

# define fields for feature attributes. A QgsFields object is needed
fields = QgsFields()
fields.append(QgsField("first", QVariant.Int))
fields.append(QgsField("second", QVariant.String))

""" create an instance of vector file writer, which will create the vector file.
Arguments:
1. path to new file (will fail if exists already)
2. field map
3. geometry type - from WKBTYPE enum
4. layer's spatial reference (instance of
   QgsCoordinateReferenceSystem)
5. coordinate transform context
6. save options (driver name for the output file, encoding etc.)
"""

crs = QgsProject.instance().crs()
transform_context = QgsProject.instance().transformContext()
save_options = QgsVectorFileWriter.SaveVectorOptions()
save_options.driverName = "ESRI Shapefile"
save_options.fileEncoding = "UTF-8"

writer = QgsVectorFileWriter.create(
  "testdata/my_new_shapefile.shp",
  fields,
  QgsWkbTypes.Point,
  crs,
  transform_context,
  save_options
)

if writer.hasError() != QgsVectorFileWriter.NoError:
    print("Error when creating shapefile: ",  writer.errorMessage())

# add a feature
fet = QgsFeature()

fet.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10,10)))
fet.setAttributes([1, "text"])
writer.addFeature(fet)

# delete the writer to flush features to disk
del writer

6.6.3. From an instance of QgsVectorLayer

Among all the data providers supported by the QgsVectorLayer class, let’s focus on the memory-based layers. Memory provider is intended to be used mainly by plugin or 3rd party app developers. It does not store data on disk, allowing developers to use it as a fast backend for some temporary layers.

Le fournisseur gère les champs en chaînes de caractères, en entiers et en réels.

The memory provider also supports spatial indexing, which is enabled by calling the provider’s createSpatialIndex() function. Once the spatial index is created you will be able to iterate over features within smaller regions faster (since it’s not necessary to traverse all the features, only those in specified rectangle).

A memory provider is created by passing "memory" as the provider string to the QgsVectorLayer constructor.

The constructor also takes a URI defining the geometry type of the layer, one of: "Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon" or "None".

L’URI peut également indiquer un système de coordonnée de référence, des champs et l’indexation. La syntaxe est la suivante:

crs=définition

Specifies the coordinate reference system, where definition may be any of the forms accepted by QgsCoordinateReferenceSystem.createFromString

index=yes

Spécifie que le fournisseur utilisera un index spatial

field=nom:type(longueur,précision)

Spécifie un attribut de la couche. L’attribut dispose d’un nom et optionnellement d’un type (integer, double ou string), d’une longueur et d’une précision. Il peut y avoir plusieurs définitions de champs.

L’exemple suivant montre une URI intégrant toutes ces options

"Point?crs=epsg:4326&field=id:integer&field=name:string(20)&index=yes"

L’exemple suivant illustre la création et le remplissage d’un fournisseur de données en mémoire

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from qgis.PyQt.QtCore import QVariant

# create layer
vl = QgsVectorLayer("Point", "temporary_points", "memory")
pr = vl.dataProvider()

# add fields
pr.addAttributes([QgsField("name", QVariant.String),
                    QgsField("age",  QVariant.Int),
                    QgsField("size", QVariant.Double)])
vl.updateFields() # tell the vector layer to fetch changes from the provider

# add a feature
fet = QgsFeature()
fet.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10,10)))
fet.setAttributes(["Johny", 2, 0.3])
pr.addFeatures([fet])

# update layer's extent when new features have been added
# because change of extent in provider is not propagated to the layer
vl.updateExtents()

Finalement, vérifions que tout s’est bien déroulé

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# show some stats
print("fields:", len(pr.fields()))
print("features:", pr.featureCount())
e = vl.extent()
print("extent:", e.xMinimum(), e.yMinimum(), e.xMaximum(), e.yMaximum())

# iterate over features
features = vl.getFeatures()
for fet in features:
    print("F:", fet.id(), fet.attributes(), fet.geometry().asPoint())
fields: 3
features: 1
extent: 10.0 10.0 10.0 10.0
F: 1 ['Johny', 2, 0.3] <QgsPointXY: POINT(10 10)>

6.7. Apparence (Symbologie) des couches vecteur

Lorsqu’une couche vecteur est en cours de rendu, l’apparence des données est assurée par un moteur de rendu et des symboles associés à la couche. Les symboles sont des classes qui gèrent le dessin de la représentation visuelle des entités alors que les moteurs de rendu déterminent quel symbole doit être utilisé pour une entité particulière.

The renderer for a given layer can be obtained as shown below:

renderer = layer.renderer()

Munis de cette référence, faisons un peu d’exploration:

print("Type:", renderer.type())
Type: singleSymbol

There are several known renderer types available in the QGIS core library:

Type

Classe

Description

singleSymbol

QgsSingleSymbolRenderer

Affiche toutes les entités avec le même symbole.

categorizedSymbol

QgsCategorizedSymbolRenderer

Affiche les entités en utilisant un symbole différent pour chaque catégorie.

graduatedSymbol

QgsGraduatedSymbolRenderer

Affiche les entités en utilisant un symbole différent pour chaque plage de valeurs.

There might be also some custom renderer types, so never make an assumption there are just these types. You can query the application’s QgsRendererRegistry to find out currently available renderers:

print(QgsApplication.rendererRegistry().renderersList())
['nullSymbol', 'singleSymbol', 'categorizedSymbol', 'graduatedSymbol', 'RuleRenderer', 'pointDisplacement', 'pointCluster', 'invertedPolygonRenderer', 'heatmapRenderer', '25dRenderer']

Il est possible d’obtenir un extrait du contenu d’un moteur de rendu sous forme de texte, ce qui peut être utile lors du débogage:

renderer.dump()
SINGLE: MARKER SYMBOL (1 layers) color 190,207,80,255

6.7.1. Moteur de rendu à symbole unique

You can get the symbol used for rendering by calling symbol() method and change it with setSymbol() method (note for C++ devs: the renderer takes ownership of the symbol.)

You can change the symbol used by a particular vector layer by calling setSymbol() passing an instance of the appropriate symbol instance. Symbols for point, line and polygon layers can be created by calling the createSimple() function of the corresponding classes QgsMarkerSymbol, QgsLineSymbol and QgsFillSymbol.

The dictionary passed to createSimple() sets the style properties of the symbol.

For example you can replace the symbol used by a particular point layer by calling setSymbol() passing an instance of a QgsMarkerSymbol, as in the following code example:

symbol = QgsMarkerSymbol.createSimple({'name': 'square', 'color': 'red'})
layer.renderer().setSymbol(symbol)
# show the change
layer.triggerRepaint()

name indique la forme du marqueur, et peut être l’une des valeurs suivantes :

  • circle

  • square

  • cross

  • rectangle

  • diamond

  • pentagon

  • triangle

  • equilateral_triangle

  • star

  • regular_star

  • arrow

  • filled_arrowhead

  • x

To get the full list of properties for the first symbol layer of a symbol instance you can follow the example code:

print(layer.renderer().symbol().symbolLayers()[0].properties())
{'angle': '0', 'color': '255,0,0,255', 'horizontal_anchor_point': '1', 'joinstyle': 'bevel', 'name': 'square', 'offset': '0,0', 'offset_map_unit_scale': '3x:0,0,0,0,0,0', 'offset_unit': 'MM', 'outline_color': '35,35,35,255', 'outline_style': 'solid', 'outline_width': '0', 'outline_width_map_unit_scale': '3x:0,0,0,0,0,0', 'outline_width_unit': 'MM', 'scale_method': 'diameter', 'size': '2', 'size_map_unit_scale': '3x:0,0,0,0,0,0', 'size_unit': 'MM', 'vertical_anchor_point': '1'}

Cela peut être utile si vous souhaitez modifier certaines propriétés:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# You can alter a single property...
layer.renderer().symbol().symbolLayer(0).setSize(3)
# ... but not all properties are accessible from methods,
# you can also replace the symbol completely:
props = layer.renderer().symbol().symbolLayer(0).properties()
props['color'] = 'yellow'
props['name'] = 'square'
layer.renderer().setSymbol(QgsMarkerSymbol.createSimple(props))
# show the changes
layer.triggerRepaint()

6.7.2. Moteur de rendu à symboles catégorisés

When using a categorized renderer, you can query and set the attribute that is used for classification: use the classAttribute() and setClassAttribute() methods.

Pour obtenir la liste des catégories

1
2
3
4
5
6
7
8
9
categorized_renderer = QgsCategorizedSymbolRenderer()
# Add a few categories
cat1 = QgsRendererCategory('1', QgsMarkerSymbol(), 'category 1')
cat2 = QgsRendererCategory('2', QgsMarkerSymbol(), 'category 2')
categorized_renderer.addCategory(cat1)
categorized_renderer.addCategory(cat2)

for cat in categorized_renderer.categories():
    print("{}: {} :: {}".format(cat.value(), cat.label(), cat.symbol()))
1: category 1 :: <qgis._core.QgsMarkerSymbol object at 0x7f378ffcd9d8>
2: category 2 :: <qgis._core.QgsMarkerSymbol object at 0x7f378ffcd9d8>

Where value() is the value used for discrimination between categories, label() is a text used for category description and symbol() method returns the assigned symbol.

The renderer usually stores also original symbol and color ramp which were used for the classification: sourceColorRamp() and sourceSymbol() methods.

6.7.3. Moteur de rendu à symboles gradués

Ce moteur de rendu est très similaire au moteur de rendu par symbole catégorisé ci-dessus mais au lieu d’utiliser une seule valeur d’attribut par classe, il utilise une classification par plages de valeurs et peut donc être employé uniquement sur des attributs numériques.

Pour avoir plus d’informations sur les plages utilisées par le moteur de rendu:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
graduated_renderer = QgsGraduatedSymbolRenderer()
# Add a few categories
graduated_renderer.addClassRange(QgsRendererRange(QgsClassificationRange('class 0-100', 0, 100), QgsMarkerSymbol()))
graduated_renderer.addClassRange(QgsRendererRange(QgsClassificationRange('class 101-200', 101, 200), QgsMarkerSymbol()))

for ran in graduated_renderer.ranges():
    print("{} - {}: {} {}".format(
        ran.lowerValue(),
        ran.upperValue(),
        ran.label(),
        ran.symbol()
      ))
0.0 - 100.0: class 0-100 <qgis._core.QgsMarkerSymbol object at 0x7f8bad281b88>
101.0 - 200.0: class 101-200 <qgis._core.QgsMarkerSymbol object at 0x7f8bad281b88>

you can again use the classAttribute (to find the classification attribute name), sourceSymbol and sourceColorRamp methods. Additionally there is the mode method which determines how the ranges were created: using equal intervals, quantiles or some other method.

Si vous souhaitez créer votre propre moteur de rendu gradué, vous pouvez utiliser l’extrait de code qui est présenté dans l’exemple ci-dessous (qui créé simplement un arrangement en deux classes):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from qgis.PyQt import QtGui

myVectorLayer = QgsVectorLayer("testdata/airports.shp", "airports", "ogr")
myTargetField = 'ELEV'
myRangeList = []
myOpacity = 1
# Make our first symbol and range...
myMin = 0.0
myMax = 50.0
myLabel = 'Group 1'
myColour = QtGui.QColor('#ffee00')
mySymbol1 = QgsSymbol.defaultSymbol(myVectorLayer.geometryType())
mySymbol1.setColor(myColour)
mySymbol1.setOpacity(myOpacity)
myRange1 = QgsRendererRange(myMin, myMax, mySymbol1, myLabel)
myRangeList.append(myRange1)
#now make another symbol and range...
myMin = 50.1
myMax = 100
myLabel = 'Group 2'
myColour = QtGui.QColor('#00eeff')
mySymbol2 = QgsSymbol.defaultSymbol(
     myVectorLayer.geometryType())
mySymbol2.setColor(myColour)
mySymbol2.setOpacity(myOpacity)
myRange2 = QgsRendererRange(myMin, myMax, mySymbol2, myLabel)
myRangeList.append(myRange2)
myRenderer = QgsGraduatedSymbolRenderer('', myRangeList)
myClassificationMethod = QgsApplication.classificationMethodRegistry().method("EqualInterval")
myRenderer.setClassificationMethod(myClassificationMethod)
myRenderer.setClassAttribute(myTargetField)

myVectorLayer.setRenderer(myRenderer)

6.7.4. Travailler avec les symboles

For representation of symbols, there is QgsSymbol base class with three derived classes:

Every symbol consists of one or more symbol layers (classes derived from QgsSymbolLayer). The symbol layers do the actual rendering, the symbol class itself serves only as a container for the symbol layers.

Having an instance of a symbol (e.g. from a renderer), it is possible to explore it: the type method says whether it is a marker, line or fill symbol. There is a dump method which returns a brief description of the symbol. To get a list of symbol layers:

marker_symbol = QgsMarkerSymbol()
for i in range(marker_symbol.symbolLayerCount()):
    lyr = marker_symbol.symbolLayer(i)
    print("{}: {}".format(i, lyr.layerType()))
0: SimpleMarker

To find out symbol’s color use color method and setColor to change its color. With marker symbols additionally you can query for the symbol size and rotation with the size and angle methods. For line symbols the width method returns the line width.

La taille et la largeur sont exprimées en millimètres par défaut, les angles sont en degrés.

6.7.4.1. Travailler avec des couches de symboles

As said before, symbol layers (subclasses of QgsSymbolLayer) determine the appearance of the features. There are several basic symbol layer classes for general use. It is possible to implement new symbol layer types and thus arbitrarily customize how features will be rendered. The layerType() method uniquely identifies the symbol layer class — the basic and default ones are SimpleMarker, SimpleLine and SimpleFill symbol layers types.

You can get a complete list of the types of symbol layers you can create for a given symbol layer class with the following code:

1
2
3
4
5
from qgis.core import QgsSymbolLayerRegistry
myRegistry = QgsApplication.symbolLayerRegistry()
myMetadata = myRegistry.symbolLayerMetadata("SimpleFill")
for item in myRegistry.symbolLayersForType(QgsSymbol.Marker):
    print(item)
1
2
3
4
5
6
7
8
EllipseMarker
FilledMarker
FontMarker
GeometryGenerator
RasterMarker
SimpleMarker
SvgMarker
VectorField

The QgsSymbolLayerRegistry class manages a database of all available symbol layer types.

To access symbol layer data, use its properties() method that returns a key-value dictionary of properties which determine the appearance. Each symbol layer type has a specific set of properties that it uses. Additionally, there are the generic methods color, size, angle and width, with their setter counterparts. Of course size and angle are available only for marker symbol layers and width for line symbol layers.

6.7.4.2. Créer des types personnalisés de couches de symbole

Imaginons que vous souhaitez personnaliser la manière dont sont affichées les données. Vous pouvez créer votre propre classe de couche de symbole qui dessinera les entités de la manière voulue. Voici un exemple de marqueur qui dessine des cercles rouges avec un rayon spécifique.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from qgis.core import QgsMarkerSymbolLayer
from qgis.PyQt.QtGui import QColor

class FooSymbolLayer(QgsMarkerSymbolLayer):

  def __init__(self, radius=4.0):
      QgsMarkerSymbolLayer.__init__(self)
      self.radius = radius
      self.color = QColor(255,0,0)

  def layerType(self):
     return "FooMarker"

  def properties(self):
      return { "radius" : str(self.radius) }

  def startRender(self, context):
    pass

  def stopRender(self, context):
      pass

  def renderPoint(self, point, context):
      # Rendering depends on whether the symbol is selected (QGIS >= 1.5)
      color = context.selectionColor() if context.selected() else self.color
      p = context.renderContext().painter()
      p.setPen(color)
      p.drawEllipse(point, self.radius, self.radius)

  def clone(self):
      return FooSymbolLayer(self.radius)

The layerType method determines the name of the symbol layer; it has to be unique among all symbol layers. The properties method is used for persistence of attributes. The clone method must return a copy of the symbol layer with all attributes being exactly the same. Finally there are rendering methods: startRender is called before rendering the first feature, stopRender when the rendering is done, and renderPoint is called to do the rendering. The coordinates of the point(s) are already transformed to the output coordinates.

For polylines and polygons the only difference would be in the rendering method: you would use renderPolyline which receives a list of lines, while renderPolygon receives a list of points on the outer ring as the first parameter and a list of inner rings (or None) as a second parameter.

En général, il est pratique d’ajouter une interface graphique pour paramétrer les attributs des couches de symbole pour permettre aux utilisateurs de personnaliser l’apparence. Dans le cadre de notre exemple ci-dessus, nous laissons l’utilisateur paramétrer le rayon du cercle. Le code qui suit implémente une telle interface:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from qgis.gui import QgsSymbolLayerWidget

class FooSymbolLayerWidget(QgsSymbolLayerWidget):
    def __init__(self, parent=None):
        QgsSymbolLayerWidget.__init__(self, parent)

        self.layer = None

        # setup a simple UI
        self.label = QLabel("Radius:")
        self.spinRadius = QDoubleSpinBox()
        self.hbox = QHBoxLayout()
        self.hbox.addWidget(self.label)
        self.hbox.addWidget(self.spinRadius)
        self.setLayout(self.hbox)
        self.connect(self.spinRadius, SIGNAL("valueChanged(double)"), \
            self.radiusChanged)

    def setSymbolLayer(self, layer):
        if layer.layerType() != "FooMarker":
            return
        self.layer = layer
        self.spinRadius.setValue(layer.radius)

    def symbolLayer(self):
        return self.layer

    def radiusChanged(self, value):
        self.layer.radius = value
        self.emit(SIGNAL("changed()"))

This widget can be embedded into the symbol properties dialog. When the symbol layer type is selected in symbol properties dialog, it creates an instance of the symbol layer and an instance of the symbol layer widget. Then it calls the setSymbolLayer method to assign the symbol layer to the widget. In that method the widget should update the UI to reflect the attributes of the symbol layer. The symbolLayer method is used to retrieve the symbol layer again by the properties dialog to use it for the symbol.

On every change of attributes, the widget should emit the changed() signal to let the properties dialog update the symbol preview.

Maintenant, il nous manque un dernier détail: informer QGIS de ces nouvelles classes. On peut le faire en ajoutant la couche de symbole au registre. Il est possible d’utiliser la couche de symbole sans l’ajouter au registre mais certaines fonctionnalités ne fonctionneront pas comme le chargement de fichiers de projet avec une couche de symbole personnalisée ou l’impossibilité d’éditer les attributs de la couche dans l’interface graphique.

Nous devons ensuite créer les métadonnées de la couche de symbole.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from qgis.core import QgsSymbol, QgsSymbolLayerAbstractMetadata, QgsSymbolLayerRegistry

class FooSymbolLayerMetadata(QgsSymbolLayerAbstractMetadata):

  def __init__(self):
    super().__init__("FooMarker", "My new Foo marker", QgsSymbol.Marker)

  def createSymbolLayer(self, props):
    radius = float(props["radius"]) if "radius" in props else 4.0
    return FooSymbolLayer(radius)

QgsApplication.symbolLayerRegistry().addSymbolLayerType(FooSymbolLayerMetadata())

You should pass layer type (the same as returned by the layer) and symbol type (marker/line/fill) to the constructor of the parent class. The createSymbolLayer() method takes care of creating an instance of symbol layer with attributes specified in the props dictionary. And there is the createSymbolLayerWidget() method which returns the settings widget for this symbol layer type.

La dernière étape consiste à ajouter la couche de symbole au registre et c’est terminé !

6.7.5. Créer ses propres moteurs de rendu

Il est parfois intéressant de créer une nouvelle implémentation de moteur de rendu si vous désirez personnaliser les règles de sélection des symboles utilisés pour l’affichage des entités. Voici quelques exemples d’utilisation: le symbole est déterminé par une combinaison de champs, la taille des symboles change selon l’échelle courante, etc.

Le code qui suit montre un moteur de rendu personnalisé simple qui crée deux symboles de marqueur et choisit au hasard l’un d’entre eux pour chaque entité.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import random
from qgis.core import QgsWkbTypes, QgsSymbol, QgsFeatureRenderer


class RandomRenderer(QgsFeatureRenderer):
  def __init__(self, syms=None):
    super().__init__("RandomRenderer")
    self.syms = syms if syms else [
      QgsSymbol.defaultSymbol(QgsWkbTypes.geometryType(QgsWkbTypes.Point)),
      QgsSymbol.defaultSymbol(QgsWkbTypes.geometryType(QgsWkbTypes.Point))
    ]

  def symbolForFeature(self, feature, context):
    return random.choice(self.syms)

  def startRender(self, context, fields):
    super().startRender(context, fields)
    for s in self.syms:
      s.startRender(context, fields)

  def stopRender(self, context):
    super().stopRender(context)
    for s in self.syms:
      s.stopRender(context)

  def usedAttributes(self, context):
    return []

  def clone(self):
    return RandomRenderer(self.syms)

The constructor of the parent QgsFeatureRenderer class needs a renderer name (which has to be unique among renderers). The symbolForFeature method is the one that decides what symbol will be used for a particular feature. startRender and stopRender take care of initialization/finalization of symbol rendering. The usedAttributes method can return a list of field names that the renderer expects to be present. Finally, the clone method should return a copy of the renderer.

Like with symbol layers, it is possible to attach a GUI for configuration of the renderer. It has to be derived from QgsRendererWidget. The following sample code creates a button that allows the user to set the first symbol

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from qgis.gui import QgsRendererWidget, QgsColorButton


class RandomRendererWidget(QgsRendererWidget):
  def __init__(self, layer, style, renderer):
    super().__init__(layer, style)
    if renderer is None or renderer.type() != "RandomRenderer":
      self.r = RandomRenderer()
    else:
      self.r = renderer
    # setup UI
    self.btn1 = QgsColorButton()
    self.btn1.setColor(self.r.syms[0].color())
    self.vbox = QVBoxLayout()
    self.vbox.addWidget(self.btn1)
    self.setLayout(self.vbox)
    self.btn1.colorChanged.connect(self.setColor1)

  def setColor1(self):
    color = self.btn1.color()
    if not color.isValid(): return
    self.r.syms[0].setColor(color)

  def renderer(self):
    return self.r

The constructor receives instances of the active layer (QgsVectorLayer), the global style (QgsStyle) and the current renderer. If there is no renderer or the renderer has different type, it will be replaced with our new renderer, otherwise we will use the current renderer (which has already the type we need). The widget contents should be updated to show current state of the renderer. When the renderer dialog is accepted, the widget’s renderer method is called to get the current renderer — it will be assigned to the layer.

Le dernier élément qui manque concerne les métadonnées du moteur ainsi que son enregistrement dans le registre. Sans ces éléments, le chargement de couches avec le moteur de rendu ne sera pas possible et l’utilisateur ne pourra pas le sélectionner dans la liste des moteurs de rendus. Finissons notre exemple sur RandomRenderer:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from qgis.core import (
  QgsRendererAbstractMetadata,
  QgsRendererRegistry,
  QgsApplication
)

class RandomRendererMetadata(QgsRendererAbstractMetadata):

  def __init__(self):
    super().__init__("RandomRenderer", "Random renderer")

  def createRenderer(self, element):
    return RandomRenderer()

  def createRendererWidget(self, layer, style, renderer):
    return RandomRendererWidget(layer, style, renderer)

QgsApplication.rendererRegistry().addRenderer(RandomRendererMetadata())

Similarly as with symbol layers, abstract metadata constructor awaits renderer name, name visible for users and optionally name of renderer’s icon. The createRenderer method passes a QDomElement instance that can be used to restore the renderer’s state from the DOM tree. The createRendererWidget method creates the configuration widget. It does not have to be present or can return None if the renderer does not come with GUI.

To associate an icon with the renderer you can assign it in the QgsRendererAbstractMetadata constructor as a third (optional) argument — the base class constructor in the RandomRendererMetadata __init__() function becomes

QgsRendererAbstractMetadata.__init__(self,
       "RandomRenderer",
       "Random renderer",
       QIcon(QPixmap("RandomRendererIcon.png", "png")))

The icon can also be associated at any later time using the setIcon method of the metadata class. The icon can be loaded from a file (as shown above) or can be loaded from a Qt resource (PyQt5 includes .qrc compiler for Python).

6.8. Sujets complémentaires

A FAIRE :

  • création/modification des symboles

  • working with style (QgsStyle)

  • working with color ramps (QgsColorRamp)

  • Explorer les couches de symboles et les registres de rendus