Wykorzystanie języka programowania Python w Quantum GIS

Python jest obiektowym językiem programowanie, który dzięki swojej prostocie i efektywności zyskuje coraz więcej zwolenników. Potwierdzeniem tego faktu jest przyznanie po raz kolejny nagrody dla najlepszego języka programowania i najlepszego języka skryptowego w 2012 r. w plebiscycie Readers’ Choice Awards magazynu Linux Journal. Główne cechy tego języka to:

  • prosta i czytelna składnia (m.in. dzięki wymuszeniu stosowania wcięć),
  • pełna i intuicyjna obiektowość,
  • język wysokiego poziomu (składnia jest łatwo zrozumiała dla człowieka),
  • działa na wielu rodzajach systemów – kod źródłowy, jeśli nie zawiera funkcji specyficznych dla danego systemu, działa w środowiskach Windows, Linux czy MacOS,
  • dynamiczny system typów,
  • duża liczba standardowych bibliotek,
  • możliwość instalowania dodatkowych modułów lub tworzenie własnych rozszerzeń.

Język ten sprawdza się zarówno do tworzenia prostych skryptów jak i rozbudowanych aplikacji, w tym serwisów WWW – popularny serwis YouTube, z którego korzystają miliony użytkowników dziennie, w większości stworzony jest właśnie w Pythonie.

Python umożliwia korzystanie z praktycznie wszystkich ważnych wolnych bibliotek związanych z GIS, w szczególności GDAL/OGR, proj4 czy GEOS. Dzięki nim można tworzyć zarówno proste narzędzia do przeglądania danych przestrzennych jak i zaawansowane aplikacje do ich analizy i przetwarzania. Wbudowane typy danych, jak listy, słowniki i krotki ułatwiają pracę z geometrią i atrybutami warstw wektorowych, a dzięki bibliotece numpy można łatwo operować na danych rastrowych. Oparcie Quantum GIS na bibliotece Qt, i możliwość wykorzystania nakładki dla języka Python o nazwie PyQt, pozwala na wykorzystanie bogatych możliwości związanych w szczególności z budową graficznych interfejsów (np. tworzenie okien wtyczek, dodatkowych paneli w oknie głównym, zarządzanie paskami narzędzi) oraz ich przenośności między różnymi systemami (Windows, Mac OS X, Linux) bez konieczności modyfikowania kodu źródłowego.

Wsparcie dla języka Python pojawiło się w Quantum GIS 0.9.0 wydanym w październiki 2007 r. Od tego powstało wiele narzędzi, głównie w postaci wtyczek, które rozszerzyły funkcjonalność tej aplikacji. Najlepszym przykładem jest fTools zawierający wiele przydatnych algorytmów do geoporcessingu, analiz przestrzennych czy operacji na geometrii i atrybutach obiektów. Warto również zwrócić uwagę na rozwijaną od pewnego czasu wtyczkę SEXTANTE, która również została stworzona w Pythonie. Posiada ona bogate możliwości m.in. integruje funkcjonalność zewnętrznych aplikacji takich jak SAGA GIS, GRASS GIS czy Orfeo Toolbox, pozwala tworzyć własne skrypty (wykorzystując oczywiście Pythona) czy budować modele obliczeniowe oparte na dostępnych modułach i algorytmach.

Jednak korzystanie z Pythona w Quantum GIS nie ogranicza się jedynie do wtyczek. Poniżej przedstawione zostały możliwości, dzięki którym można wykorzystać ten język programowania do usprawnienia codziennej pracy.

  1. Konsola Pythona
  2. Wtyczki
  3. Akcje
  4. Samodzielna aplikacja
  5. Script Runner
  6. Własne funkcje w generatorze wyrażeń
  1. Konsola Pythona

Wbudowana w Quantum GIS konsola Pythona pozwala użytkownikowi na bezpośrednią interakcję z uruchomionym środowiskiem oraz korzystanie z udostępnionego API. Bezpośrednie wpisywanie komend pozwala na szybkie wykonanie pojedynczych czynności lub przetestowanie prostych algorytmów bez konieczności tworzenia skryptów lub dodatkowych modułów.

