Index de l'article

Some PyQGIS tips, from the most common to the most practical, to learn or optimize your use of QGIS with Python.

 

Some links:


Open layers

Open some shapes

# Main path
myPath = r'C:\\Users\\Georges\\Downloads\\'
 
project = QgsProject.instance()
project.removeAllMapLayers()
project.clear()
iface.mapCanvas().refresh()
 
# Path of layers
peaks = QgsVectorLayer(myPath + 'peaks_selection/peaks_selection.shp', 'Sommets', 'ogr')
glaciers = QgsVectorLayer(myPath + 'glaciers/glaciers.shp', 'Glaciers', 'ogr')
eau = QgsVectorLayer(myPath + 'eau/eau.shp', 'Fleuves', 'ogr')
troncons_routes = QgsVectorLayer(myPath + 'troncons_routes/troncons_routes.shp', 'Grandes routes', 'ogr')
iris = QgsVectorLayer(myPath + 'iris/iris.shp', 'IRIS', 'ogr')
 
# Open layers
project.addMapLayer(peaks)
project.addMapLayer(glaciers)
project.addMapLayer(eau)
project.addMapLayer(troncons_routes)
project.addMapLayer(iris)
 
iface.mapCanvas().refresh()

Open OSM

(Attention to the &)

project = QgsProject.instance()
 
urlWithParams = "type=xyz&url=http://tile.openstreetmap.org/{z}/{x}/{y}.png"
osm = QgsRasterLayer(urlWithParams, "OpenStreetMap", "wms")
 
project.addMapLayer(osm)
osm.setOpacity(0.75)
 
iface.mapCanvas().refresh()

As we open OSM, which use a specific projection (3857), better to define and force the projection of the project, and the ellipsoid:

project = QgsProject.instance()
...
crs = QgsCoordinateReferenceSystem.fromEpsgId(4326)
project.setCrs(crs)
project.setEllipsoid('EPSG:4326')

Open a Geojson

Or a GML...

myPath = r'C:\\Users\\georg\\Downloads\\'
 
project = QgsProject.instance()
 
eau = QgsVectorLayer(myPath + 'MyGeoJson.geojson', 'Rivières', 'ogr')
 
project.addMapLayer(eau)

Open a Geojson online

iface.addVectorLayer('https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_populated_places.geojson', 'Populated places', 'ogr')

Change a layer's encoding

myLayer = QgsVectorLayer(r'C:/Users/Georges/Downloads/my layer/new_file.tab', new_file, 'ogr')
myLayer.setProviderEncoding('ISO-8859-1')

Open a CSV

csv_path = 'file:///' + myPath + 'World Stats.csv?delimiter=;'
my_csv = QgsVectorLayer(csv_path, 'Countries', 'delimitedtext')
project.addMapLayer(my_csv)

 


Analyze layers

Count layer fields

project = QgsProject.instance()
myLayer = project.mapLayersByName("My layer")[0]
print(myLayer.fields().count())

Count layer features

project = QgsProject.instance()
myLayer = project.mapLayersByName("Adresses")[0]
layerNumberFeatures = myLayer.featureCount()
print(layerNumberFeatures)

Display layer fields names

project = QgsProject.instance()
myLayer = project.mapLayersByName("My layer")[0]
print(myLayer.fields().names())

Get layer projection

project = QgsProject.instance()
myLayer = project.mapLayersByName("Adresses")[0]
layerProj = myLayer.crs()
print(layerProj)

Check if a layer is valid

myLayer = QgsVectorLayer(monRepertoire, 'My layer', 'ogr')
 
if myLayer.isValid():
    print('My layer', 'is valid')

 


Manage layers

Remove all the layers from the QGIS canvas

project = QgsProject.instance()
project.removeAllMapLayers()
project.clear()
iface.mapCanvas().refresh()

Clone a layer

oldLayer = project.mapLayersByName("Old layer")[0]
newLayer = oldLayer.clone()
newLayer.setName('New layer')
project.addMapLayer(newLayer)

Rename a layer

mes_sommets.setName('New name')

Copy-paste a layer with all his files (tab, shp ...) and open them

If you have a layer named test in a directory named my layer, you can create a copy named new file in the same directory and open them in QGIS:

import os
import shutil
 
QgsProject.instance().removeAllMapLayers()
iface.mapCanvas().refresh()
 
directory = r'C:/Users/Georges/Downloads/my layer'
new_file = 'new file'
 
# REMOVE NEW LAYER IF EXISTS
files = os.listdir(directory)
for f in files:
    if f.startswith(new_file):
        try:
            os.remove(directory + '/' + f)
        except:
            pass
 
# COPY LAYER
files = os.listdir(directory)
for f in files:
    if not f.startswith(new_file):
        shutil.copyfile(directory + '/' + f, directory + '/' + new_file + '.' + f.split('.')[1])
print('Layer copied!')
 
