QGIS atlas – mapové listy se zobrazením jednotlivých vrstev

V tomto blogu si ukážeme příklad použití tvorby atlasu, který vychází z reálného dotazu účastníka našeho kurzu QGIS pro pokročilé. Princip použití atlasu spočívá v automatické tvorbě sady mapových výstupů na základě jednotlivých prvků ve vrstvě. Jak se takový atlas dá vytvořit popisujeme v materiálech pro školení (kapitola Tvorba atlasu). To je ale jen zlomek možností, které atlas nabízí. Díky možnosti provázání hodnot s různými parametry, využití vzorců nebo malých Python skriptů, máme při generování vícelistých výstupů téměř neomezené možnosti.

Popis řešené situace

Požadavek účastníka kurzu spočíval v tom, že potřeboval vytvořit sérii mapových výstupů, které by zobrazovaly jedno území s podkladovými daty a každá jednotlivá stránka by navíc zobrazovala jednu zájmovou liniovou vrstvu. Tedy atlas, který nebude iterovat nad prvky v jedné vrstvě, ale and konkrétními vrstvami v projektu. Vrstev pro jednotlivé zobrazení bylo řádově desítky, data měla podobnou strukturu, jen zobrazovala jiný jev.

Nápad na možné řešení

Princip navrhovaného řešení je použití tabulky, kde budou v řádcích vypsány unikátní identifikátory vrstev (layer_id), pro které budeme atlas vytvářet. Tuto tabulku použijeme jako vrstvu pokrytí v atlasu a nastavíme pojmenování stran podle sloupce s identifikátory. Tím zajistíme vytvoření strany atlasu pro každý identifikátor vrstvy.

U těchto vrstev potom nastavíme symbologii podle pravidla, kdy necháme zobrazit prvky ve vrstvě pouze pokud se jejich id shoduje s názvem stránky atlasu. Použitím právě layer_id docílíme toho, že se atlas vygeneruje správně i pokud budou mezi vrstvami některé se shodným jménem. Zároveň necháme zobrazit ostatní podkladové vrstvy, které budou statické – zobrazené na každé straně atlasu.

Navrhované řešení se záměrně vyhýbá editaci nebo slučování vstupních dat. Řešení je poměrně přímočaré, ale provedení může pokulhávat, zejména v případě kdy máme k zobrazení desítky nebo stovky vrstev. Takže si proces musíme trochu zautomatizovat. Jak na to?

Postup

1. Příprava tabulky

V první řadě musíme vytvořit tabulku se sloupcem s unikátními identifikátory vrstev v projektu  (proměnná layer_id). Identifikátor lze zjistit ve vlastnostech vrstvy v záložce proměnné, a můžeme začít kopíro… řekli jsme automatizovat! :). Při tvorbě tabulky si tedy pomůžeme malým Python skriptem, který v základu výtahne layer_id všech vrstev v konkrétní skupině a vytvoří csv tabulku s jedním sloupcem, ve kterém budou získané hodnoty zapsané. Dáme všechny požadované vrstvy do jedné skupiny, zapneme python konzoli (Zásuvné moduly –> Python console) a z vestavěného textového editoru spustíme skript pomocí tlačítka img-mail (je nutné zadat název skupiny group_name a cestu pro uložení tabulky csv_path):

goup_name = "group1"
csv_path = "/cesta/pro/tabulku.csv"

root = QgsProject.instance().layerTreeRoot()

group_layers = []
for i in root.findGroup(group_name).findLayers():
    group_layers.append(i.layerId())

with open(csv_path, "w") as f:
    for item in group_layers:
        f.write("%s\n" % item)

Python konzole v QGIS 3.4

Nyní nahrajeme tabulku pomocí Přidat vrstvu s odděleným textem…, a nebo rozšíříme náš skript a necháme ho nahrát tabulku za nás. Na konec skriptu stačí přidat:

uri = (
    'file://{}?type=csv&delimiter=%20&useHeader=No&detectTypes=yes'
    '&geomType=none&subsetIndex=no&watchFile=no'
).format(csv_path)

layer = iface.addVectorLayer(
    uri, group_name + "_list", "delimitedtext"
)

Náhled na vytvořenou tabulku a seznam vrstev

2. Nastavení atlasu