Aby uruchomić konsolę należy z menu ‚Wtyczki’ wybrać ‚Konsola Pythona’. Od razu po  uruchomieniu użytkownik ma dostęp do instancji klasy QgisInterface (poprzez obiekt qgis.utils.iface, a w wersji rozwojowej master iface), dzięki któremu można operować w środowisku Quantum GIS. Pozwala ona m.in. na dostęp do wczytanych warstw, obszaru mapy czy ustawień aplikacji. Importując moduły qgis.core i qgis.gui użytkownik ma pełny dostęp do API Quantum GIS.

Przykładowa sesja z konsoli Pythona:

>>> warstwa = qgis.utils.iface.activeLayer()
>>> warstwa.featureCount()
342L
>>> obiekt = QgsFeature()
>>> warstwa.featureAtId(25,obiekt,True,True)
True
>>> obiekt.attributeMap()
{0: , 1: , 2: , 3: , 4: , 5: }
>>> str(obiekt.attributeMap()[2].toString())
'Wysoczyzna Lubartowska'
>>> obiekt.geometry().area()
1565346973.9045937

[notice] Aktualnie w wersji rozwojowej QGIS konsola Pythona została znacząco rozbudowana. Dodano m.in. kolorowanie składni, autouzupełnianie poleceń, rozdzielono obszar wpisywania poleceń od okna reprezentującego ich wynik. Ponadto możliwe jest wczytywanie skryptów z plików tekstowych.

new_console[/notice]

  1. Wtyczki

Wbudowany system wtyczek (ang. plugins), o których wspomniano we wstępie, umożliwia tworzenie dodatkowych narzędzi rozszerzających standardowe możliwości Quantum GIS. Aplikacja ta wspiera wtyczki napisane w C++ oraz w Pythonie, jednak zdecydowanie większość stanowią te drugie. W sieci dostępne są zarówno proste wtyczki wykonujące pojedyncze czynności jak i rozbudowane aplikacje o szerokich możliwościach jak np. SEXTANTE i fTools (oba pluginy są integralną częścią QGIS). Dostępność tak dużej ilość różnorodnych rozszerzeń związana jest z prężną społecznością użytkowników Quantum GIS.

Popularność wtyczek napisanych w Pythonie związana jest z prostym i szybkim procesem ich tworzenia – niemal każda osoba znająca podstawy programowania może stworzyć prostą wtyczkę dostosowaną do własnych potrzeb. Dzięki wykorzystaniu standardowych modułów, bądź doinstalowując dodatkowe biblioteki, możliwości są niemal nieograniczone. Warto w tym miejscu wspomnieć o dwóch narzędziach, które ułatwiają proces tworzenia wtyczek: Plugin Builder i Plugin Reloader. Pierwszy umożliwia szybkie stworzenie szablonu dla nowej wtyczki wraz z podstawowym oknem, drugi pozwala zresetować wtyczkę po zmianie jej kodu źródłowego bez konieczności uruchamiania okna do zarządzania wtyczkami lub wyłączania QGIS.

Quantum GIS udostępnia wygodny instalator wtyczek. Dostępny jest on w menu ‚Wtyczki’ po wybraniu pozycji ‚Pobierz więcej wtyczek…’. Instalowane wtyczki pobierane są z tzw. repozytoriów. Standardowo dostępne jest oficjalne repozytorium Quantum GIS. Istnieje również możliwość dodawania innych repozytoriów. Kilka adresów dostępnych jest pod adresem http://hub.qgis.org/projects/quantum-gis/wiki/Python_Plugin_Repositories. Ponadto każdy użytkownik może stworzyć własne repozytorium poprzez utworzenie specjalnego pliku XML i dodanie ścieżki do niego w Instalatorze wtyczek.

[important]Niektóre wtyczki oznaczone są jako eksperymentalne. Domyślnie nie są one wyświetlane w oknie pobierania, aby mieć do nich dostęp należy zaznaczyć odpowiednią opcję w Instalatorze.[/important]