test = QgsVectorLayer(directory + '/test.tab', 'test', 'ogr')
QgsProject.instance().addMapLayer(test)
 
new = QgsVectorLayer(directory + '/' + new_file + '.tab', 'new file', 'ogr')
QgsProject.instance().addMapLayer(new)

Change a layer's encoding

myLayer = QgsVectorLayer(r'C:/Users/Georges/Downloads/my layer/new_file.tab', new_file, 'ogr')
myLayer.setProviderEncoding('ISO-8859-1')

Create a group and put a layer into

directory = r'C:/Users/Georges/Downloads/my layer'
newfile = QgsVectorLayer(directory + '/new file.tab', 'newfile', 'ogr')
QgsProject.instance().addMapLayer(newfile)
 
groupName = 'Mon joli groupe'
root = QgsProject.instance().layerTreeRoot()
group = root.addGroup(groupName)
 
layer = QgsProject.instance().mapLayersByName('newfile')[0]
 
mylayer = root.findLayer(layer.id())
myClone = mylayer.clone()
parent = mylayer.parent()
 
group = root.findGroup('Mon joli groupe')
group.insertChildNode(0, myClone)
 
parent.removeChildNode(mylayer)

Hide the rasters bands

root = QgsProject.instance().layerTreeRoot()
for layer in QgsProject.instance().mapLayers().values():
    if layer.type() == QgsMapLayerType.RasterLayer:
        LayerNode = root.findLayer(layer.id())
        LayerNode.setExpanded(False)

Uncheck a layer

project = QgsProject.instance()
myLayer = project.mapLayersByName('My layer')[0]
project.layerTreeRoot().findLayer(myLayer.id()).setItemVisibilityCheckedParentRecursive(False)

Transform a layer projection

This is not a reprojection, which need a processing.run, here below it is just a transformation, which can be unefficient according your context.

project = QgsProject.instance()
 
myLayer = project.mapLayersByName("My layer")[0]
 
my_projection = QgsCoordinateReferenceSystem(4326)
myLayer.setCrs(my_projection)
my_transform = QgsCoordinateTransform(myLayer.crs(), iface.mapCanvas().mapSettings().destinationCrs(), project)
myLayerExtent = my_transform.transform(myLayer.extent())
 
iface.mapCanvas().setExtent(myLayerExtent)
iface.mapCanvas().refresh()

Manage the layers display order

firstLayer = project.mapLayersByName("First layer")[0]
secondLayer = project.mapLayersByName("Second layer")[0]
thirdLayer = project.mapLayersByName("Third layer")[0]
 
root = project.layerTreeRoot()
root.setHasCustomLayerOrder (True)
 
order = root.customLayerOrder()
order.insert(0, order.pop(order.index(firstLayer)))
order.insert(1, order.pop(order.index(secondLayer)))
order.insert(2, order.pop(order.index(thirdLayer)))
 
root.setCustomLayerOrder(order)

Another way cloning the layer:

myLayer = QgsVectorLayer(myPathLayer, "Buffer area", "ogr")
project.addMapLayer(peaks_buffer)
 
root = project.layerTreeRoot()
myBelowLayer = root.findLayer(myLayer.id())
myClone = myBelowLayer.clone()
parent = myBelowLayer.parent()
parent.insertChildNode(-1, myClone)
parent.removeChildNode(myBelowLayer)

Zoom on a layer

countries = QgsVectorLayer(myPath + 'simple_countries/simple_countries.shp', 'Countries', 'ogr')
extent_countries = countries.extent()
iface.mapCanvas().setExtent(extent_countries)
iface.mapCanvas().refresh()

 


Edit layers

Add a point in a shape

It is like projecting points. You have another full example about how to do it in a loop and from an API here (search Autres exemples d'APIs).

Just below a simple example.

(Attention to &)

myPath = r'C:\\Users\\georg\\Downloads\\'
 
project = QgsProject.instance()
project.removeAllMapLayers()
project.clear()
iface.mapCanvas().refresh()
 
myLayer = QgsVectorLayer(myPath + 'peaks_selection/peaks_selection.shp', 'Peaks', 'ogr')
project.addMapLayer(myLayer)
 
crs = QgsCoordinateReferenceSystem.fromEpsgId(4326)
project.setCrs(crs)
project.setEllipsoid('EPSG:4326')
 
# Add a point
myPoints = project.mapLayersByName('Peaks')[0]
aPoint = QgsVectorLayer(myPoints.dataProvider().dataSourceUri(), '', 'ogr')
caps = aPoint.dataProvider().capabilities()
 
if caps & QgsVectorDataProvider.AddFeatures:
    feat = QgsFeature(aPoint.fields())
    feat.setAttributes([1, 'Fake peak'])
    feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(6.0631, 44.8844)))
    res, outFeats = aPoint.dataProvider().addFeatures([feat])

Pack a shape/commit your edits

When you write a lot of features in a shape, or after deletion, it is good to pack your shape (to avoid some blank lines in the .dbf file for example). It is a kind of commit.

