Warning
A new version of this tutorial is available at Writing Python Scripts for Processing Framework (QGIS3)
One can write standalone pyqgis scripts that can be run via the Python Console in QGIS. With a few tweaks, you can make your standalone scripts run via the Processing Framework. This has several advantages. First, taking user input and writing output files is far easier because Processing Framework offers standardized user interface for these. Second, having your script in the Processing Toolbox also allows it to be part of any Processing Model or be run as a Batch job with multiple inputs. This tutorial will show how to write a custom python script that can be part of the Processing Framework in QGIS.
Our script will perform a dissolve operation based on a field chosen by the
user. It will also sum up values of another field for the dissolved features.
In the example, we will dissolve a world shapefile based on a SUBREGION
attribute and sum up POP_EST
field to calculate total population in the
dissolved region.
Note
If you are looking to do a Dissolve operation along with Statistics, you can
use the excellent DissolveWithStats
plugin. This script is a
demonstration how to implement similar functionality via a Processing
script.
We will use the Admin 0 - Countries dataset from Natural Earth.
Download the Admin 0 - countries shapefile..
Data Source [NATURALEARTH]
For convenience, you may directly download a copy of the dataset from the links below:
ne_10_admin_0_countries.zip
file and
load the ne_10_admin_0_countries
layer. Go to .dissolve_layer
, dissolve_field
and
sum_field
. Note that we are adding dissolve_layer
after both the
field input definitions. This means that input will be pre-populated with
choice of fields from the dissolve_layer
. We also specify the
output_layer
as the output vector layer. Click Save button.##dissolve_layer=vector
##dissolve_field=field dissolve_layer
##sum_field=field dissolve_layer
##output_layer=output vector
dissolve_with_sum
and save it at the default location
under folder.processing.getObject()
and processing.features()
. These are convenience wrappers that make it
easy to work with data. You can learn more about these from Additional
functions for handling data
section of QGIS Processing Documentation. Click Save to save the
newly entered code and then the X button to close the editor.Note
This script uses python list comprehensions extensively. Take a look at this list comprehension tutorial to get familiar with the syntax.
from qgis.core import *
from PyQt4.QtCore import *
inlayer = processing.getObject(dissolve_layer)
dissolve_field_index = inlayer.fieldNameIndex(dissolve_field)
sum_field_index = inlayer.fieldNameIndex(sum_field)
# Find unique values present in the dissolve field
unique_values = set([f[dissolve_field] for f in
processing.features(inlayer)])
print unique_values
SUBREGION
as the dissolve field. You may choose any
field as the sum field as the script doesn’t have any code yet
to deal with it. Click Run.processing.runalg()
method.# Create a dictionary to hold values from the sum field
sum_unique_values = {}
attrs = [f.attributes() for f in processing.features(inlayer)]
for unique_value in unique_values:
val_list = [ f_attr[sum_field_index] for f_attr in attrs if f_attr[dissolve_field_index] == unique_value]
sum_unique_values[unique_value] = sum(val_list)
# Run the regular Dissolve algorithm
processing.runalg("qgis:dissolve", dissolve_layer, "false",
dissolve_field, output_layer)
# Add a new attribute called 'SUM' in the output layer
outlayer = processing.getObject(output_layer)
provider = outlayer.dataProvider()
provider.addAttributes([QgsField('SUM', QVariant.Double)])
outlayer.updateFields()
# Set the value of the 'SUM' field for each feature
outlayer.startEditing()
new_field_index = outlayer.fieldNameIndex('SUM')
for f in processing.features(outlayer):
outlayer.changeAttributeValue(f.id(), new_field_index, sum_unique_values[f[dissolve_field]])
outlayer.commitChanges()
SUBREGION
as the dissolve
field and POP_EST
as the sum field. Click Run.Note
The processing algorithm may take upto 10 minutes to finish depending on your system.
SUM
field with the
POP_EST
values from all original polygons added up.SUM
field and the field that was used to dissolve the
original layer. Click Save button and close the window.# Delete all fields except dissolve field and the newly created 'SUM' field.
outlayer.startEditing()
fields_to_delete = [fid for fid in range(len(provider.fields())) if fid != new_field_index and fid != dissolve_field_index]
provider.deleteAttributes(fields_to_delete)
outlayer.updateFields()
outlayer.commitChanges()
processing.features()
method to read features, it will respect the
current selection. To demonstrate that, let’s make a selection first. Click
on the Select features using an expression button."CONTINENT" = 'North America' OR "CONTINENT" = 'South America'
dissolve_with_sum
script and select Execute.output layer
will be added to QGIS. This will contain dissolved
geometries only from the selected features in the input layer. You will
also note that the output layer
will contain only 2 fields as expected.Below is the complete script for reference. You may modify it to suit your needs.
##dissolve_layer=vector
##dissolve_field=field dissolve_layer
##sum_field=field dissolve_layer
##output_layer=output vector
from qgis.core import *
from PyQt4.QtCore import *
inlayer = processing.getObject(dissolve_layer)
dissolve_field_index = inlayer.fieldNameIndex(dissolve_field)
sum_field_index = inlayer.fieldNameIndex(sum_field)
# Find unique values present in the dissolve field
unique_values = set([f[dissolve_field] for f in processing.features(inlayer)])
# Create a dictionary to hold values from the sum field
sum_unique_values = {}
attrs = [f.attributes() for f in processing.features(inlayer)]
for unique_value in unique_values:
val_list = [ f_attr[sum_field_index] for f_attr in attrs if f_attr[dissolve_field_index] == unique_value]
sum_unique_values[unique_value] = sum(val_list)
# Run the regular Dissolve algorithm
processing.runalg("qgis:dissolve", dissolve_layer, "false",
dissolve_field, output_layer)
# Add a new attribute called 'SUM' in the output layer
outlayer = processing.getObject(output_layer)
provider = outlayer.dataProvider()
provider.addAttributes([QgsField('SUM', QVariant.Double)])
outlayer.updateFields()
# Set the value of the 'SUM' field for each feature
outlayer.startEditing()
new_field_index = outlayer.fieldNameIndex('SUM')
for f in processing.features(outlayer):
outlayer.changeAttributeValue(f.id(), new_field_index, sum_unique_values[f[dissolve_field]])
outlayer.commitChanges()
# Delete all fields except dissolve field and the newly created 'SUM' field
outlayer.startEditing()
fields_to_delete = [fid for fid in range(len(provider.fields())) if fid != new_field_index and fid != dissolve_field_index]
provider.deleteAttributes(fields_to_delete)
outlayer.updateFields()
outlayer.commitChanges()
This work is licensed under a Creative Commons Attribution 4.0 International License