OknoZarządzanie wtyczkami’ umożliwia włączanie i wyłączanie wtyczek. Najczęściej po włączeniu wtyczki jej ikona pojawia się na pasku narzędzi oraz w jednym z menu – w zależności od przeznaczenia wtyczki podzielone są na kilka kategorii m.in. Internet, Wektor, Raster, Bazy danych. Niektóre wtyczki są dostępne w inny sposób, np. SEXTANTE i qNote tworzą dodatkowe panele w oknie głównym QGIS, które można włączyć z menu dostępnym pod prawym przyciskiem myszy.

  1. Akcje

Akcje stanowią ciekawą możliwość dostosowania projektu i interakcję użytkownika z obiektami warstwy na podstawie ich atrybutów. Dzięki temu możliwe jest uruchomienie zewnętrznej aplikacji z parametrami pobranymi z tabeli atrybutów i np. otworzenie pliku graficznego lub wyświetlenie strony w przeglądarce. Z kilku rodzajów dostępnych akcji największe możliwości daje Python.

open_wiki_action

Okno zarządzania akcjami.
Źródło kodu: Linfiniti Geo Blog

Powyższy obrazek przedstawia okno do zarządzania akcjami z poziomu właściwości warstwy wektorowej. Podany w przykładzie kod utworzy okno przeglądarki i wyświetli stronę Wikipedii z informacjami o wybranym mezoregionie z warstwy z podziałem fizjograficznym.

Innym ciekawym przykładem obrazującym możliwości wykorzystania akcji jest połączenie z narzędziem gdaltindex z pakietu GDAL. Program ten tworzy warstwę wektorową z zasięgiem rastrów ze wskazanego katalogu. W ten sposób można np. utworzyć indeks sąsiadujących arkuszy map topograficznych lub ortofotomap. location to pole w tabeli atrybutów przechowujące nazwy plików rastrowych. Wywołanie poniższej akcji spowoduje wczytanie wybranego rastra do Quantum GIS (plik warstwy i rastry znajdują się w tym samym katalogu):

import os.path
warstwa = qgis.utils.iface.activeLayer()
katalog = os.path.dirname(str(warstwa.source()))
qgis.utils.iface.addRasterLayer(os.path.join(katalog,'[% "location" %]'), '[% "location" %]')

 

  1. Samodzielna aplikacja

Opisane powyżej sposoby wykorzystania Pythona wymagały uruchomienia programu Quantum GIS. Jednak do korzystania z klas i metod udostępnianych przez QGIS nie jest to konieczne. Wystarczy stworzyć plik .py, zaimportować w nim moduł qgis.core i zainicjować sterowniki do odczytu danych aby uzyskać dostęp do kluczowych funkcjonalności takich jak ładowanie warstw, dostęp do obiektów (geometrii i atrybutów) czy narzędzi geoprocessingu. Wszystko to wykonuje się w trzech linijkach kodu! Dzięki temu tworzenie skryptów jest znacznie łatwiejsze – programista skupia się na tworzonym kodzie i jego funkcjonalności, a nie o poszczególne elementy jak np. dostęp do warstwy i odczyt danych. Dla wygody użytkowania można również stworzyć aplikację okienkową np. do podglądu wczytanych warstw. Moduł qgis.gui zawiera komponenty związane z interfejsem użytkownika, w szczególności warto zwrócić uwagę na kontrolkę widoku mapy (klasa QgsMapCanvas), na której można wyświetlać załadowane warstwy.

Aby móc skorzystać z klas i metod udostępnianych przez program Quantum GIS należy zaimportować moduł qgis.core (i ewentualnie qgis.gui), ustawić katalog instalacyjny QGIS i wyszukać sterowniki dostępu do różnych typów danych:

from qgis.core import *
QgsApplication.setPrefixPath(r"/katalog/instalacyjny/qgis", True)
QgsApplication.initQgis()

Po zakończeniu pracy należy usunąć zbędne śmieci z pamięci komputera:

QgsApplication.exitQgis()