For example, if after some deletions, you remove your layer from QGIS, then you re-open it, and then then your do new changes, if you check the attributes table you will see some empty blank lines.

We will use GDAL/OGR and some SQL to pack our layer, with a id field named here OSM_ID:

import subprocess
 
myOriginalShape = myPath + 'peaks_selection/peaks_selection.shp'
myTempShape = myPath + 'peaks_selection/temp_peaks_selection.shp'
 
# Pack with GDAL/OGR filtering with SQL
cmd = [
    'ogr2ogr', '-f', 'ESRI Shapefile',
    myTempShape, myOriginalShape,
    '-sql', 'SELECT * FROM peaks_selection WHERE OSM_ID IS NOT NULL'
]
subprocess.run(cmd)

And here a full example to edit, pack, rename and see the last edits:

(Attention to &)

import subprocess
import time
 
myPath = r'C:\\Users\\georg\\Downloads\\'
 
myOriginalShape = myPath + 'peaks_selection/peaks_selection.shp'
myTempShape = myPath + 'peaks_selection/temp_peaks_selection.shp'
 
project = QgsProject.instance()
project.removeAllMapLayers()
project.clear()
iface.mapCanvas().refresh()
 
myLayer = QgsVectorLayer(myOriginalShape, 'Peaks', 'ogr')
myLayer.setProviderEncoding('ISO-8859-1')
 
project.addMapLayer(myLayer)
crs = QgsCoordinateReferenceSystem.fromEpsgId(4326)
project.setCrs(crs)
project.setEllipsoid('EPSG:4326')
 
# Add a point
def addPoint():
    myPoints = project.mapLayersByName('Peaks')[0]
    aPoint = QgsVectorLayer(myPoints.dataProvider().dataSourceUri(), '', 'ogr')
    caps = aPoint.dataProvider().capabilities()
 
    if caps & QgsVectorDataProvider.AddFeatures:
        feat = QgsFeature(aPoint.fields())
        feat.setAttributes([1, 'Fake peak'])
        feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(6.0631, 44.8844)))
        res, outFeats = aPoint.dataProvider().addFeatures([feat])
 
QTimer.singleShot(1000, addPoint)
 
# Then pack/commit
def myPacking():
    cmd = [
        'ogr2ogr', '-f', 'ESRI Shapefile',
        myTempShape, myOriginalShape,
        '-sql', 'SELECT * FROM peaks_selection WHERE OSM_ID IS NOT NULL'
    ]
    subprocess.run(cmd)
 
QTimer.singleShot(200, myPacking)
 
# Clear project
project = QgsProject.instance()
project.removeAllMapLayers()
project.clear()
iface.mapCanvas().refresh()
 
# Then delete/rename
def myDeleteRename():
    for ext in ['.shp', '.shx', '.dbf', '.prj']:
        old_file = myOriginalShape.replace('.shp', ext)
        new_file = myTempShape.replace('.shp', ext)
 
    if os.path.exists(old_file):
        os.remove(old_file)
 
    os.rename(new_file, old_file)
 
QTimer.singleShot(200, myDeleteRename)
 
# Clear project
project = QgsProject.instance()
project.removeAllMapLayers()
project.clear()
iface.mapCanvas().refresh()
 
# Then reopen the layer updated
def myReopen():
    myLayer = QgsVectorLayer(myOriginalShape, 'Peaks', 'ogr')
    myLayer.setProviderEncoding('ISO-8859-1')
    project.addMapLayer(myLayer)
 
    crs = QgsCoordinateReferenceSystem.fromEpsgId(4326)
    project.setCrs(crs)
    project.setEllipsoid('EPSG:4326')
 
QTimer.singleShot(200, myReopen)
 
# Final refresh to see the last edits
time.sleep(1)
QgsProject.instance().reloadAllLayers()

Add fields in a layer

myLayer = QgsVectorLayer(r'C:/Users/Georges/Downloads/my layer/new_file.tab', 'new file', 'ogr')
myLayerInstance = QgsProject.instance().mapLayersByName('new file')[0]
 
myLayerInstance.startEditing()
 
myLayerInstance.dataProvider().addAttributes([QgsField("newfield1", QVariant.String), QgsField("newfield2", QVariant.String)])
 
myLayerInstance.updateFields()
 
myLayerInstance.commitChanges()

Delete a field

myLayer.dataProvider().deleteAttributes(['My field'])

Fill a field

myLayerInstance = QgsProject.instance().mapLayersByName('new file')[0]
 
with edit(myLayerInstance):
    for feature in myLayerInstance.getFeatures():
        # A VALUE
        feature['newfield1'] = 'Abc Xyz'
 
        # CONCATENATE OTHER FIELD
        feature['newfield2'] = feature['name'] + '-' + feature['id']
 
        myLayerInstance.updateFeature(feature)

Create a shape

