PyQGIS introduction

Let’s start with simple tasks.

First steps

Layers access

Úkol

  • list of layers determined from current project (even unsaved) on line 1
  • print layer name and feature count for vector layers (3)
  • for other layer types print only name (5)
1
2
3
4
5
for layer in QgsProject.instance().mapLayers().values():
    if layer.type() == QgsMapLayer.VectorLayer:
        print (layer.name(), layer.featureCount())
    else:
        print (layer.name())

Script to download.

../_images/qgis_editor.png

Fig. 3 Example of running simple script from QGIS built-in editor.

Úkol

  • skip disabled layers on line 2
  • process only vector layers with multipolygon geometry type (5)
  • loop over features on line 9
  • get feature geometry on line 10
  • get attribute value nazev (name in Czech) if exists (12)
  • print feature info (fid, name, area in hectares - assuming map units meters), see line 16
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
for layer in QgsProject.instance().mapLayers().values():
    if not QgsProject.instance().layerTreeRoot().findLayer(layer.id()).itemVisibilityChecked():
        continue

    if layer.type() != QgsMapLayer.VectorLayer or layer.wkbType() != QgsWkbTypes.MultiPolygon:
        continue
  
    print (layer.name(), layer.featureCount())
    for feat in layer.getFeatures():
        geom = feat.geometry()
        try:
            nazev = feat['nazev']
        except KeyError:
            nazev = 'no name defined'
            
        print ('{0}: {1} {2:.1f} ha'.format(feat.id(), nazev, geom.area()/1e4))
        

Script to download.

Vector data, features access and editing

Sample data (ice cream shops in Czech Republic downloaded from OpenStreetMap as points only): ice_cream.csv.

Adding CSV-based layers

Úkol

  • load layer without geometry (as table) (see lines 2 and 5)
  • add table layer into layer tree (6)
1
2
3
4
5
6
7
filename = '/home/martin/git/gismentors/yungo-plugins/_static/data/ice_cream.csv'
uri = 'file:///{}?delimiter=,'.format(filename)

name = os.path.splitext(os.path.basename(filename))[0]
layer = QgsVectorLayer(uri, name, 'delimitedtext')

QgsProject.instance().addMapLayer(layer)

Script to download.

Úkol

  • geometry built from longitute and latitude
  • set spatial reference system to EPSG:4326
  • add map layer into layer tree
1
2
3
4
5
6
7
filename = '/home/martin/git/gismentors/yungo-plugins/_static/data/ice_cream.csv'
uri = 'file:///{}?delimiter=,&xField=lon&yField=lat&crs=epsg:4326'.format(filename)

name = os.path.splitext(os.path.basename(filename))[0]
layer = QgsVectorLayer(uri, name, 'delimitedtext')

QgsProject.instance().addMapLayer(layer)

Script to download.

Save layer into file-based GIS format

Úkol

  • reproject to S-JTSK (EPSG:5514) (target CRS set on line 4)
  • save layer into Esri Shapefile format (this task performed on lines 5-7)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
layer = QgsProject.instance().mapLayersByName('ice_cream')[0]

shp_file = "/tmp/ice_cream.shp"
crs = QgsCoordinateReferenceSystem("EPSG:5514")
QgsVectorFileWriter.writeAsVectorFormat(
    layer, shp_file,
    "UTF-8", driverName="ESRI Shapefile", destCRS=crs)
                                        
layer_shp = QgsVectorLayer(shp_file, "test", "ogr")
print (layer_shp.isValid())

Script to download.

Úkol

Improvements

  • check if input layer found (see line 1)
  • check for writter’s errors (see cookbook example)

Editing vector features

Let’s delete all features (ice cream shows) located more than 1km from specified point.

Úkol

  • point of interest must be transformed into layer’s CRS (10-13)
  • area of interest is defined by rectangle on lines 15-19
  • invert selection on line 24
  • delete selected features on line 27
  • note that layer must be switched to edinging mode, it can be done eg. by triggers, see lines 26,28
 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
shp_file = "/tmp/ice_cream.shp"
layer = QgsVectorLayer(shp_file, "test", "ogr")

QgsProject.instance().addMapLayer(layer)

x = 14.3881100
y = 50.1041200
geom = QgsGeometry.fromPointXY(QgsPointXY(x, y))

p_crs = QgsCoordinateReferenceSystem("EPSG:4326")
trans = QgsCoordinateTransform(
    p_crs, layer.crs(), QgsProject.instance())
geom.transform(trans)

p = geom.asPoint()
offset = 1500
p1 = QgsPointXY(p.x() - offset, p.y() - offset)
p2 = QgsPointXY(p.x() + offset, p.y() + offset)
aoi = QgsRectangle(p1, p2)

layer.selectByRect(aoi)
print (len(layer.selectedFeatures()))

layer.invertSelection()

iface.actionToggleEditing().trigger()
iface.actionDeleteSelected().trigger()
iface.actionToggleEditing().trigger()

Script to download.

Úkol

Compare with

layer.startEditing()
layer.deleteSelectedFeatures()
layer.commitChanges()