Pisanje Pajton skripti za okvir za obradu (QGIS3)¶
Moguće je pisati samostalne pyqgis skripte koje se mogu pokrenuti preko Python konzole u QGIS-u. Uz nekoliko podešavanja, možete naterati svoje samostalne skripte da se pokreću preko Processing Framework-a. Ovo ima nekoliko prednosti. Prvo, uzimanje korisničkog unosa i pisanje izlaznih datoteka je mnogo lakše jer Processing Framework nudi standardizovani korisnički interfejs za njih. Drugo, prisustvo vaše skripte u Processing Toolbox-u joj takođe omogućava da bude deo bilo kog modela obrade ili da se pokreće kao paketni zadatak sa više unosa. Ovaj tutorijal će pokazati kako napisati prilagođenu python skriptu koja može biti deo Processing Framework-a u QGIS-u.
Белешка
API za obradu je potpuno redizajniran u QGIS3. Molimo pogledajte ovaj vodič za najbolje prakse i savete.
Pregled zadatka¶
Naš skript će izvršiti operaciju rastvoravanja na osnovu polja koje je korisnik izabrao. Takođe će sumirati vrednosti drugog polja za rastvorene karakteristike. U primeru, rastvorićemo svetski shapefile na osnovu atributa „CONTINENT“ i sumirati polje „POP_EST“ da bismo izračunali ukupnu populaciju u rastvorenom regionu.
Dobijte podatke¶
Koristićemo skup podataka Admin 0 - Countries iz Natural Earth-a.
Preuzmite datoteku Admin 0 - countries shapefile..
Izvor podataka [NATURALEARTH]
Radi lakšeg snalaženja, možete direktno preuzeti geopaket koji sadrži gornji sloj odozdo:
Procedura¶
U QGIS panelu pregledača, pronađite direktorijum u koji ste sačuvali preuzete podatke. Proširite datoteku
zip
iligpkg
i izaberite slojne_10m_admin_0_countries
. Prevucite sloj na platno.

Idite na Skripte u traci sa alatkama i izaberite Kreiraj novu skriptu iz šablona.
. Kliknite na dugme

Šablon sadrži sav osnovni kod koji je potreban da bi ga Processing Framework prepoznao kao skriptu za obradu i upravljao ulazima/izlazima. Hajde da počnemo sa prilagođavanjem primernog šablona našim potrebama. Prvo promenite naziv klase iz
ExampleProcessingAlgorithm
uDissolveProcessingAlgorithm
. Ovo ime takođe treba ažurirati u metodicreateInstance
. Dodajte dokumentacioni string klasi koji objašnjava šta algoritam radi.

Kako se pomerate nadole, videćete metode koje dodeljuju ime, grupu, opis itd. skripti. Promenite povratne vrednosti za metod name na
dissolve_with_sum
, metod displayName naDissolve with Sum
, metod group i metod groupId nascripts
. Promenite povratnu vrednost metode shortHelpString na opis koji će se prikazati korisniku. Kliknite na dugme Sačuvaj.

Nazovite skriptu
dissolve_with_sum
i sačuvajte je na podrazumevanoj lokaciji u folderu .

Sada ćemo definisati ulaze za skriptu. Šablon već sadrži definiciju vektorskog sloja „INPUT“ i sloja „OUTPUT“. Dodaćemo 2 nova ulaza koja omogućavaju korisniku da izabere „DISSOLVE_FIELD“ i „SUM_FIELD“. Dodajte novi uvoz na vrhu i sledeći kod u metodi „initAlgorithm“. Kliknite na dugme Run da biste pregledali promene.
from qgis.core import QgsProcessingParameterField
self.addParameter(
QgsProcessingParameterField(
self.DISSOLVE_FIELD,
'Choose Dissolve Field',
'',
self.INPUT))
self.addParameter(
QgsProcessingParameterField(
self.SUM_FIELD,
'Choose Sum Field',
'',
self.INPUT))


