I Qlik Sense SaaS har precis möjligheten kommit att visa bilder i ett kartobjekt och detta är något som också kan användas för att skapa en enkel scatter plot med bilder. Genom att använda sig av olika lager kan grafen byggas upp. I detta inlägg går vi igenom hur man kan göra. Observera att i skrivande stund fungerar detta inte i on-prem-installationer.
Exempeldata
I denna guide ska vi använda oss av ett enkelt data set. Vi har 10 länder med två mätvärden, X och Y, som vi vill visa i en scatter plot. Hämta ner Excel-fil med data här.
Bilderna på flaggor som vi ska använda hämtar vi från GitHub där det finns en samling. Genom att byta ut landskoden i url:n kan vi styra vilken bild vi visar. Adressen till varje bild ser ut så här (det är ”SE” på slutet som ska bytas till respektive landskod):
För att det ska fungera att länka till externa bilder behöver vi lägga till domänen i godkända källor för media. Detta görs genom att lägga till domän i Content Security Policy inne Qlik Management Console (QMC). Detta steg kan bara utföras av någon som är administratör i miljön.
Gå till QMC och välj Content Security Policy. Klicka på Add-knappen och fyll i ett namn, domän och välj imc-src (bildkälla) i Directive. Klicka på spara-knappen.
Skapa en ny app
Börja med att skapa en ny app och läs in Excel-filen ovan på valfritt sätt. Den kan exempelvis läsas in genom att man drar och släpper filen på Qlik Sense-fönstret.
Kartobjekt
Qlik har en standardgraf för scatter plots där man kan skapa upp en sådan graf på några sekunder. Dock vill i detta fall använda ländernas flaggor som punkter i grafen och detta stödjs inte i standardobjektet. Istället ska vi använda ett kartobjekt och själv placera ut kartor, axlar, stödlinjer och annat.
Ett kartobjekt visar normalt en geografisk karta över världen eller en region. Qlik tolkar själv data som stadsnamn och länder för att placera ut lager med punkter, områden, linjer och liknande. Man kan också välja att använda sig av koordinater med latitud och longitud. Genom att använda ett kartobjekt där vi väljer att inte visa någon bakgrundskarta får vi en canvas att rita upp en graf på.
Dra ut ett kartobjekt på ett nytt ark. Gör följande inställningar:
- Appearance, Legend, Show legend: Slå av
- Appearance, Presentation, Scale bar: Slå av
- Map Settings, Base Map: None (den helt vita)
- Map Settings, Projection: User defined (meters)
Lager Y-axel
Vi börjar med ett lager för att visa ett rakt streck uppåt för Y-axeln. Generellt kommer vi att arbeta med koordinater utifrån ett origo i nedre vänstra hörnet. Koordinater anger vi som (3,5) där första värdet är X-värdet och det andra värdet är Y-värdet (X,Y). Y-värdet kommer i kartobjektet motsvara Latitude och X-värdet motsvarar Longitude.
Vår Y-axel ska börja i (0,0), men hur lång ska den vara? Vi vill att båda våra axlar blir lika långa och därför vill vi att den går till det högsta möjliga värdet av X och Y för alla länder.
Om det högsta värdet är till exempel 39 vill vi dock att grafen ska gå till 40. Därför gör vi en liten uträkning som avrundar axelns längd till närmsta över 10-tal. Om man har mycket höga värden blir dock 10-tal inte så bra. Då får man anpassa skalan alternativet använda antalet siffror i talet för att välja en lämplig avrundning. Vi kan titta på det mer i ett kommande inlägg.
Formeln för att räkna ut axelns höjd blir: ceil(rangemax(max(X),max(Y)),10)
Max() kommer att titta efter det högsta värdet av X respektive Y som finns i data för det aktuella urvalet. Rangemax() kommer att ta det högsta värdet av max(X) och max(Y). Ceil-funktionen avrundar upp talet till närmsta 10-tal.
Lägg till ett linjelager på kartobjektet och sätt följande inställningar:
- Layers, Add layer
- Select a layer type: Line layer
- Data, Dimensions, Add: =1 (tryck sedan enter)
- Data, Dimensions, Label: Y-axel (detta visas som namn på lagret i inställningarna)
- Location, Start point: Latitude and longitude fields
- Location, Start point, Latitude: 0
- Location, Start point, Longitude: 0
- Location, End point: Latitude and longitude fields
- Location, End point, Latitude: ceil(rangemax(max(X),max(Y)),10)
- Location, End point, Longitude: 0
- Width & Style: Sätt två steg från minsta
- Colors: Byt till mörkgrå
Om alla inställningar gjorts korrekt borde du nu se en vertikal linje mitt i objektet.
X-axel
Upprepa nu föregående steg med att skapa ett nytt linjelager och gör samma inställningar. Den enda skillnaden blir att koordinaterna denna gång ska motsvara en liggande linje.
- Start Longitude: 0
- Start Latitiude: 0
- End Longitude: ceil(rangemax(max(X),max(Y)),10)
- End Latitude: 0
Nu ska det finnas två axlar i objektet.
Flaggor
I detta lager ska vi placera ut kartorna med hjälp av deras X och Y-värden. Vi gör detta genom att skapa ett punktlager och byta symbolerna till bilder. För varje bild skapar vi en url som hämtar flaggan från GitHub.
Om värdena skiljer sig mycket i storleksordning mellan X och Y skulle alla flaggor hamna till exempel längst ner på en axel. Så för att motverka detta får vi skjuta ut flaggorna relativt värdena på X och Y. Om till exempel X-värden är mycket högre än Y-värden, flyttar vi flaggornas latitud X/Y. För att få fram det totala värdet på X/Y använder vi total i uttrycken. Annars skulle vi endast få värdet för respektive land då dimensionen automatiskt filtrerar data. Formeln blir till exempel för Y-axeln: Y*if(max(total X)>max(total Y),ceil(max(total X)/10)/ceil(max(total Y)/10),1)
Skapa ett nytt punktlager enligt nedan:
- Layers, Add layer
- Layers, Select a layer type: Point layer
- Data, Dimensions, Field: ID
- Data, Dimensions, Label: Flags
- Location, Latitude and longitude fields: Vald
- Location, Latitude: Y*if(max(total X)>max(total Y),ceil(max(total X)/10)/ceil(max(total Y)/10),1)
- Location, Longitude: X*if(max(total Y)>max(total X),ceil(max(total Y)/10)/ceil(max(total X)/10),1)
- Size & Shape, Shape: Image from URL
- Size & Shape, Image: =’https://raw.githubusercontent.com/cristiroma/countries/master/data/flags/PNG-32/’ & Country & ’-32.png’
- Size & Shape, Bubble size: Öka till lämpligt värde
Text på axlar
På axlarna vill vi nu visa värden vid 100% och 50% av respektive axels längd. Detta kommer vi att göra med ett punktlager där döljer själva punkten genom att göra den genomskinlig.
Vi börjar med det högsta värdet på X-axeln. Lägg till ett punktlager med följande inställningar:
- Layers, Add layer
- Layers, Select a layer type: Point layer
- Data, Dimensions, Field: =1
- Data, Dimensions, Label: Text 100% X-axel
- Location, Latitude and longitude fields: Vald
- Location, Latitude: 0
- Location, Longitude: ceil(rangemax(max(X),max(Y)),10)
- Bubble size: Minsta
- Colors, Color, Opacity: Längst till vänster
- Colors, Outline color, Opacity: Längst till vänster
- Options, General, Show label: Aktiverat
- Labels: ceil(max(X),10)
Nu ska ett värde dykt upp längst till höger på X-axlen:
Repetera stegen för en punkt mitt på X-axeln. För positionerna mitt på axlarna delar vi med 2, ceil(rangemax(max(X),max(Y)),10)/2.
Y-axeln liknar inställningarna på X-axeln, men vi behöver flytta texten från att vara under punkten till över punkten (det finns ingen inställning för till vänster om punkten). Vi behöver också justera positionen för punkten så att texten hamnar till vänster om axeln. Hur mycket det ska justeras med beror på skalan av grafen. För vårt exempel fungerar inställningen nedan, men detta kan behöva justeras beroende på dina värden. I ett kommande inlägg kan vi gå djupare in på hur vi kan räkna ut detta dynamiskt.
Lägg till text på Y-axeln med följande inställningar:
- Layers, Add layer
- Select a layer type: Point layer
- Data, Dimensions, Field: =1
- Data, Dimensions, Label: Text 100% Y-axel
- Location, Latitude and longitude fields: Vald
- Location, Latitude: ceil(rangemax(max(X),max(Y)),10)
- Location, Longitude: -ceil(rangemax(max(X),max(Y)),10)/30
- Bubble size: Minsta
- Colors, Color, Opacity: Längst till vänster
- Colors, Outline color, Opacity: Längst till vänster
- Options, General, Show label: Aktiverat
- Labels: ceil(max(Y),10)
Stödlinjer
Nu ska vi lägga till lite stödlinjer som hjälper oss att läsa av grafen. I det här exemplet lägger vi till tre tunna linjer på X- respektive Y-axeln. Istället för att göra det i 2*4 lager skapar vi ett lager med fyra dimensionsvärde som ger oss tre linjer. De fyra dimensionsvärdena skapas av funktionen valuelist(1,4) och får då värdena 1, 2, 3 och 4. Genom att multiplicera dimensionsvärdet med en fjärdedel av axelns längd kan vi hoppa mellan startpunkterna:
valueloop(1,4)*ceil(max(X),10)/4
Skapa ett nytt linjelager med följande inställningar:
- Layers, Add layer
- Select a layer type: Line layer
- Data, Dimensions, Field: =valueloop(1,4)
- Data, Dimensions, Label: Vertical Sublines
- Location, Start point: Latitude and longitude fields
- Location, Start point, Latitude: 0
- Location, Start point, Longitude: valueloop(1,4)*ceil(rangemax(max(Y),max(X)),10)/4
- Location, End point: Latitude and longitude fields
- Location, End point, Latitude: ceil(rangemax(max(X),max(Y))/10)*10
- Location, End point, Longitude: valueloop(1,4)*ceil(rangemax(max(Y),max(X)),10)/4
- Width & Style: Minsta
- Colors: Byt till ljusgrå
Gör sedan motsvarande horisontella linjer genom att skapa ett nytt lager med motsvarande inställningar. Start och slutpunkter ska istället sättas till:
- Location, Start point, Latitude: valueloop(1,4)*ceil(rangemax(max(Y),max(X)),10)/4
- Location, Start point, Longitude: ceil(rangemax(max(X),max(Y))/10)*10
- Location, End point, Latitude: valueloop(1,4)*ceil(rangemax(max(Y),max(X)),10)/4
- Location, End point, Longitude: 0
Se till att ordna lagren så att Y- och X-axel ligger ovanför stödlinjerna – då blir det snyggast i hur de överlappar varandra. Flaggornas lager ska också ligga lägnst upp.
Tooltip
Till sist ska vi även visa lite information när man håller musen över en flagga. Gå till lagret för flaggor och välj att lägga till en Custom Tooltip. Nu lägger vi enkelt ihop våra X och Y-värden med koden:
=’Y: ’ & Y & chr(13) & ’X: ’ & X
Klart (men…)
Nu har vi byggt en enkel scatter plot med bilder och förhoppningsvis har du förstått grunderna i att skapa egna grafer med kartobjketet. Vårt objekt kan förbättras på många sätt och här är några tankar:
- max(X) & max(Y) behöver ändras så att man kan hantera uttryck
- Y/X-axlarnas skala behöver hanteras dynamiskt så att ett större tal avrundas till en högre siffra n 10
- Texten på Y-axeln behöver flyttas mer till vänster om talet är stort
- Hantera %-tal
Om du vill kan du ladda ner en version av objektet här tillsammans med de tre första förbättringarna som nämns ovan. För att hantera objektet dynamiskt använder vi oss av tre variabler som du behöver konfigurera:
- vExpX: Uttryck för X-axeln, t.ex. sum(X)
- vExpY: Uttryck för Y-axeln, t.ex. sum(Y)
- vDim: Dimensionen för grafen, t.ex. Country för länder
En del uttryck blir riktigt spännande när allt ska hanteras:
=-ceil(rangemax(max(aggr($(vExpX),$(vDim))),max(aggr($(vExpY),$(vDim)))),pow(10,len(round(rangemax(max(aggr($(vExpX),$(vDim))),max(aggr($(vExpY),$(vDim))))))-2))/
(-5*(len(round(rangemax($(=max(aggr($(vExpX),$(vDim)))),$(=max(aggr($(vExpY),$(vDim)))))))-1)+50)