[notice]

Ważne jest odpowiednie ustawienie zmiennych środowiskowych, tak aby interpreter Pythona wiedział gdzie szukać odpowiednich bibliotek:

Windows:

set PYTHONPATH=%PYTHONPATH%;c:\qgispath\python
set PATH=%PATH%;c:\qgispath\bin

Linux:

export PYTHONPATH=%PYTHONPATH%;/qgispath/share/qgis/python
export PATH=%PATH%;/qgispath/bin

, gdzie qgispath to katalog instalacyjny Quantum GIS.

[/notice]

  1. Wtyczka Script Runner

Wtyczka pozwala na uruchamianie skryptów bezpośrednio z okna QGIS w celu automatyzacji czynności. Dokładniejszy opis tego narzędzia można znaleźć w dziale Wtyczki.

  1. Własne funkcje w generatorze wyrażeń

[notice]Opisana poniżej funkcjonalność dostępna jest w chwili obecnej w wersji rozwojowej Quantum GIS (tzw. master)[/notice]

Generator wyrażeń (ang. expression builder) zwraca wartość w oparciu o wyrażenie zdefiniowane przez użytkownika. W wyrażeniu mogą być używane funkcje, nazwy pól (przekazujące wartość pola dla każdego z obiektów warstwy) lub informacje o geometrii obiektów. Quantum GIS wykorzystuje generator wyrażeń  do stylizacji warstw w oparciu o zdefiniowane reguły, etykietowania obiektów oraz w kalkulatorze pól dostępnym w tabeli atrybutów.

generator_wyrazen

Okno generatora wyrażeń

Standardowo generator wyrażeń zawiera wiele funkcji pogrupowanych w kilku kategoriach m.in. związanych z konwersją danych, dostępem do danych z tabeli atrybutów czy geometrii oraz funkcjami matematycznymi. Dostępną standardowo listę można rozszerzyć dodając własne funkcje. Umożliwia to dodanie nowych funkcji, niedostępnych standardowo, jak również uproszczenie wyrażeń złożonych z wielu funkcji, dzięki czemu nie trzeba za każdym razem wpisywać skomplikowanych formuł.

Poniżej podstawowy kod do zarejestrowania własnej funkcji:

from qgis.utils import qgsfunction

@qgsfunction(0, "Nazwa kategorii")
def vertices(values, feature, parent):
 pass

Aby zarejestrować funkcję w QGIS należy użyć dekoratora @qgsfunction. W tym celu należy przed definicją funkcji wpisać @qgsfunction(0, „Nazwa kategorii”). Dekorator przyjmuje dwa parametry: pierwszy to liczba parametrów, które przyjmuje funkcja; drugi to nazwa kategorii, do której przypisana zostanie funkcja w generatorze wyrażeń. Sama funkcja przekazuje trzy parametry:

  • values – lista zawierająca parametry podane przez użytkownika w oknie generatora (liczba elementów w liście określona jest pierwszym parametrem dekoratora @qgsfunction) – wszystkie elementy listy są typu QVariant,
  • feature – przekazuje obiekt warstwy (klasa QgsFeature),
  • parent – wskaźnik do klasy QgsExpression, służy do obsługi wyjątków (parent.setEvalErrorString(‚Treść błędu’))

Dwa ostatnie parametry, jeśli nie są używane mogą zostać zastąpione przez zastąpienie ich parametrem *args:

@qgsfunction(0, "Nazwa kategorii")
def vertices(values, *args):
 pass

Poniższe przykładowe funkcje formatCoordXformatCoordX pozwalają zapisać w tabeli atrybutów współrzędne punktu w formie stopnie, minuty, sekundy np. 22 35′ 12″.

#-*- coding: windows-1250 -*-
"""Konwersja współrzędnych do zapisu geograficznego (stopnie, minuty, sekundy)
Piotr Pociask (2013)
"""

#import niezbędnych modułów
from qgis.utils import qgsfunction
from qgis.core import QGis, QgsCoordinateReferenceSystem, QgsCoordinateTransform
from math import floor

