Algorytmy danych geoprzestrzennych
Skrypty geoprzetwarzania w QGIS
Krzysztof Dyba
Narzędzia przetwarzania (Processing Toolbox) w QGIS są kompleksowym systemem do uruchamiania algorytmów analizy geoprzestrzennej. Algorytmy te mogą pochodzić z różnych źródeł:
- Natywne algorytmy (wbudowane bezpośrednio w QGIS i napisane w C++ dla większej wydajności).
- Zewnętrzne algorytmy (pochodzące z różnych aplikacji, np. SAGA GIS czy GRASS GIS).
- Własne skrypty przetwarzania.
Skrypty przetwarzania są pisane przy użyciu języka Python i wykorzystują QGIS Python API (PyQGIS) do interakcji z danymi przestrzennymi. Skrypty te muszą przestrzegać określonej struktury, w tym definiować dane wejściowe, wyjściowe i logikę algorytmu. Istnieje kilka możliwości ich zastosowania:
- bezpośrednie uruchomienie z poziomu interfejsu QGIS,
- wykorzystanie w kreatorze modeli (model designer) do tworzenia złożonych przepływów pracy,
- użycie do przetwarzania wsadowego,
- odwołanie się z poziomu wbudowanej konsoli Python.
Aby stworzyć nowy skrypt przetwarzania w QGIS należy:
- Otworzyć panel algorytmów w zakładce Processing (
CTRL
+ALT
+T
). - Kliknąć ikonę “Twórz nowy skrypt” (alternatywnie można wykorzystać gotowy szablon).
- Napisać kod zgodnie z wymaganą strukturą.
- Zapisać plik z rozszerzeniem
.py
w katalogu ze skryptami w QGIS (będzie dostępny w zakładce “Skrypty” w panelu algorytmów).
Struktura skryptu
Do tworzenia skryptów przetwarzania można wybrać jeden z dwóch sposobów:
- Wykorzystanie klasy QgsProcessingAlgorithm. Szablon dostępny jest tutaj.
- Wykorzystanie dekoratora
@alg
, który umożliwia modyfikację metody lub klasy bez bezpośredniej zmiany ich kodu (wrapping). Jest to sposób uproszczony z brakiem możliwości użycia we wtyczkach. Szablon dostępny jest tutaj.
Przykładowe skrypty znajdziesz w repozytorium QGIS.
Wyświetlenie metadanych
Zacznijmy od napisania prostego skryptu używając dekoratora @alg
, który umożliwi wyświetlenie metadanych warstwy wektorowej. Obligatoryjnie musimy zdefiniować cztery elementy:
- Dekorator
@alg
służący do definiowania nazwy i lokalizacji algorytmu w panelu algorytmów. - Dekorator
@alg.input
służący do definiowania danych wejściowych. - Dekorator
@alg.output
służący do definiowania danych wyjściowych. - Logikę algorytmu.
Oprócz tego, wymagana jest dokumentacja (opis) wewnątrz funkcji używając docstrings
(jeśli tego nie uwzględnimy, zostanie zwrócony błąd).
Dane wyjściowe muszą zostać jawnie zdefiniowane, tzn. należy dokładnie wskazać, co jest wynikiem działania algorytmu. W przeciwnym razie nie będzie można poprawnie użyć skryptu w przetwarzaniu sekwencyjnym (np. w modelerze). Algorytm może przyjmować i zwracać dane różnego typu (niekoniecznie warstwy), np. łańcuchy tekstu, liczby czy wartości logiczne. Wszystkie typy danych wejściowych i wyjściowych dla algorytmów przetwarzania znajdziesz tutaj. Do przetwarzania przydatne będą również metody ewaluacji parametrów opisane tutaj. Jeśli algorytm posiada poprawnie zdefiniowane wyjście (warstwa wektorowa, rastrowa, chmura punktów), to automatycznie zostanie dodane do projektu.
Danymi wejściowymi w naszej funkcji będzie warstwa wektorowa wybrana przez użytkownika za pomocą interfejsu, a danymi wyjściowymi łańcuch tekstu opisujące metadane tej warstwy (np. nazwa, źródło, liczba obiektów, typ geometrii, zakres przestrzenny oraz układ przestrzenny) jako słownik.
from qgis.processing import alg
@alg(name = "vector_metadata", label = "Print metadata of vector layer",
= "examplescripts" , group_label = "Example scripts")
group @alg.input(type = alg.VECTOR_LAYER, name = "INPUT", label = "Input vector layer")
@alg.output(type = alg.STRING, name = "OUTPUT", label = "Metadata")
def vector_metadata(instance, parameters, context, feedback, inputs):
"""
Print metadata of vector layer
"""
# QgsVectorLayer
= instance.parameterAsVectorLayer(parameters, "INPUT", context)
layer
= layer.name()
name = layer.dataProvider().dataSourceUri()
data_source = layer.featureCount()
num_features = layer.geometryType()
geometry_type = layer.extent().toString(precision = 2)
extent = layer.crs().authid()
crs
= {
output "Layer name": name,
"Data source": data_source,
"Number of features": num_features,
"Geometry type": geometry_type,
"Extent": extent,
"CRS": crs
}
# sprawdź czy użytkownik anulował operację
if feedback.isCanceled():
return {}
return output
Stworzenie buforów
Zobaczmy teraz jak wygląda bardziej zaawansowany skrypt, który stworzy bufory geometrii i zapisze wynik w lokalizacji określonej przez użytkownika. Jako wynik działania zostanie zwrócona ścieżka do utworzonego pliku.
from qgis.processing import alg
from qgis.core import QgsVectorLayer, QgsFeature, QgsVectorFileWriter
@alg(name = "buffers", label = "Calculate buffers",
= "examplescripts" , group_label = "Example scripts")
group @alg.input(type = alg.SOURCE, name = "INPUT", label = "Input vector layer")
@alg.input(type = alg.DISTANCE, name = "BUFFERDIST", label = "Buffer distance")
@alg.input(type = alg.INT, name = "SEGMENTS", label = "Buffer segments", default = 15)
@alg.input(type = alg.VECTOR_LAYER_DEST, name = "OUTPUT_PATH", label = "Output path")
@alg.output(type = alg.FILE, name = "OUTPUT", label = "Buffers")
def buffers(instance, parameters, context, feedback, inputs):
"""
Calculate buffers
"""
= instance.parameterAsVectorLayer(parameters, "INPUT", context)
layer = instance.parameterAsDouble(parameters, "BUFFERDIST", context)
bufferdist = instance.parameterAsInt(parameters, "SEGMENTS", context)
segments = instance.parameterAsOutputLayer(parameters, "OUTPUT_PATH", context)
output_path
= layer.crs().authid()
crs = QgsVectorLayer("Polygon?crs=" + crs, "Buffer", "memory")
buffer_layer
if feedback.isCanceled():
return {}
= []
features for feature in layer.getFeatures():
= feature.geometry()
geom = geom.buffer(bufferdist, segments)
buffer_geom = QgsFeature()
buffer_feature
buffer_feature.setGeometry(buffer_geom)
features.append(buffer_feature)
buffer_layer.dataProvider().addFeatures(features)
buffer_layer.updateExtents()
if feedback.isCanceled():
return {}
QgsVectorFileWriter.writeAsVectorFormatV3(= buffer_layer,
layer = output_path,
fileName = context.transformContext(),
transformContext = QgsVectorFileWriter.SaveVectorOptions()
options
)
return {"OUTPUT": output_path}
Zadania
- Zaimplementuj wybrany przez siebie algorytm lub narzędzie z poprzednich zajęć jako skrypt przetwarzania w QGIS.