Den som följer mig på Twitter (@klaskarlsson) noterade att jag testade att skapa etiketter i diagram i kartan med QGIS i helgen. I detta inlägg tänkte jag beskriva detta i lite mera detalj.
Som vanligt när det gäller QGIS så kan en del saker som är enkla i andra GIS vara lite omständligt, men när man väl hittat en lösning, så är variationsmöjligheterna nära på oändliga.
Det ursprungliga problemet var att man ville ha värden för staplarna i ett stapeldiagram i kartan.
Men ingenstans i inställningarna finns det en möjlighet att lägga till etiketter.
Det går att skapa etiketter för lagret och placera dessa traditionellt, men med en anpassad etikett som kombinerar alla kolumnvärden så kan man skapa en anpassad placering med ”offset” så att etiketten placeras under stapeldiagrammet.
Stapeldiagrammet är ”låst” mitt på den punkt som lagrar värdena som staplarna representerar. Och genom att jag vet hur stort diagrammet får vara baserat på värdena i attributen, så kan jag skapa ett offset med ett uttryck som kan flytta etiketten så att den exakt passar in i diagrammens nederkant.
I mitt exempel så har jag satt diagrammen som maximalt 100 mm höga och maximalt värde som en stapel kan ha är också 100, vilket gör att uttrycket blir lite enklare. Om man har mer komplicerade värden för diagramstorleken så får man räkna lite på vilka värden som krävs i uttrycket.
-- Generate an array with offset in x and y (upper left) array( 0 , -- using array to find largest value -- This is the diagram size array_last(array_sort(array("A","B","C"))) / 2 + 4 -- Half the size plus half the font size )
När man skapar offset såhär så är det viktigt att tänka på att det är offset i ”skärmkoordinater”. ”Skärmnoll” är uppe till vänster, så för att flytta etiketten nedåt så skall man ha ett positivt offset i y. För att flytta uppåt så är det ett negativt värde.
Om man är nöjd med detta så blir det inte krångligare. Men om man i stället vill ha etiketterna separerade över respektive stapel, då blir det lite krångligare.
Jag lägger till ett nytt lager för varje stapel med samma källdata som för diagrammet. Dessa punkter skall inte ha någon symbol utan bara en etikett. I mitt diagram så hämtas värden direkt från attribut i kolumnerna ”A”, ”B” och ”C”, så jag döper mina lager till ”A”, ”B” och ”C”.
Till skillnad från tidigare så behöver uttrycket nu även ta hänsyn till kolumnvärdet, så att etiketten placeras på rätt plats över stapeln. Flytta en stapelbredd till vänster och med utgångspunkt i ”centrum” av diagrammet, gå halva höjden nedåt (i botten på diagrammet) och därefter uppåt med värdet för kolumnen (i toppen på stapeln) och slutligen kompensera för etiketthöjden.
Om du inte vill kompensera för typsnittshöjd så kan du i stället placera etiketten ”över” punkten. Då struntar du helt enkelt i ”- 4” i uttrycket.
array( -10, -- Col "A" is 10 mm wide, move 10 mm to the left -- Find largest diagram value (diagram size) array_last( array_sort( array("A","B","C"))) / 2 - "A" - 4 -- Half the size, then back "A" and compensate for font height )
Nu är det bara att upprepa för de övriga kolumnerna där kolumn ”B” inte flyttas i x-led ( 0 ) och ”C” flyttas till höger ( 10 ). Annars är det bara att byta ”A” mot ”B” eller ”C” i slutet av uttrycket.
Sedan går det att justera uttrycken så att det passar. Man kanske vill placera etiketten i överkant av stapeln, men innanför. Kanske mitt på stapeln, eller något helt annat.
Pajdiagram
Det går att göra motsvarande även för pajdiagram.
Det går att anpassa diagrammen ganska mycket, exempelvis kan man justera storleken på diagrammet baserat på totalsumman av värden. I det här fallet är max 174, vilket skapar ett diagram med 50 mm diameter. Dessa värden behövs i senare uttryck.
Något annat som är bra att känna till är att diagrammet börjar rakt upp, och går moturs. Detta är också väldigt viktigt när vi börjar skriva uttryck för etiketterna.
För att skapa etikettpunkter här så måste jag använda central etikettplacering. Sedan räknas punkten ut från centrum med avstånd och riktning. Startpunkten, eftersom det är offset, blir 0,0. Avståndet kompenserar för fontstorleken med ”5” i det här fallet. Sedan beräknas avståndet baserat på max storlek för diagrammen (radien för diametern = 25) och hur stor del av max-summan diagrammet har.
Riktningen beräknas i radianer och för ”A” så är det ganska enkelt. Halva andelen av ”A” som en del av totalsumman blir 180 * ”A” / ( ”A” + ”B” + ”C” ) här är 180 = 360/2. Eftersom project() flyttar punkterna i ”positiv” riktning vilket passar geografiska koordinater, så behöver jag även här kompensera för att jag använder skärmkoordinater. Därför läggs 180 grader till i början på raden. Ett alternativ är att låta diagrammet börja nedåt, men för mig känns det lite mindre intuitivt.
Sedan skapas en lista (array) med offset koordinater för x och y.
För övriga etiketter så behöver man tänka till lite. Det som skiljer är vinkeln. Man kan justera uttrycket så att man får halva vinkeln för ”B”, men man måste även lägga till hela vinkeln för ”A”. På motsvarande sätt beräknar man halva vinkeln för ”C” och lägger till den sammanlagda vinkeln för ”A” och ”B”.
Detta tillsammans placerar etiketter i pajdiagrammen som representerar värdet för varje bit. Även här kan man sedan justera beräkningarna om man vill placera etiketterna någon annanstans.
Avslutning
Om man nöjer sig med en samlad etikett för diagrammet, så är det inte speciellt krångligt, men ”tydligheten” blir lite lidande i en del fall.
Om man vill ha helt anpassade etiketter så måste man skapa ”kopior” på lagret för diagrammen där man endast visar etiketter. Ett lager för varje etikett. Det blir lite mer att göra och det är svårt att spara en stil som enkelt går att applicera på olika lager. Framför allt då man måste ta hänsyn till värden, attributnamn, antal kolumner och så vidare.
Att det över huvud taget är möjligt visar på hur kraftfullt QGIS är. Det var länge sedan jag använde diagram i ArcMap, men motsvarande funktion där hade sannolikt varit en enkel kryssruta. Men sedan hade du inte haft några direkta möjligheter att påverka utseendet. Med QGIS är som sagt lösningarna inte alltid direkt självklara, men när man väl ”löst upp knuten” så är möjligheterna ofta oändliga.