layer = QgsProject.instance().mapLayersByName('peaks')[0]
layer.selectByExpression('"NAME" LIKE \'Aiguille%\'')
 
root = r'C:/Users/georg/Downloads/Aiguilles/'
if not os.path.exists(root):
    os.makedirs(root)
 
file = str(root)+'Aiguilles.shp'
writer = QgsVectorFileWriter.writeAsVectorFormat(layer, file, 'utf-8', driverName='ESRI Shapefile', onlySelected=True)

 


Filter/Select

Select features

myPath = r'C:\\Users\\georg\\Downloads\\'
 
project = QgsProject.instance()
project.removeAllMapLayers()
project.clear()
iface.mapCanvas().refresh()
 
myLayer = QgsVectorLayer(myPath + 'peaks_selection/peaks_selection.shp', 'Sommets', 'ogr')
QgsProject.instance().addMapLayer(myLayer)
 
# SELECT
myExpr = u"NAME LIKE '{}'".format('Grand Pic de la Meije')
mySelect = myLayer.getFeatures(QgsFeatureRequest().setFilterExpression(myExpr))
 
myLayer.selectByIds([f.id() for f in mySelect])

Select function

def SelectAndZoom(layername, field, value):
    mylayer = QgsProject.instance().mapLayersByName(layername)[0]
    myselect = mylayer.getFeatures( QgsFeatureRequest().setFilterExpression ( u'"%s" = \'%s\'' % (field, value)) )
    mylayer.selectByIds( [ f.id() for f in myselect ] )
    iface.mapCanvas().zoomToSelected(mylayer)

Then use it like that:

SelectAndZoom('My layer', 'My field', 'Some value')

Select features after click on another layer

layer_selected = QgsProject.instance().mapLayersByName("decathlon_france")[0]
layer_to_select = QgsProject.instance().mapLayersByName("iso_iris")[0]
 
def SelectionAuto():
    selected_features = layer_selected.selectedFeatures()
    for i in selected_features:
        attrs = i.__geo_interface__
        id_mag = i['id']
        # print (id_mag)
 
        myselect = layer_to_select.getFeatures( QgsFeatureRequest().setFilterExpression ( u'"id_mag" = \'%s\'' % id_mag ) )
        layer_to_select.selectByIds( [ f.id() for f in myselect ] )
        # iface.mapCanvas().zoomToSelected(layer_to_select)
 
layer_selected.selectionChanged.connect(SelectionAuto)

Filter a layer

myFilter = u"field_a <> '{}'".format('A value')
myLayer.setSubsetString(myFilter)

Remove a filter

myLayer.setSubsetString('')

 


Temporary layers

Add a temporary layers

point_vector = QgsVectorLayer("Point", "my_points", "memory")
project.addMapLayer(point_vector)

Add fields

from qgis.PyQt.QtCore import QVariant
...
pr = point_vector.dataProvider()
pr.addAttributes([QgsField("id", QVariant.Int), QgsField("name", QVariant.String)])
point_vector.updateFields()

Add a point

f = QgsFeature()
f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(7.7633340, 48.5785590)))
f.setAttributes([8, 'My 8'])
pr.addFeature(f)
point_vector.updateExtents()
project.addMapLayer(point_vector)
iface.mapCanvas().refresh()

 


Symbologies

Simple symbology on points

myLayer = QgsProject.instance().mapLayersByName("My points")[0]
 
symbol_peak = QgsMarkerSymbol.createSimple({'name': 'Triangle', 'color': 'green', 'outline_color': 'black', 'size': '4'})
myLayer.renderer().setSymbol(symbol_peak)
myLayer.triggerRepaint()
iface.layerTreeView().refreshLayerSymbology(myLayer.id())
iface.mapCanvas().refresh()

Other point markers: 

circle square cross rectangle diamond pentagon triangle equilateral_triangle star regular_star arrow filled_arrowhead x

Use PNG on points

You can build your own picture as PNG and use it in symbology with QgsRasterMarkerSymbolLayer:

myPath = r'C:\\Users\\georg\\Downloads\\'
 
project = QgsProject.instance()
project.removeAllMapLayers()
project.clear()
iface.mapCanvas().refresh()
 
# Path of layers
peaks = QgsVectorLayer(myPath + 'peaks_selection/peaks_selection.shp', 'Peaks', 'ogr')
project.addMapLayer(peaks)
 
myLayer = QgsProject.instance().mapLayersByName("Peaks")[0]
 
# Use a SVG in symbology
myPicture = myPath + 'flower.png'
 
symbolLayer = QgsRasterMarkerSymbolLayer(myPicture)
symbolLayer.setSize(10)
 
symbol_peak = QgsMarkerSymbol.createSimple({})
symbol_peak.changeSymbolLayer(0, symbolLayer)
 
myLayer.renderer().setSymbol(symbol_peak)
myLayer.triggerRepaint()
 
iface.layerTreeView().refreshLayerSymbology(myLayer.id())
iface.mapCanvas().refresh()

