04. QGIS - tvorba zásuvného modulu¶
V této části se zaměříme na tvorbu zásuvných modulů pro software QGIS.
Založme zásuvný modul na posledním příkladu z minulého cvičení. Pro větší přehlednost tak učiníme v následujících krocích. Takový postup je doporučován z toho důvodu, že se řeší zvlášť možné problémy vzniknuvší při implementaci funkcionality a při tvorbě zásuvného modulu.
- tvorba funkce
- ze skriptu vytvoříme funkci
- parametrizujeme funkci
- rozšíříme funkci o další zamýšlenou funkcionalitu
- implementujme funkci jako součást zásuvného modulu
Tvorba funkce k vytvoření obalové vrstvy¶
Připomeňme si, jak vypadal skript, který vytvářel obalovou zónu kolem
bodů z vrstvy lucas a vypisoval jejich obsah.
from qgis.core import QgsProject
# mapLayersByName() vraci seznam
for feature in QgsProject.instance().mapLayersByName('lucas')[0].getFeatures():
if feature['obs_dist']: # nutno pokud jsou nektere prvky NULL
# druhym parametrem je pocet lomovych bodu pouzitych k vytvoreni kruznice
# (jedna se o body navic ke ctyrem potrebnym pro ctverec)
buffer = feature.geometry().buffer(feature["obs_dist"], 5)
point = feature.geometry().asPoint()
print(f'{feature["point_id"]}: [{point.x()}, {point.y()}]: {buffer.area()} m2')
Tvorba funkce je jednoduchá.
from qgis.core import QgsProject
def lucas_buffer():
# mapLayersByName() vraci seznam
for feature in QgsProject.instance().mapLayersByName('lucas')[0].getFeatures():
if feature['obs_dist']: # nutno pokud jsou nektere prvky NULL
# druhym parametrem je pocet lomovych bodu pouzitych k vytvoreni kruznice
# (jedna se o body navic ke ctyrem potrebnym pro ctverec)
buffer = feature.geometry().buffer(feature["obs_dist"], 5)
point = feature.geometry().asPoint()
print(f'{feature["point_id"]}: [{point.x()}, {point.y()}]: {buffer.area()} m2')
if __name__ == '__console__':
lucas_buffer()
Přestože však byla tvorba funkce jednoduchá, dává nám mnoho možností. Pro opětovné použití funkce na jiných vrstvách je zajisté záhodno ji parametrizovati. Zároveň v případě, že není vstupní vrstva nalezena, vyvoláme vyjímku.
Úkol
Přepišme funkci tak, aby vyvolávala vyjímku i v případě, že je nalezeno více vrstev stejného názvu.
Vytvoření výstupní vektorové vrstvy¶
Vytvořme novou funkci create_new_layer, která na základě
specifikace (typ geometrie a souřadnicový systém, struktura atributové
tabulky) vytvoří novou vektorovou vrstvu. Takto vytvořenou vrstvu na
konci skriptu přidejme do mapové okna.
Dále upravme funkci lucas_buffer tak, aby vytvářela nové
prvky obalové zóny a zapisovala je včetně relevatních atributů do nové
vektorové vrstvy vytvořené voláním funkce create_new_layer.
Úkol
Přepišme funkci tak, aby souřadnicový systém výstupní vrstvy byl odvozen z vektorové vrstvy vstupní.
Tvorba zásuvného modulu¶
Nejprve nainstalujme dva nové zásuvné moduly:
- Plugin Builder - použijeme pro vytvoření šablony pluginu
- Plugin Reloader - tento plugin umožní znovunačíst již zavedený zásuvný modul. To nám zásadně usnadní vývoj a testování našeho zásuvného modulu v prostředí QGISu.
Vytvoření šablony zásuvného modulu¶
Spustíme Plugins > Plugin Builder a pomocí jednoduchého průvodce
vytvořme šablonu našeho zásuvného modulu.
V prvním kroku dejinujme:
Class name- název Python třídy implementující zásuvný modul (bez diakritiky, mezer a pod)Plugin name- název zásuvného modulu, tak jak se bude zobrazovat v menuDescription- krátký popis modulu, tak jak se bude zobrazovat v dialoguPluginsModule name- název Python modulu a zároveň adresáře se zásuvným modulem (bez diakritiky, mezer a pod)Version number- verze zásuvného moduluMinimum QGIS version- minimální verze QGIS nutná pro fungování zásuvného moduluAuthor/Company- autor zásuvného moduluEmail address- kontakt na autora
Poznámka
Položky Description, Version number, Minimum QGIS version, Author/Company a Email adress lze jednoduše změnit po vytvoření zásuvného modulu v souboru metadata.txt.
V dalším kroku popišme funcionalitu zásuvného modulu. Tato informace
se bude zobrazovat v dialogu Plugins. Popis lze změnit po
vytvoření zásuvného modulu v souboru metadata.txt.
V následujícím kroku definujme způsob začlenění zásuvného modulu do prostředí QGISu. Máme tři možnosti:
Tool button with dialog- dialog s tlačítkemTool button with dock widget- připnutelné okno s tlačítkemProcessing provider- integrace do nástrojů zpracování
V našem případě zvolme připnutelné okno s tlačítkem.
Dále definujme podpůrné komponenty zásuvného modulu. Typicky je pro nás důležitá:
Internatializationv případě, že plánuje zásuvný modul lokalizovat do různých jazykůpb_toolusnadní sestavení zásuvného modulu do formy zip archivu a jeho publikaci v repozitáři zásuvných modulů QGIS
Mezi povinné informace patří i odkaz na repozitář se zdrojovým kódem
zásuvného modulu, na systém pro hlášení chyb, domovskou stránku a
klíčová slova. Všechny tyto položky lze jednoduše změnit po vytvoření
zásuvného modulu v souboru metadata.txt.
Na poslední stránce průvodce zvolíme adresář, do kterého se nově vytvořený plugin vytvoří.
Načtení zásuvného modulu v QGIS¶
Ve výchozím nastavení QGIS při startu vyhledává zásuvné moduly v profilu uživatele. V nastavení ale můžeme přidat i další adresáře, ve kterých bude zásuvné moduly vyhledávat. To se nám bude pří dalším vývoji a testování zásuvného modulu hodit.
V dialogu Settings > Options, záložce System sekci
Enviroment definujme proměnou prostředí QGIS_PLUGINPATH. Tato
proměnná bude odkazovat na adresář, ve kterém je umístěn podadresář se
zásuvným modulem.
Todo
Přidat screenshot s načteným pluginem
Tip
Zobrazí-li se vám chybová hláška The resource compiler pyrcc5 was not found in your path, nejspíše nemáte nainstalovaný balíček pyqt5-dev-tools. Na Linuxu využívajícím balíčkovací systém apt jej nainstalujete pomocí příkazu sudo apt install pyqt5-dev-tools.
Definice uživatelského rozhraní¶
Výchozí uživatelské rozhraní bude velice minimalistické. Bylo by vhodné jej doplnit o potřebné vstupní parametry:
- vstupní vektorová vrstva
- výstupní vektorová vrstva
- tlačítko, které zásuvný modul spustí
Lze tak učiniti dvěma různými způsoby. Za využití programovacího jazyka Python (PyQt), nebo za pomoci nástroje Qt Designer. Přidejme jednotlivé prvky v programu Qt Designer. Tím si ukážeme jeho výhody (jednoduché a intuitivní ovládání), ale i nevýhody (jest vhodný pro rychlý návrh, ale nejsme v něm schopni vytvořit složitější signály a zdířky). Jeden, nikoli však jediný, z možných návrhů může nakonec vypadati následujícím způsobem.
Funkcionalita zásuvného modulu¶
Ačkoli jsme si vytvořili oku lahodící grafické uživatelské rozhraní, rádi bychom mu dodali potřebnou funkcionalitu. Upravme soubor fgis_plugin/fgis_plugin.py tak, aby se po stisknutí tlačítka Run spustila funkce lucas_buffer. Po vygenerování vypadá soubor následujícím způsobem.
Přidejme tlačítku run_button odpovídající signál. Abychom mohli importovat funkci lucas_buffer a nemuseli ji psáti znovu, uložme si náš dosavadní skript pod názvem lucas_tools do adresáře se zásuvným modulem. Po našich úpravách by měl soubor fgis_plugin/fgis_plugin.py vypadati podobně jako v následujícím příkladu.
Úkol
Upravte funkce v souboru lucas_tools tak, aby nebylo v fgis_plugin_dockwidget.py zapotřebí duplikovat kód pro definici nové vrstvy.
Úprava zásuvného modulu¶
Zásuvný modul rozšiřme o novou funkcionalitu - stažení fotografií pro vybrané LUCAS body.
Fotografie dostupné pro zvolené LUCAS body můžeme jednoduše stáhnout pomocí Python balíčku st-lucas. Tento balíček doinstalujeme:
Nejprve vyzkoušejme stažení fotografií pro daný bod LUCAS a rok měření:
from zipfile import ZipFile
from st_lucas import LucasIO
point_id = 46682050
target_dir = "/home/martin/Downloads"
lucasio = LucasIO()
lucasio.data = "/home/martin/Downloads/lukas_sample.gpkg"
images = lucasio.get_images(2018, point_id)
filename = lucasio.download_images(images, target_dir)
with ZipFile(filename) as zip:
zip.extractall(target_dir)
Na základě toho rozšířme zdrojový kód o novou funkci
unzip_lucas_photos(). Dále modifikujme funkci
lucas_buffer_photo() tab, aby fotografie byly staženy a rozbaleny
do cílového adresáře v následující struktuře (pointid_year):
Do atributové tabulky výstupní vrstvy přidejme nový atribut photo
odkazující na soubor P.jpg.
Úkol
Upravme funkci tak, aby nestahovala zip archiv s fotografiemi opakovaně.
Tip
Fotografie může být zobrazena přímo v atributové tabulce.
Ve vlastnostech vrstvy (Attributes Form) nastavíme: Widget Type na Attachment a Integrated Document Viewer Type na Image.
Po otevření atributové tabulky se přepneme do režimu formuláře.
Úkol
Upravte zásuvný modul tak, aby byl attribut photo nastaven automaticky na Attachment a Image.
Úkol
Vyzkoušejte vytvořit další zásuvný modul. Můžete čerpat z materiálů školení skupiny GISMentors.
Publikace zásuvného modulu¶
Vytvořený zásuvný modul můžeme s kolegy sdílet ve formě zip
archivu. Ten lze jednoduše nainstalovat z Plugins > Manage and
Install Plugins... > Install from ZIP.
Zip archiv se zásuvným modulem lze vytvořit pomocí nástroje
pb_tool. Nejprve jej doinstalujeme:
Nástroj poskytuje celou řadu voleb (podrobné informace můžete vypsat
pomocí pb_tool --help). Nám postačí pb_tool zip pro vytvoření
zip archivu.
V našem případě jsme do struktury zásuvného modulu přidali soubor
lucas_tools.py. Ten musíme začlenit do konfigurace pb_tool.cfg:
Poznámka
Pokud nemáme sepsánu dokumentaci (adresář help), tak můžeme její sestavení vypnout. Zakomentujeme řádek:
Poznámka
V případě, že jste měnili ikonku zásuvného modulu (icon.png) je nutné spustit
Poté můžeme vytvořit zip archiv.
Soubor se vytvoří v adresáři zip_build.
Úkol
Vyzkoušejte instalaci zásuvného modulu z vytvořeného zip archivu.
QGIS plugins web portal
V případě, že jsme se zásuvným modulem spokojeni a chceme jej sdílet s
ostatními uživateli QGIS, tak je tu možnost jej publikovat na webovém
portálu QGIS. Zásuvný modul bude ve výsledku snadno
instalovatelný z Plugins > Manage and Install Plugins....
Postup: Nejprve si vytvoříme na webovém portálu učet https://plugins.qgis.org/accounts/login/ a poté zásuvný modul nahrajeme ve formě zip archivu. Zásuvný modul projde hodnocením. V případě, že splní všechny podmínky (licence GNU GPL, dokumentace, ...) bude schálen a tím se stane snadno dostupný pro další uživatele QGISu.










