QGIS:Becoming a GIS Power User
上QQ阅读APP看书,第一时间看更新

Creating custom geoprocessing scripts using Python

In Chapter 4, Spatial Analysis, we used the tools of Processing Toolbox to analyze our data, but we are not limited to these tools. We can expand processing with our own scripts. The advantages of processing scripts over normal Python scripts, such as the ones we saw in the previous section, are as follows:

  • Processing automatically generates a graphical user interface for the script to configure the script parameters
  • Processing scripts can be used in Graphical modeler to create geoprocessing models

As the following screenshot shows, the Scripts section is initially empty, except for some Tools to add and create new scripts:

Writing your first Processing script

We will create our first simple script; which fetches some layer information. To get started, double-click on the Create new script entry in Scripts | Tools. This opens an empty Script editor dialog. The following screenshot shows the Script editor with a short script that prints the input layer's name on the Python Console:

The first line means our script will be put into the Learning QGIS group of scripts, as shown in the following screenshot. The double hashes (##) are Processing syntax and they indicate that the line contains Processing-specific information rather than Python code. The script name is created from the filename you chose when you saved the script. For this example, I have saved the script as my_first_script.py. The second line defines the script input, a vector layer in this case. On the following line, we use Processing's getObject() function to get access to the input layer object, and finally the layer name is printed on the Python Console.

You can run the script either directly from within the editor by clicking on the Run algorithm button, or by double-clicking on the entry in the Processing Toolbox. If you want to change the code, use Edit script from the entry context menu, as shown in this screenshot:

Tip

A good way of learning how to write custom scripts for Processing is to take a look at existing scripts, for example, at https://github.com/qgis/QGIS-Processing/tree/master/scripts. This is the official script repository, where you can also download scripts using the built-in Get scripts from on-line scripts collection tool in the Processing Toolbox.

Writing a script with vector layer output

Of course, in most cases, we don't want to just output something on the Python Console. That is why the following example shows how to create a vector layer. More specifically, the script creates square polygons around the points in the input layer. The numeric size input parameter controls the size of the squares in the output vector layer. The default size that will be displayed in the automatically generated dialog is set to 1000000:

##Learning QGIS=group
##input_layer=vector
##size=number 1000000
##squares=output vector
from qgis.core import *
from processing.tools.vector import VectorWriter
# get the input layer and its fields
my_layer = processing.getObject(input_layer)
fields = my_layer.dataProvider().fields()
# create the output vector writer with the same fields
writer = VectorWriter(squares, None, fields, QGis.WKBPolygon, my_layer.crs())
# create output features
feat = QgsFeature()
for input_feature in my_layer.getFeatures():
 # copy attributes from the input point feature
    attributes = input_feature.attributes()
    feat.setAttributes(attributes)
 # create square polygons
    point = input_feature.geometry().asPoint()
    xmin = point.x() - size/2
    ymin = point.y() - size/2
    square = QgsRectangle(xmin,ymin,xmin+size,ymin+size)
    feat.setGeometry(QgsGeometry.fromRect(square))
    writer.addFeature(feat)
del writer

In this script, we use a VectorWriter to write the output vector layer. The parameters for creating a VectorWriter object are fileName, encoding, fields, geometryType, and crs.

Note

The available geometry types are QGis.WKBPoint, QGis.WKBLineString, QGis.WKBPolygon, QGis.WKBMultiPoint, QGis.WKBMultiLineString, and QGis.WKBMultiPolygon. You can also get this list of geometry types by typing VectorWriter.TYPE_MAP in the Python Console.

Note how we use the fields of the input layer (my_layer.dataProvider().fields()) to create the VectorWriter. This ensures that the output layer has the same fields (attribute table columns) as the input layer. Similarly, for each feature in the input layer, we copy its attribute values (input_feature.attributes()) to the corresponding output feature.

After running the script, the resulting layer will be loaded into QGIS and listed using the output parameter name; in this case, the layer is called squares. The following screenshot shows the automatically generated input dialog as well as the output of the script when applied to the airports from our sample dataset:

Visualizing the script progress

Especially when executing complex scripts that take a while to finish, it is good practice to display the progress of the script execution in a progress bar. To add a progress bar to the previous script, we can add the following lines of code before and inside the for loop that loops through the input features:

i = 0
n = my_layer.featureCount()
for input_feature in my_layer.getFeatures():
    progress.setPercentage(int(100*i/n))
    i+=1
Note

Note that we initialize the i counter before the loop and increase it inside the loop after updating the progress bar using progress.setPercentage().