Use SVG on points

Use QgsSvgMarkerSymbolLayer, but attention, SVG is a very specific format, maybe prefer PNG.

myPath = r'C:\\Users\\georg\\Downloads\\'
 
project = QgsProject.instance()
project.removeAllMapLayers()
project.clear()
iface.mapCanvas().refresh()
 
# Path of layers
peaks = QgsVectorLayer(myPath + 'peaks_selection/peaks_selection.shp', 'Peaks', 'ogr')
project.addMapLayer(peaks)
 
myLayer = QgsProject.instance().mapLayersByName("Peaks")[0]
 
# Use a SVG in symbology
mySvg = 'C:/Program Files/QGIS 3.28.13/apps/qgis-ltr/resources/themes/Night Mapping/icons/eye.svg'
 
svg_symbol_layer = QgsSvgMarkerSymbolLayer(mySvg)
svg_symbol_layer.setSize(10)
 
symbol_peak = QgsMarkerSymbol.createSimple({})
symbol_peak.changeSymbolLayer(0, svg_symbol_layer)
 
myLayer.renderer().setSymbol(symbol_peak)
myLayer.triggerRepaint()
 
iface.layerTreeView().refreshLayerSymbology(myLayer.id())
iface.mapCanvas().refresh()

Simple symbology on lines

With HTML color.

myroads = QgsProject.instance().mapLayersByName("Roads")[0]
myrivers = QgsProject.instance().mapLayersByName("Rivers")[0]
 
# Roads
symbol = QgsLineSymbol.createSimple({'line_style': 'dash', 'line_width': '0.5', 'color': 'black'})
myroads.renderer().setSymbol(symbol)
myroads.triggerRepaint()
iface.layerTreeView().refreshLayerSymbology(myroads.id())
 
# Rivers
symbol = QgsLineSymbol.createSimple({'line_style': 'solid', 'line_width': '0.75', 'color': '#0088CC'})
myrivers.renderer().setSymbol(symbol)
myrivers.triggerRepaint()
iface.layerTreeView().refreshLayerSymbology(myrivers.id())
 
iface.mapCanvas().refresh()

Simple symbology on polygons

With RGB color (50,165,77,75), and some transparency (here 75, from 0 to 255), et on rafraîchit le panneau des couches afin que notre légende y soit aussi prise en compte:

myground = QgsProject.instance().mapLayersByName("Ground")[0]
 
symbol = QgsFillSymbol.createSimple({'line_style': 'solid', 'line_width': '0.2', 'color': '50,165,77,75'})
myground.renderer().setSymbol(symbol)
 
myground.triggerRepaint()
iface.layerTreeView().refreshLayerSymbology(myground.id())
iface.mapCanvas().refresh()

Check current symbology properties

my_layer = QgsProject.instance().mapLayersByName("My points")[0]
print(my_layer.renderer().symbol().symbolLayers()[0].properties())

Categorized Symbology

For a categorized symbology, we will need to define several symbologies, then assign them based on attribute values.