Videćete dijalog Dissolve with Sum sa našim novodefinisanim ulazima. Izaberite sloj
ne_10m_admin_0_countries
kao Input layer`. Pošto su i Dissolve Field i Sum Fields filtrirani na osnovu ulaznog sloja, biće unapred popunjeni postojećim poljima iz ulaznog sloja. Kliknite na dugme Close.

Sada definišemo našu prilagođenu logiku za obradu podataka u metodi
processAlgorithm
. Ovoj metodi se prosleđuje rečnik pod nazivomparameters
. On sadrži ulaze koje je korisnik izabrao. Postoje pomoćne metode koje vam omogućavaju da uzmete ove ulaze i kreirate odgovarajuće objekte. Prvo dobijamo naše ulaze koristeći metodeparameterAsSource
iparameterAsString
. Zatim želimo da kreiramo stok karakteristika gde ćemo pisati izlaz. QGIS3 ima novu klasu pod nazivomQgsFeatureSink
, što je preferirani način za kreiranje objekata koji mogu da prihvate nove karakteristike. Izlazu su potrebna samo 2 polja - jedno za vrednost rastvorenog polja i drugo za zbir izabranog polja.
from PyQt5.QtCore import QVariant
from qgis.core import QgsField, QgsFields
source = self.parameterAsSource(
parameters,
self.INPUT,
context)
dissolve_field = self.parameterAsString(
parameters,
self.DISSOLVE_FIELD,
context)
sum_field = self.parameterAsString(
parameters,
self.SUM_FIELD,
context)
fields = QgsFields()
fields.append(QgsField(dissolve_field, QVariant.String))
fields.append(QgsField('SUM_' + sum_field, QVariant.Double))
(sink, dest_id) = self.parameterAsSink(
parameters,
self.OUTPUT,
context, fields, source.wkbType(), source.sourceCrs())


Sada ćemo pripremiti ulazne funkcije i kreirati rečnik koji će čuvati jedinstvene vrednosti iz polja za rastvaranje - dissolve_field i zbir vrednosti iz polja za sumu - sum_field. Obratite pažnju na upotrebu metode „feedback.pushInfo()“ za komunikaciju statusa sa korisnikom.
feedback.pushInfo('Extracting unique values from dissolve_field and computing sum')
features = source.getFeatures()
unique_values = set(f[dissolve_field] for f in features)
# Get Indices of dissolve field and sum field
dissolveIdx = source.fields().indexFromName(dissolve_field)
sumIdx = source.fields().indexFromName(sum_field)
# Find all unique values for the given dissolve_field and
# sum the corresponding values from the sum_field
sum_unique_values = {}
attrs = [{dissolve_field: f[dissolveIdx], sum_field: f[sumIdx]} for f in source.getFeatures()]
for unique_value in unique_values:
val_list = [ f_attr[sum_field] for f_attr in attrs if f_attr[dissolve_field] == unique_value]
sum_unique_values[unique_value] = sum(val_list)

Zatim ćemo pozvati ugrađeni algoritam za obradu
native:dissolve
na ulaznom sloju da bismo generisali rastvorene geometrije. Kada dobijemo rastvorene geometrije, iteriramo kroz izlaz algoritma za rastvorivanje i kreiramo nove karakteristike koje će biti dodate izlazu. Na kraju vraćamodest_id
FeatureSink kao izlaz. Sada je skripta spremna. Kliknite na dugme Run.
Белешка
Obratite pažnju na upotrebu „parameters[self.INPUT]“ za direktno preuzimanje ulaznog sloja iz rečnika parametara, bez definisanja istog kao izvora. Pošto prosleđujemo ulazni objekat algoritmu bez ikakve radnje sa njim, nije potrebno definisati ga kao izvor.
from qgis.core import QgsFeature
# Running the processing dissolve algorithm
feedback.pushInfo('Dissolving features')
dissolved_layer = processing.run("native:dissolve", {
'INPUT': parameters[self.INPUT],
'FIELD': dissolve_field,
'OUTPUT': 'memory:'
}, context=context, feedback=feedback)['OUTPUT']
# Read the dissolved layer and create output features
for f in dissolved_layer.getFeatures():
new_feature = QgsFeature()
# Set geometry to dissolved geometry
new_feature.setGeometry(f.geometry())
# Set attributes from sum_unique_values dictionary that we had computed
new_feature.setAttributes([f[dissolve_field], sum_unique_values[f[dissolve_field]]])
sink.addFeature(new_feature, QgsFeatureSink.FastInsert)
return {self.OUTPUT: dest_id}


U dijalogu Dissolve with Sum, izaberite
ne_10m_admin_0_countries
kao Ulazni sloj,CONTINENT
kao Polje za rastvorivanje iPOP_EST
kao Polje za sumiranje. Kliknite na Pokreni.

Kada je obrada završena, kliknite na dugme Zatvori i prebacite se na glavni QGIS prozor.

Videćete rastvoreni izlazni sloj sa po jednom karakteristikom za svaki kontinent i ukupnom populacijom sabranom iz pojedinačnih zemalja koje pripadaju tom kontinentu.

Još jedna prednost pisanja skripte za obradu je to što su metode unutar Processing Framework-a svesne izbora sloja i automatski filtriraju vaše ulaze da bi koristile samo odabrane karakteristike. To se dešava zato što definišemo naš ulaz kao „QgsProcessingParameterFeatureSource“. Izvor karakteristika omogućava korišćenje BILO KOJEG objekta koji sadrži vektorske karakteristike, ne samo vektorskog sloja, tako da kada postoje odabrane karakteristike u vašem sloju i zatražite od Processing-a da koristi odabrane karakteristike, ulaz se prosleđuje vašem skriptu kao objekat „QgsProcessingFeatureSource“ koji sadrži odabrane karakteristike, a ne ceo vektorski sloj. Evo kratke demonstracije ove funkcionalnosti. Recimo da želimo da rastvorimo samo određene kontinente. Hajde da napravimo izbor koristeći alatku Izaberi karakteristiku pomoću izraza.

Unesite sledeći izraz da biste izabrali obeležja iz Severne i Južne Amerike i kliknite na Izaberi.
"CONTINENT" = 'North America' OR "CONTINENT" = 'South America'

Videćete izabrane karakteristike označene žutom bojom. Pronađite skriptu „dissolve_with_sum“ i dvaput kliknite na nju da biste je pokrenuli.

U dijalogu Dissolve with Sum, izaberite
ne_10m_admin_0_countries
kao Input layer. Ovaj put, obavezno označite polje Samo selected features. IzaberiteSUBREGION
kao Dissolve field iPOP_EST
kao Sum field.

Kada se obrada završi, kliknite na Zatvori i vratite se na glavni QGIS prozor. Primetićete novi sloj sa samo odabranim objekatima rastvorenim. Kliknite na dugme Identifikuj i kliknite na objekat da biste proverili i potvrdili da je skripta ispravno radila.

Ispod je kompletan skript za referencu. Možete ga izmeniti prema svojim potrebama.
# -*- coding: utf-8 -*-
"""
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
from PyQt5.QtCore import QCoreApplication, QVariant
from qgis.core import (QgsProcessing,
QgsFeatureSink,
QgsFeature,
QgsField,
QgsFields,
QgsProcessingException,
QgsProcessingAlgorithm,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterField,
)
import processing
class DissolveProcessingAlgorithm(QgsProcessingAlgorithm):
"""
Dissolve algorithm that dissolves features based on selected
attribute and summarizes the selected field by cumputing the
sum of dissolved features.
"""
INPUT = 'INPUT'
OUTPUT = 'OUTPUT'
DISSOLVE_FIELD = 'dissolve_field'
SUM_FIELD = 'sum_field'
def tr(self, string):
"""
Returns a translatable string with the self.tr() function.
"""
return QCoreApplication.translate('Processing', string)
def createInstance(self):
return DissolveProcessingAlgorithm()
def name(self):
"""
Returns the algorithm name, used for identifying the algorithm. This
string should be fixed for the algorithm, and must not be localised.
The name should be unique within each provider. Names should contain
lowercase alphanumeric characters only and no spaces or other
formatting characters.
"""
return 'dissolve_with_sum'
def displayName(self):
"""
Returns the translated algorithm name, which should be used for any
user-visible display of the algorithm name.
"""
return self.tr('Dissolve with Sum')
def group(self):
"""
Returns the name of the group this algorithm belongs to. This string
should be localised.
"""
return self.tr('scripts')
def groupId(self):
"""
Returns the unique ID of the group this algorithm belongs to. This
string should be fixed for the algorithm, and must not be localised.
The group id should be unique within each provider. Group id should
contain lowercase alphanumeric characters only and no spaces or other
formatting characters.
"""
return 'scripts'
def shortHelpString(self):
"""
Returns a localised short helper string for the algorithm. This string
should provide a basic description about what the algorithm does and the
parameters and outputs associated with it..
"""
return self.tr("Dissolves selected features and creates and sums values of features that were dissolved")
def initAlgorithm(self, config=None):
"""
Here we define the inputs and output of the algorithm, along
with some other properties.
"""
# We add the input vector features source. It can have any kind of
# geometry.
self.addParameter(
QgsProcessingParameterFeatureSource(
self.INPUT,
self.tr('Input layer'),
[QgsProcessing.TypeVectorAnyGeometry]
)
)
self.addParameter(
QgsProcessingParameterField(
self.DISSOLVE_FIELD,
'Choose Dissolve Field',
'',
self.INPUT))
self.addParameter(
QgsProcessingParameterField(
self.SUM_FIELD,
'Choose Sum Field',
'',
self.INPUT))
# We add a feature sink in which to store our processed features (this
# usually takes the form of a newly created vector layer when the
# algorithm is run in QGIS).
self.addParameter(
QgsProcessingParameterFeatureSink(
self.OUTPUT,
self.tr('Output layer')
)
)
def processAlgorithm(self, parameters, context, feedback):
"""
Here is where the processing itself takes place.
"""
source = self.parameterAsSource(
parameters,
self.INPUT,
context
)
dissolve_field = self.parameterAsString(
parameters,
self.DISSOLVE_FIELD,
context)
sum_field = self.parameterAsString(
parameters,
self.SUM_FIELD,
context)
fields = QgsFields()
fields.append(QgsField(dissolve_field, QVariant.String))
fields.append(QgsField('SUM_' + sum_field, QVariant.Double))
(sink, dest_id) = self.parameterAsSink(
parameters,
self.OUTPUT,
context, fields, source.wkbType(), source.sourceCrs())
# Create a dictionary to hold the unique values from the
# dissolve_field and the sum of the values from the sum_field
feedback.pushInfo('Extracting unique values from dissolve_field and computing sum')
features = source.getFeatures()
unique_values = set(f[dissolve_field] for f in features)
# Get Indices of dissolve field and sum field
dissolveIdx = source.fields().indexFromName(dissolve_field)
sumIdx = source.fields().indexFromName(sum_field)
# Find all unique values for the given dissolve_field and
# sum the corresponding values from the sum_field
sum_unique_values = {}
attrs = [{dissolve_field: f[dissolveIdx], sum_field: f[sumIdx]}
for f in source.getFeatures()]
for unique_value in unique_values:
val_list = [ f_attr[sum_field]
for f_attr in attrs if f_attr[dissolve_field] == unique_value]
sum_unique_values[unique_value] = sum(val_list)
# Running the processing dissolve algorithm
feedback.pushInfo('Dissolving features')
dissolved_layer = processing.run("native:dissolve", {
'INPUT': parameters[self.INPUT],
'FIELD': dissolve_field,
'OUTPUT': 'memory:'
}, context=context, feedback=feedback)['OUTPUT']
# Read the dissolved layer and create output features
for f in dissolved_layer.getFeatures():
new_feature = QgsFeature()
# Set geometry to dissolved geometry
new_feature.setGeometry(f.geometry())
# Set attributes from sum_unique_values dictionary that we had computed
new_feature.setAttributes([f[dissolve_field], sum_unique_values[f[dissolve_field]]])
sink.addFeature(new_feature, QgsFeatureSink.FastInsert)
return {self.OUTPUT: dest_id}
If you want to give feedback or share your experience with this tutorial, please comment below. (requires GitHub account)