#rejestracja funkcji
@qgsfunction(1, "Python")
def formatCoordX(values, feature, parent):
 """
 Konwertuje współrzędną X do zapisu stopień, minuta, sekunda.
 Funkcja jako parametr przyjmuje kod EPSG odwzorowania warstwy punktowej.
 """
 #values - argumenty przekazane przez użytkownika
 #feature - klasa QgsFeature
 #parent - wskaźnik do generatora
 return coordinates(values, feature, True)

#rejestracja funkcji
@qgsfunction(1, "Python")
def formatCoordY(values, feature, parent):
 """
 Konwertuje współrzędną Y do zapisu stopień, minuta, sekunda.
 Funkcja jako parametr przyjmuje kod EPSG odwzorowania warstwy punktowej.
 """
 return coordinates(values, feature, False)

#funkcja transformująca współrzędne punktu między układami
def coordinates(values, feature, doX):
 #pobranie geometrii obiektu
 geom = feature.geometry()
 if geom is None: return None
 if geom.wkbType() == QGis.WKBPoint:
 #zdefiniowanie układów współrzędnych: warstwy punktowej i docelowego układu WGS 84
 sourceCrs = QgsCoordinateReferenceSystem(values[0].toInt()[0], QgsCoordinateReferenceSystem.EpsgCrsId)
 destCrs = QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
 transform = QgsCoordinateTransform(sourceCrs, destCrs)
 #transformacja współrzędnych pomiędzy układami
 destCoords = transform.transform(geom.asPoint())
 if doX: return formatCoords(destCoords.x())
 else: return formatCoords(destCoords.y())
 else:
 return None

#funkcja konwertująca stopnie dziesiętne na współrzędne geograficzna (stopnie, minuty, sekundy)
def formatCoords(coord):
 degree = int(floor(coord))
 minutes = (coord-degree)*60
 seconds = (minutes - floor(minutes)) * 60
return "%d %d' %.2f''" % (degree, int(minutes), seconds)

Plik z kodem, np. coords.py, należy zachować w katalogu /.qgis/python, znajdującym się standardowo w folderze użytkownika, lub w innym miejscu „widzianym” przez QGIS (znajdującym się w zmiennej środowiskowej PATH). Aby móc skorzystać ze stworzonych funkcji w generatorze wyrażeń należy jeszcze ją załadować w Quantum GIS. Można to zrobić ręcznie w konsoli Pythona dla jednej sesji poprzez wpisanie import coords.py. Funkcje mogą być również ładowane za pomocą wtyczki, należy jednak pamiętać aby wyrejestrować funkcję poleceniem QgsExpression.unregisterFunction(nazwa_funkcji) jeśli użytkownik wyłączy wtyczkę – zapobiegnie to ewentualnym błędom.

Jeśli chcemy aby stworzone funkcje były zawsze widoczne w QGIS bez konieczności ich ręcznego ładowania w konsoli lub tworzenia dodatkowych rozszerzeń można wykorzystać plik setup.py. Plik ten jest przetwarzany podczas uruchamiania Quantum GIS, w związku z czym można go wykorzystać do automatycznego rejestrowania utworzonych funkcji. Plik setup.py należy stworzyć w katalogu /.qgis/python, znajdującym się standardowo w folderze użytkownika. Aby funkcja była dostępna w generatorze wyrażeń można ją bezpośrednio umieścić w setup.py lub załadować moduł, w którym jest jej definicja. Zgodnie z powyższym przykładem wygląda to następująco:

from coords.py import formatCoordX, formatCoordY

lub

from coords.py import *

Podsumowanie

Powyższy opis wykorzystania języka Python w Quantum GIS nie zamyka wszystkich możliwości, jednak obrazuje w jak szerokim zakresie możliwe jest dostosowanie tej aplikacji dzięki połączeniu obu środowisk. Prosta składnia Pythona oraz dostępność wielu dodatkowych bibliotek pozwala użytkownikom uzupełnić brakujące funkcjonalności lub dostosowania istniejące algorytmy do własnych potrzeb.