Here we put all our peaks in blue triangle (, then we will look for a single peak based on its name (My best peak, in the NAME field). This will change to a dark blue triangle and larger size ().

symbol_peak = QgsMarkerSymbol.createSimple({'name': 'Triangle', 'color': '#0088CC', 'outline_color': 'black', 'size': '4'})
symbol_peak_selected = QgsMarkerSymbol.createSimple({'name': 'Triangle', 'color': 'blue', 'outline_color': 'black', 'size': '7'})
 
color_peak = QgsRendererCategory(None, symbol_peak, 'Peaks', True)
color_peak_selected = QgsRendererCategory('My best peak', symbol_peak_selected, 'My best peak', True)
 
renderer = QgsCategorizedSymbolRenderer("NAME", [color_peak,color_peak_selected])
 
mylayer.setRenderer(renderer)
mylayer.triggerRepaint()
iface.mapCanvas().refresh()

Transparency on a basemap (OSM)

osm = QgsRasterLayer(urlWithParams, "OpenStreetMap", "wms")
project.addMapLayer(osm)
osm.setOpacity(0.75)
 
iface.mapCanvas().refresh()

 


Labeling

Usual labels

project = QgsProject.instance()
 
myLayers = QgsVectorLayer(myPath + 'myLayers/myLayers.shp', 'myLayers', 'ogr')
 
project.addMapLayer(myLayers)
 
myLayerLabelSettings = QgsPalLayerSettings()
myLayerLabelSettings.fieldName = 'name'
myLayerLabelSettings.enabled = True
 
myLayerText = QgsTextFormat()
myLayerText.setFont(QFont('Verdana', 8))
myLayerText.setSize(8)
 
myLayerLabelSettings.setFormat(myLayerText)
 
myLayerSettings = QgsVectorLayerSimpleLabeling(myLayerLabelSettings)
myLayers.setLabeling(myLayerSettings)
myLayers.setLabelsEnabled(True)
 
myLayers.triggerRepaint()
iface.mapCanvas().refresh()
time.sleep(0.5)

 


Intersection

Below we set processes with a function in a QTimer.singleShot, to allow multi-execution, but it is not mandatory according your context.

import os
import shutil
 
myPath = r'C:\\Users\\georg\\Downloads\\'
 
project = QgsProject.instance()
project.removeAllMapLayers()
project.clear()
iface.mapCanvas().refresh()
 
peaks = QgsVectorLayer(myPath + 'peaks_selection/peaks_selection.shp', 'Peaks', 'ogr')
iris = QgsVectorLayer(myPath + 'iris/iris.shp', 'IRIS', 'ogr')
 
QgsProject.instance().addMapLayer(peaks)
QgsProject.instance().addMapLayer(iris)
 
# Intersection function
def myIntersection():
    # Directory for created layer
    _peaks_intersection = myPath + '_peaks_intersection'
    if os.path.isdir(_peaks_intersection) == True:
        shutil.rmtree(_peaks_intersection)
    if os.path.isdir(_peaks_intersection) == False:
        os.mkdir(_peaks_intersection)
 
    # Intersect peaks and IRIS
    peaks_intersection_path = _peaks_intersection + r'\\peaks_intersection.shp'
    processing.run('qgis:intersection', { \
    "INPUT": peaks, \
    "OVERLAY": iris, \
    "INPUT_FIELDS": ["OSM_ID", "NAME", "OTHER_TAGS"], \
    "OVERLAY_FIELDS": ["CODE_IRIS", "NOM_COM"], \
    "OVERLAY_FIELDS_PREFIX": "", \
    "OUTPUT": peaks_intersection_path})
 
    # Remove layers
    project.removeMapLayer(peaks)
    project.removeMapLayer(iris)
 
    # Open the new intersected layer
    peaks_intersection = QgsVectorLayer(peaks_intersection_path, 'Peaks', "ogr")
    project.addMapLayer(peaks_intersection)
 
    # Register layer
    myIntersection = project.mapLayersByName('Peaks')[0]
 
# Run function with delay
QTimer.singleShot(200, myIntersection)

Other params here!

 


Buffer

Below we set processes with a function in a QTimer.singleShot, to allow multi-execution, but it is not mandatory according your context.

Buffer with 4326 point layer, so with fake units:

import os
import shutil
 
myPath = r'C:\\Users\\georg\\Downloads\\'
 
project = QgsProject.instance()
project.removeAllMapLayers()
project.clear()
iface.mapCanvas().refresh()
 
crs = QgsCoordinateReferenceSystem.fromEpsgId(4326)
project.setCrs(crs)
project.setEllipsoid('EPSG:4326')
 
peaks = QgsVectorLayer(myPath + 'peaks_selection/peaks_selection.shp', 'Peaks', 'ogr')
QgsProject.instance().addMapLayer(peaks)
 
# Buffer function
def myBuffer():
    # Directory for created layer
    _peaks_buffer = myPath + '_peaks_buffer'
    if os.path.isdir(_peaks_buffer) == True:
        shutil.rmtree(_peaks_buffer)
    if os.path.isdir(_peaks_buffer) == False:
        os.mkdir(_peaks_buffer)
 
    # Buffer on peaks
    peaks_buffer_path = _peaks_buffer + r'\\peaks_buffer.shp'
 
    processing.run('qgis:buffer', { \
    "INPUT": peaks, \
    "DISTANCE": 0.05, \
    "SEGMENTS": 10, \
    "END_CAP_STYLE": 0, \
    "DISSOLVE": False, \
    "OUTPUT": peaks_buffer_path})
 
    # Open the buffer layer
    peaks_buffer = QgsVectorLayer(peaks_buffer_path, "Buffer area", "ogr")
    project.addMapLayer(peaks_buffer)
 
    # Register layer
    my_buffer = project.mapLayersByName("Buffer area")[0]
 
    # Buffer below
    root = project.layerTreeRoot()
    myBelowLayer = root.findLayer(peaks_buffer.id())
    myClone = myBelowLayer.clone()
    parent = myBelowLayer.parent()
    parent.insertChildNode(-1, myClone)
    parent.removeChildNode(myBelowLayer)
 
# Run function with delay
QTimer.singleShot(200, myBuffer)

  


Fix geometry

Fix invalid geometry (and register the output to use it later)

Here we register the output with the name MyFixedLayer. So we can use it later.

alg_params = {
    'INPUT':'C:\\Users\\georg\\Downloads\\MyLayer.shp',
    'METHOD':1,
    'OUTPUT':'C:\\Users\\georg\\Downloads\\MyFixedLayer.shp'
}
outputs['MyFixedLayer'] = processing.run('native:fixgeometries', alg_params, context=context)

Fix invalid geometry (from a previous output registered)

alg_params = {
    'INPUT': outputs['MyPreviousOutput']['OUTPUT'],
    'METHOD':1,
    'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
}
outputs['MyNewOutput'] = processing.run('native:fixgeometries', alg_params, context=context)

 


Merge vector layers

First, create and fill a list with your layers to merge, then:

myPath = r'C:\\Users\\georg\\Downloads\\'
 
project = QgsProject.instance()
 
...
 
parameters = {'LAYERS': listLayersToMerge,'CRS': 'EPSG:25832','OUTPUT': myPath + 'results.shp'}
processing.run("qgis:mergevectorlayers", parameters)
 
myMerge = QgsVectorLayer(myPath + 'results.shp', 'My merge', 'ogr')
project.addMapLayer(myMerge)

A full example here, search for Fusion de couches

 


Joins

Join a CSV

import os
import shutil
 
myPath = r'C:\\Users\\georg\\Downloads\\'
 
project = QgsProject.instance()
project.removeAllMapLayers()
project.clear()
iface.mapCanvas().refresh()
 
crs = QgsCoordinateReferenceSystem.fromEpsgId(4326)
project.setCrs(crs)
project.setEllipsoid('EPSG:4326')
 
countries = QgsVectorLayer(myPath + 'simple_countries/simple_countries.shp', 'Countries', 'ogr')
 
project.addMapLayer(countries)
myCountries = project.mapLayersByName('Countries')[0]
 
extent_countries = countries.extent()
iface.mapCanvas().setExtent(extent_countries)
iface.mapCanvas().refresh()
 
# IMPORT CSV
csv_path = 'file:///' + myPath + 'World Stats.csv?delimiter=;'
my_csv = QgsVectorLayer(csv_path, 'Countries', 'delimitedtext')
project.addMapLayer(my_csv)
 
# JOIN 
shpField='COUNTRY_HB'
csvField='Country'
 
myJoin = QgsVectorLayerJoinInfo()
myJoin.setJoinFieldName(csvField)
myJoin.setTargetFieldName(shpField)
myJoin.setJoinLayerId(my_csv.id())
myJoin.setUsingMemoryCache(True)
myJoin.setJoinLayer(my_csv)
myJoin.setJoinFieldNamesSubset(['Population (2024)'])
myJoin.setPrefix('')
 
countries.addJoin(myJoin)
countries.dataProvider().forceReload()

 


Classifications

You can use any of these classification method classes:

  • QgsClassificationQuantile()
  • QgsClassificationEqualInterval()
  • QgsClassificationJenks()
  • QgsClassificationPrettyBreaks()
  • QgsClassificationLogarithmic()
  • QgsClassificationStandardDeviation()

Available color ramps

You can check all the ramps availables in your QGIS like that:

default_style = QgsStyle().defaultStyle()
available_ramps = default_style.colorRampNames()
for ramp in available_ramps:
    print(ramp)

Equal intervals

# Set layer name and desired params
ramp_name = 'Spectral'
value_field = 'Population (2024)'
num_classes = 10
classification_method = QgsClassificationEqualInterval()
 
layer = QgsProject().instance().mapLayersByName('Countries')[0]
 
format = QgsRendererRangeLabelFormat()
format.setTrimTrailingZeroes(True)
 
default_style = QgsStyle().defaultStyle()
 
color_ramp = default_style.colorRamp(ramp_name)
 
renderer = QgsGraduatedSymbolRenderer()
renderer.setClassAttribute(value_field)
renderer.setClassificationMethod(classification_method)
renderer.setLabelFormat(format)
renderer.updateClasses(layer, num_classes)
 
renderer.updateColorRamp(color_ramp)
 
layer.setRenderer(renderer)
layer.triggerRepaint()

Jenks

# Set layer name and desired params
ramp_name = 'PuRd'
value_field = 'Population (2024)'
num_classes = 20
classification_method = QgsClassificationJenks()
 
layer = QgsProject().instance().mapLayersByName('Countries')[0]
 
format = QgsRendererRangeLabelFormat()
format.setTrimTrailingZeroes(True)
 
default_style = QgsStyle().defaultStyle()
 
color_ramp = default_style.colorRamp(ramp_name)
 
renderer = QgsGraduatedSymbolRenderer()
renderer.setClassAttribute(value_field)
renderer.setClassificationMethod(classification_method)
renderer.setLabelFormat(format)
renderer.updateClasses(layer, num_classes)
 
renderer.updateColorRamp(color_ramp)
 
layer.setRenderer(renderer)
layer.triggerRepaint()

Round zeroes

format = QgsRendererRangeLabelFormat()
format.setTrimTrailingZeroes(True)

Decimals

format = QgsRendererRangeLabelFormat()
format.setPrecision(2)

Separator

format = QgsRendererRangeLabelFormat()
format.setFormat("%1 - %2")

Invert colors

color_ramp = default_style.colorRamp(ramp_name)
 
# Manually invert the color ramp
if isinstance(color_ramp, QgsGradientColorRamp):
    inverted_ramp = QgsGradientColorRamp(
        color_ramp.color2(), # Use the second color as the start color
        color_ramp.color1() # Use the first color as the end color
    )
else:
    inverted_ramp = color_ramp
...
renderer.updateColorRamp(inverted_ramp)

 


Install a third-party Python module in QGIS

You will have to go through the OSGeo4W shell.

We will use Pip, but Pip is already in the Python of QGIS.

Follow this tutorial to install a module on the version of Python used by your QGIS on Windows, or more simply just below.

In the OSGeo shell (and not in the usual Windows shell), with some old QGIS version, maybe start to target the environment:

py3_env

On more recent versions (QGIS 3.34 for example), just enter:

python -m pip install wikipedia

If you have some users rights restrictions:

python -m pip install wikipedia --user

You may need to restart QGIS to take your new library into account (no need with the Wikipedia lib, but it depends of the library).

Maybe you will need to register Pip or Python in your Path System Variable, just follow the instructions from the OSGeo shell.

Other libraries examples

pip install requests-html
py -m pip install requests-html
pip install wikidata
pip install requests

PIP on Windows

But maybe you would install Pip on Windows. Pip is a Python extensions installer, check this:

 


Generate maps in a loop

Full code to generate maps in a loop here!

 


Miscellaneous

Get executed QGIS Python code

In the QGIS menu: Processing/History.

In a plugin (from QGIS 3.28): Advanced/Copy as Python Command

Set projection and ellipsoid

project = QgsProject.instance()
...
crs = QgsCoordinateReferenceSystem.fromEpsgId(4326)
project.setCrs(crs)
project.setEllipsoid('EPSG:4326')

See the available process and scripts

for alg in QgsApplication.processingRegistry().algorithms():
    print("{}:{} --> {}".format(alg.provider().name(), alg.name(), alg.displayName()))

Manage the multi-execution of your script

Sometimes it is good to remove existing layers and clean your QGIS instance before to run the working code (but also read on because it is not perfect):

project = QgsProject.instance()
project.removeAllMapLayers()
project.clear()
iface.mapCanvas().refresh()

Sometimes it is good to delete all persistent variables at the begining of your code to manage the multi-execution of your script (to be able to run it, and re-run it, then re-run it... it can be useful when your work, but keep to read on because it is not perfect):

for g in globals():
    del g

OK guys, now the real solution 😃: according your working context, and especially when you create/re-create new layers and/or new directories (with a geo-process for example), it is better to do it in a function (def), then to run your function in a QTimer.singleShot, with a little delay (below 200 milliseconds):

...
def myGeoProcess():
    ...
    processing.run('qgis:anyGeoProcess', {
    ...
    })
...
QTimer.singleShot(200, myGeoProcess)
...

Find a full example in the chapter named Processing: Intersection or Processing: Buffer.

Using QGIS Buttons in Python Code

eMenu = iface.viewMenu()
eMenu.actions()[12].trigger()

Add custom text in map

project = QgsProject.instance()
iface.mapCanvas().refresh()
 
manager = project.layoutManager()
layout = QgsPrintLayout(project)
layout.initializeDefaults()
layout.setName(layoutName)
 
manager.addLayout(layout)
map = QgsLayoutItemMap(layout)
 
myBoldFont=QtGui.QFont('Verdana', 11)
myBoldFont.setBold(True)
 
TextCustom = QgsLayoutItemLabel(layout)
TextCustom.setText("Wikipédia :")
TextCustom.setFont(myBoldFont)
layout.addLayoutItem(TextCustom)
TextCustom.attemptMove(QgsLayoutPoint(230, 90, QgsUnitTypes.LayoutMillimeters))
TextCustom.attemptResize(QgsLayoutSize(60, 100, QgsUnitTypes.LayoutMillimeters))

Download a picture and add a backgound color

from PyQt5 import *
from qgis.PyQt.QtGui import QImage, QPainter, QColor
 
# Image 1
url = r'https://j4binv.master-geomatique.org/images/img_site/logos/logo2021-blanc.png'
response = requests.get(url)
image_originale1 = myPath + 'logo_master.png'
path_nouvelle_image1 = myPath + 'logo_master_fond_vert.png'
 
# Dowload image
if response.status_code == 200:
    with open(image_originale1, 'wb') as file:
        file.write(response.content)
else:
    raise Exception('Impossible de télécharger l\'image !')
 
# Set a black background
my_image = QImage(image_originale1)
largeur = my_image.width() + 40
hauteur = my_image.height() + 40
 
nouvelle_image1 = QImage(largeur, hauteur, QImage.Format_ARGB32)
nouvelle_image1.fill(QColor(21, 187, 161))
 
painter = QPainter(nouvelle_image1)
 
x_offset = (largeur - my_image.width()) // 2
y_offset = (hauteur - my_image.height()) // 2
 
painter.drawImage(x_offset, y_offset, my_image)
painter.end()
 
nouvelle_image1.save(path_nouvelle_image1)