Jag jobbar ganska ofta med kartböcker. Det är ett bra format på kartor när man är på resande fot. Innan du påpekar att ”man kan ju ha kartor i mobilen”, så vill jag påstå att, Nej. Man kan inte alltid ha kartor i mobilen! Och så kan vi lämna det där.
För att navigera i en kartbok så kan man använda indexsidor där kartbokens sidor och utbredning är utritad på en karta i mindre skala. För att slippa behöva hoppa fram och tillbaka till en indexsida så är det praktiskt att ha referenser i marginalen av varje kartblad som anger vilket blad som angränsar till det aktuella bladet.
Det går att skapa sådana referenser manuellt i attributtabellen för kartbokens skapande, men det betyder många ganska avancerade uttryck i uttrycksbyggaren.
Därför har jag rivit mitt hår några timmar och skapat ett Pythonverktyg som gör allt det här åt mig.
Skapa bladlayouten
Jag börjar dock med att skapa en layout som kan passa kartbokens blad.
Jag gör bara en enkel layout till att börja med, men du kan skapa en hur avancerad layout du vill. Det jag behöver för detta exempel är ett sidnummer och en referens för varje möjlig angränsande sida till bladet, inklusive diagonaler.
Även om alla blad inte har angränsande blad på alla sidor, så räcker det i princip med fyra sidor i en 2 x 2 layout för att alla skall behövas på något av bladen.
Skapa index
(Mot slutet av inlägget kommer det ett förenklat alternativ till att skapa detta kartboksindex, som dock kräver QGIS 3.8 eller senare)
I senare versioner av QGIS kan man skapa en polygon i kartfönstret som har samma täckning som en karta i en layout. Det kan man använda för att få lite hjälp med att skapa ett ”index” eller ”grid” lager för kartboken. Sök bara bland verktygen efter ”layout”.
Polygonen använder jag för att få fram hur bred och hög kartan i layouten är. Detta kan exempelvis göras med ett enkelt uttryck.
bounds_width($geometry) || '\n' || bounds_height($geometry)
Det går att ta reda på bredd och höjd på andra sätt också, exempelvis direkt i layouten. Men då får du räkna lite själv förstås.
Att skapa ett rutnät finns det också ett verktyg för. Välj polygon som typ och den totala utsträckningen för din kartbok. Som horisontellt och vertikalt värde använder jag det som räknades fram tidigare för täckningspolygonen.
Nästa steg blir att skapa ett attribut för sidnumrering. Det går såklart att använda polygonernas id, men det är inte sannolikt att dessa kommer i den ordning som du vill att de skall vara i. Du kan i princip döpa bladen till vad du vill. Tänk dock på att texten skall få plats i layouten senare.
Skapa angränsande bladhänvisning
Så var det då dags för mitt lilla verktyg. Jag går inte igenom koden här, den är både stökig och suboptimal, men den fungerar. Åtminstone för mig.
Du kan ladda ner filen med koden här: grid_neighbours.py, och du sparar den i din QGIS profil under ”processing/scripts”. När du sedan startar om QGIS så hittar du verktyget under ”scripts/Vector table” i toolboxen.
Kör verktyget och välj ditt grid-lager samt det fält som du skapat för sidnummer. Du kan också välja att spara resultatet som en fil. Fram tills nu har jag bara jobbat med minneslager, så det är först nu som jag sparar en faktisk fil för min kartbok.
Verktyget går igenom varje polygon och kontrollerar om det finns en polygon strax vid sidan om den i åtta olika riktningar (även diagonalt). Om det gör det så skriver den dessa polygoners sidnummer (i mitt fall) i ett nytt attribut som heter exempelvis ”neighbour_topleft”.
Som du ser i bilden ovan så har sida 1 grannar i sida 2, 6 och 5. Dessa värden kan nu användas för att göra färdigt kartboken.
Skapa kartboken
Kartboken definieras i en egen flik i layouten.
Kartan skall sedan också ”aktiveras” för att kunna kontrolleras av kartboken.
Sedan är det bara att ersätta texterna i layouten med hänvisningar till attributen i tabellen. Texten vid pilen som pekar upp till höger ersätts med en hänvisning till fältet ”neighbour_topright”.
Här skulle man kunna stanna. Men jag vill inte att pilar som saknar referenstext skall synas. Därför blir det ett litet uttryck som testar detta för att visa eller dölja pilen.
Det finns ingen motsvarande funktion i layouten till huvudkartans ”Enable layer”, men det går att använda ”Exclude item from exports” i stället. Om man däremot vill se förändringarna i gränssnittet utan att behöva exportera så är det bättre att sätta opaciteten dynamiskt. En enkel if sats kopplat till det attribut som motsvarar pilens position räcker för att det skall gå att sätta 100 eller 0 i opacitet beroende på om det finns ett värde i fältet eller inte.
Som du ser i bilden ovan så verkar allt stämma. Och om det gör det för denna ganska enkla kartboken så borde det göra det även för betydligt mer omfattande kartböcker.
Verktyget är avsett att användas på polygoner som ligger kant i kant, utan större överlapp. Det fungerar inte med linjer eller punkter och inte heller där det finns ett större mellanrum mellan polygonerna. Syftet är ju att direkt angränsande polygoner skall vara enkla att identifiera.
Utveckling
När jag hintade om det här inlägget på Twitter igår så kom det lite frågor som gav mig ytterligare uppslag till förenklingar i byggandet av kartböcker.
Kan man inte skapa ett verktyg som automatiskt bygger ett index baserat på en befintlig layout?
Jamen det är klart man kan! Så det gjorde jag…
Den här gången i modellbyggaren, men principen är den samma.
Hämta verktyget här: AtlasGrid.model3, och placera det i din QGIS profil, eller använd ”öppna modell” i verktygslådan.
Verktyget ber om en utsträckning där bladen skall skapas, samt en layout att basera bladen på. Du måste således ha en färdig layout med korrekt skala färdig. Man annars så är det här väldigt smidigt att använda.
Det går att bygga ihop båda verktygen, men det gör jag inte. Jag vill nämligen manuellt styra sidornas ordning och numrering. Det går att bygga ett verktyg som gör detta generiskt (vänster till höger, uppifrån och ner), men just nu känns inte det som att det behövs.
En annan vidareutveckling är att lägga till möjligheten att välja ett objekt som skall täckas med polygoner, och inte bara en fyrkantig yta. Det får dock bli ett helt annat projekt.