Python-scripts schrijven voor framework Processing

Men kan zelfstandige scripts in Pyqgis schrijven die kunnen worden uitgevoerd in de Python Console in QGIS. Met een aantal aanpassingen kunt u uw scripts voor Pyqgis ook uitvoeren via het framework Processing. Dat heeft een aantal voordelen. Ten eerste is het invoeren van invoer door de gebruiker en het schrijven van uitvoerbestanden veel eenvoudiger omdat het framework Processing hier een gestandaardiseerde gebruikersinterface voor biedt. Ten tweede, door uw script te hebben in de Processing Toolbox kan het ook deel uitmaken van elk Model voor Processing of worden uitgevoerd als een Batch-taak met meerdere invoer. Deze handleiding zal laten zien hoe een aangepast script voor Python te schrijven dat deel kan uitmaken van het framework Processing in QGIS.

Overzicht van de taak

Ons script zal een bewerking voor ontbinden uitvoeren, gebaseerd op een door de gebruiker gekozen veld. Het zal ook de waarden van een ander veld bij elkaar optellen voor de ontbonden objecten. In het voorbeeld zullen we een world shapefile ontbinden, gebaseerd op een attribuut SUBREGION en het veld POP_EST optellen om de totale bevolking in de ontbonden regio te berekenen.

Notitie

Als u zoekt naar een mogelijkheid om een bewerking Dissolve naast Statistieken uit te voeren, kunt u de excellente plug-in DissolveWithStats gebruiken. Dit script is een demonstratie van hoe een soortgelijke functionaliteit te implementeren via een script voor Processing.

De gegevens ophalen

We zullen de gegevensset Admin 0 - Countries van Natural Earth gebruiken.

Download het Admin 0 - countries shapefile..

Gegevensbron [NATURALEARTH]

Voor het gemak kunt u direct een kopie van de gegevensset downloaden vanaf de links hieronder:

ne_10_admin_0_countries.zip

Procedure

  1. Open QGIS en ga naar Kaartlagen ‣ Laag toevoegen ‣ Vectorlaag toevoegen. Blader naar het gedownloade bestand ne_10_admin_0_countries.zip en laadt de laag ne_10_admin_0_countries. Ga naar Processing ‣ Toolbox.

../_images/1108.png
  1. Vergroot de groep Scripts in de Processing Toolbox en selecteer Nieuw script aanmaken.

../_images/260.png
  1. Het begin van het script moet voldoen aan de specificaties voor invoer en uitvoer om een script voor Python te kunnen laten herkennen als een script voor Processing. Dat zal worden gebruikt om de gebruikersinterface te construeren om het script uit te voeren. U kunt meer te weten komen over de indeling van deze regels in de QGIS Processing-documentatie. Voer de volgende regels in de Script editor in. Hier specificeren we 3 gebruikersinvoeren: dissolve_layer, dissolve_field en sum_field. Merk op dat we dissolve_layer toevoegen na de beide definities voor veldinvoer. Dit betekent dat de invoer vooraf zal worden gevuld met de keuze van de velden in dissolve_layer. We specificeren ook de output_layer als de uitvoer vectorlaag. Klik op de knop Opslaan.

##dissolve_layer=vector
##dissolve_field=field dissolve_layer
##sum_field=field dissolve_layer
##output_layer=output vector
../_images/336.png
  1. Noem het script dissolve_with_sum en sla het op op de standaard locatie in de map .qgis2 ‣ processing ‣ scripts.

../_images/426.png
  1. Klik, terug in de Script editor, op de knop Start algoritme om een voorbeeld te zien van de gebruikersinterface.

../_images/527.png
  1. U ziet dat we, slechts door het toevoegen van een aantal regels, een keurige gebruikersinterface hebben om de invoer te kunnen specificeren. Het is ook consistent met alle andere algoritmes voor Processing, dus is er geen leercurve voor het gebruiken van uw eigen aangepaste algoritme.

../_images/625.png
  1. Voer, in de Script editor, de volgende code in. Het zal u opvallen dat we enkele speciale methoden gebruiken zoals processing.getObject() en processing.features(). Dit zijn wrappers voor het gemak die het eenvoudiger maken om met gegevens te werken. U kunt hier meer over te weten komen in het gedeelte Aanvullende functies voor het afhandelen van gegevens van de QGIS Processing-documentatie. Klik op Opslaan om de nieuw ingevoerde code op te slaan en dan op de knop X om de bewerker te sluiten.

Notitie