V první řadě vložíme do mapového výstupu mapové okno, které nastavíme podle potřeb. Potom přejdeme k nastavení atlasu. Jako vrstvu pokrytí nastavíme naší tabulku a pro generování názvů stran zvolíme sloupec (máme pouze jeden – field_1). Nyní když spustíme náhled atlasu, vidíme, že se nám vygenerovala stránka pro každé layer_id. Teď zbývá pouze zařídit, aby se na stránkách zobrazovali jen ty vrstvy, které chceme. Tedy vrstva, která má hodnotu layer_id shodnou s názvem strany atlasu. Toho docílíme nastavením pravidla v symbologii vrstev. V takovém případě budeme ignorovat standardní ovládání atlasu pro mapovým oknem, které bude neaktivní.

Nastavení atlasu s použitím tabulky

3. Nastavení viditelnosti vrstev pro stranu atlasu

Otevřeme vlastnosti jedné z vrstev ve skupině a zvolíme symbologii podle pravidla. Otevřeme jedinou položku, nastylujeme podle potřeb a nastavíme filtr:

@layer_id = @atlas_pagename

Díky tomuto pravidlu se symbologie použije pouze, pokud výsledek filtru bude pravdivý, v našem případě – id vrstvy se shoduje s názvem strany v atlasu.

Posledním krokem je nastylování všech ostatních vrstev stejným způsobem. Toho docílíme jednoduše tak, že zkopírujeme styl vrstvy, ve které jsme nastavili symbologii, a tento styl použijeme pro všechny vrstvy ve skupině (pravým tlačítkem klikneme na položku skupiny a vybereme vložit styl). Nevýhodou by mohlo být, že všechny vrstvy budou mít ve výstupech stejný styl. Pokud by to byl problém, dá se to ošetřit například generováním náhodných barev u symbolů, kdy jako hodnotu barvy vložíme vzorec, kdy položky RGB budou náhodná čísla ve zvoleném rozmezí.

Nastavení symbologie podle pravidla

Nicméně celý krok 3 si můžeme usnadnit “vytuněním” našeho skriptu. Do smyčky, která iteruje nad vrstvami, přidáme nastavení symbologie podle pravidla s našim filtrem (inspirováno příspěvkem na gis.stackexchange.com):

group_layers = []
for i in root.findGroup(group_name).findLayers():
    group_layers.append(i.layerId())

    layer = i.layer()
    symbol = QgsSymbol.defaultSymbol(layer.geometryType())
    renderer = QgsRuleBasedRenderer(symbol)
    root_rule = renderer.rootRule()
    rule = root_rule.children()[0]
    rule.setLabel("Atlas")
    rule.setFilterExpression('@layer_id = @atlas_pagename')
    layer.setRenderer(renderer)

4. Vzhled výstupu a export atlasu

Nyní nezbývá nic než doplnit mapový výstup o další potřebné prvky. Prvky lze také nastavit tak, aby se generovaly na základě proměnných hodnot (např. texty). V případě použití proměnných vrstvy na straně atlasu však budeme muset tuto vrstvu specifikovat (nepoužíváme ovládání atlasem). To zajistíme funkcí layer_property(@atlas_pagename), pro název vrstvy např.:

[% layer_property(@atlas_pagename,'name') %] 

Náhled atlasu

Jakmile jsme se vzhledem výstupu spokojení, můžeme atlas exportovat do jednoho pdf dokumentu nebo do samostatných výstupů.

Celý skript

– vytvoří (a nahraje do projektu) csv tabulku se seznamem id vrstev (layer_id) v konkrétní skupině

– u vrstev ve skupině nastaví styl podle pravidla tak, aby se pro každou stranu atlasu zobrazila pouze jedna vrstva

(Aktuální verzi skriptu lze nalázet na GitHub)

group_name = "nazev_skupiny"
csv_path = "cesta/pro/vytvoreni/tabulky.csv"

root = QgsProject.instance().layerTreeRoot()

group_layers = []
for i in root.findGroup(group_name).findLayers():
    group_layers.append(i.layerId())

    layer = i.layer()
    symbol = QgsSymbol.defaultSymbol(layer.geometryType())
    renderer = QgsRuleBasedRenderer(symbol)
    root_rule = renderer.rootRule()
    rule = root_rule.children()[0]
    rule.setLabel("Atlas")
    rule.setFilterExpression('@layer_id = @atlas_pagename')
    layer.setRenderer(renderer)

with open(csv_path, "w") as f:
    for item in group_layers:
        f.write("%s\n" % item)

uri = (
    'file://{}?type=csv&delimiter=%20&useHeader=No&detectTypes=yes'
    '&geomType=none&subsetIndex=no&watchFile=no'
).format(csv_path)

layer = iface.addVectorLayer(
    uri, group_name + "_list", "delimitedtext"
)

Post navigation