Dit script gebruikt zeer veel Python samenvattingen uit lijsten. Bekijk deze list comprehension tutorial eens om bekend te geraken met de syntaxis.

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
../_images/724.png
  1. Bij het schrijven van code is het belangrijk om de fouten te kunnen zien en uw code te kunnen debuggen. Uw scripts voor Processing kunnen eenvoudig worden gedebugd via de ingebouwde Python Console. Ga, in het hoofdvenster van QGIS, naar Plug-ins ‣ Python Console. Zoek, als de console eenmaal is geopend, naar uw script in de Processing Toolbox en dubbelklik erop om het te starten.

../_images/823.png
  1. Selecteer SUBREGION als het dissolve field. U mag elk veld kiezen als het sum field omdat het script nog geen code heeft om dat af te handelen. Klik op Run.

../_images/921.png
  1. U zult een dialoogvenster voor foutberichten zien. Dat werd verwacht omdat het script nog niet volledig is en nog geen uitvoer genereert.

../_images/1022.png
  1. In het hoofdvenster van QGIS zult u de uitvoer voor debuggen van het script zien afgedrukt in de console. Dit is een handige manier om argumenten voor afdrukken toe te voegen en tussenliggende waarden voor variabelen te zien.

../_images/1125.png
  1. Laten we terug gaan naar het bewerken van het script door met rechts te klikken op het script en te selecteren Script bewerken.

../_images/1223.png
  1. Voer de volgende code in om het script te voltooien. Merk op dat we het bestaande algoritme Dissolve in QGIS gebruiken via Processing met behulp van de methode processing.runalg().

# 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()
../_images/1320.png
  1. Voer het algoritme uit door SUBREGION te selecteren als het dissolve field en POP_EST als het sum field. Klik op Run.

Notitie

Het algoritme van Processing kan tot 10 minuten nodig hebben om te voltooien, afhankelijk van uw systeem.

../_images/1419.png
  1. Als de verwerking is voltooid kunt u het gereedschap Objecten identificeren gebruiken en op een willkeurige polygoon klikken. U zult het nieuw toegevoegde veld SUM zien met de waarden van POP_EST uit alle originele polygonen bij elkaar opgeteld.

../_images/1518.png
  1. U zult zien dat alle andere velden in de uitvoer nog steeds aanwezig zijn. Wanneer u vele objecten ontbindt om één enkel object te maken, heeft het geen zin om de originele velden in de uitvoer te behouden. Ga terug naar de Script editor en voeg de volgende toe om alle velden, met uitzondering van het veld SUM en het veld dat werd gebruikt om de originele laag te ontbinden, te verwijderen. Klik op de knop Opslaan en sluit het venster.

# 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()
../_images/1617.png
  1. Eén van de verborgen mogelijkheden van het framework Processing is dat alle algoritmes kunnen werken op geselecteerde objecten van een laag. Dat is enorm handig als u een algoritme wilt uitvoeren op een subset van een laag. Omdat ons script de methode processing.features() gebruikt om objecten te lezen, zal het de huidige selectie respecteren. Laten we, om dat te demonstreren, eerst een selectie maken. Klik op de knop Selecteren van objecten gebruik makend van een expressie.

../_images/1716.png
  1. Voer de volgende expressie in om objecten te selecteren uit Noord- en Zuid-Amerika en klik op Selecteren.

"CONTINENT" = 'North America' OR "CONTINENT" = 'South America'
../_images/1816.png
  1. U zult de geselecteerde objecten zien geaccentueerd in geel. Klik met rechts op het script dissolve_with_sum en selecteer Uitvoeren.

../_images/1914.png
  1. Selecteer de invoer zoals eerder en klik op Run.

../_images/2011.png
  1. Een nieuwe output layer zal worden toegevoegd aan QGIS. Deze zal alleen de ontbonden geometrieën bevatten uit de geselecteerde objecten van de invoerlaag. U zult ook zien dat de output layer, zoals verwacht, slechts 2 velden zal bevatten.

../_images/2116.png
  1. Een laatste maar belangrijk resterend punt is om ons algoritme te documenteren. Het framework Processing heeft leuke gereedschappen om Help te schrijven en er toegang tot te verkrijgen. Ga naar de Script editor en klik op de knop Help-script bewerken.

../_images/2215.png
  1. Vul de details in voor de verschillende elementen en klik op OK. Nu zal een gedetailleerde Help beschikbaar zijn voor alle gebruikers van uw script op de tab Help als zij het algoritme starten.

../_images/2312.png

Hieronder staat het volledige script als verwijzing. U kunt het aanpassen zodat het aan uw eigen wensen voldoet.

##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()
comments powered by Disqus

This work is licensed under a Creative Commons Attribution 4.0 International License