In een ander artikel deelde ik hoe ik begon met het inlezen van mijn Garmin hardloop data.

Het doel: zelf leren werken met de data zodat ik mijn eigen visualisaties kan maken.

Mijn volgende stop op deze reis is het gebruiken van kaarten als de achtergrond van mijn routes. Het is iets wat hardloop apps als Garmin Connect of Strava automatisch voor je doen.

Maar ik wil het zelf leren. En wel om twee redenen:

  1. ik leer zo hoe ik kaarten kan gebruiken in datavisualisaties
  2. ik heb zo meer controle over hoe mijn kaart eruit komt te zien

Spoiler: het is me gelukt:

Als je dit vergelijkt met de kaart hieronder (het eindresultaat van mijn vorige blog), ziet het er toch wel wat toffer uit, al zeg ik het zelf.

In dit artikel leg ik je uit wat erbij komt kijken om van een visualisatie zonder kaart tot een visualisatie mét kaart te komen.


Waarom een kaart?

Als we aan routes denken, denken we aan kaarten. Een kaart toevoegen aan mijn visualisatie van hardloopdata zal daarom bijdragen aan de herkenbaarheid van de data.

Het beeld zal er daarnaast wat interessanter uit komen te zien doordat de achtergrond niet meer bestaat uit een egaal kleurvlak, maar uit een kaart met informatie van de omgeving.

Daarnaast ben ik benieuwd of ik zo’n kaart geautomatiseerd zou kunnen genereren. Dan zou ik met een druk op de knop een kaart kunnen maken van een leuke hardloopherinnering.

Genoeg redenen om het eens te proberen.

Waar haal je een kaart vandaan?

Een kaart kan allerlei vormen van informatie bevatten: over gemeentes, natuur, cultuur, … te veel info om zelf bij elkaar te sprokkelen. Daarom ga ik niet zelf een kaart tekenen, maar een kaart opvragen via een API.

Met een API kan ik via code gebruik maken van een dienst.


Voorbeeld API

Met de Twitter API (of tegenwoordig de X API, wat echt heel vaag klinkt) kan je tweets inlezen zonder in te hoeven loggen in Twitter. Zo kan je bijvoorbeeld code schrijven welke automatisch tweets inleest en verwerkt, zonder dat je zelf iets hoeft te doen.


Voor mijn visualisatie ga ik gebruikmaken van een API van Mapbox.

Ik heb ooit van Mapbox gehoord op een evenement en er is een belangrijke reden waarom ik Mapbox wil gebruiken voor mijn kaarten: ze bieden de optie om je eigen stijl op een kaart toe te passen. Zo kan ik de kaart mooi laten aansluiten bij het beeld dat ik voor ogen heb.

Daarnaast laten ze me tot 50.000 kaarten genereren per maand, zonder dat ik moet gaan betalen. Dus ik kan voorlopig vooruit met deze tool!

Mijn eerste kaart

Er zijn twee tools van Mapbox die ik me helpen bij het samenstellen van mijn kaart.

De eerste is Mapbox Studio, een tool waarmee ik een eigen stijl kan samenstellen:

Hierbij kan ik aangeven welke kleuren ik wil gebruiken en welke gegevenslabels (bijv. de naam van steden) ik wel of niet wil tonen.

Vervolgens wil ik een kaart maken en deze als achtergrond voor mijn hardloopdata gebruiken. Ook hier helpt Mapbox mij op weg met een tool.

De Static Images API playground richt zich niet op de stijl, maar op de kaart zelf: welke omgeving wil ik terugzien en welke afmeting wil ik dat mijn kaart heeft? Met deze tool kan ik uitproberen hoe mijn kaart eruit komt te zien:

Deze tool vangt mijn gewenste instellingen af in een URL. Met die URL kan ik de afbeelding ophalen via code en gebruiken in mijn project. Ik kies de kaart die ongeveer mijn routes zou moeten omvatten, kopieer de link en plak deze in mijn project.

En zo kom ik tot mijn eerste visualisatie van hardloopdata met een kaart op de achtergrond:

Functioneel heb ik mijn doel bereikt: ik kan mijn hardloopdata tonen op een kaart.

Hierna hoef ik ‘alleen nog maar’ het een en ander te tweaken. Al is die laatste 20% van het resultaat dat ik zoek veelal 80% van het werk.

De stijl aanpassen

Een ding zit me gelijk dwars: groene lijnen op een grotendeels groene kaart vallen niet op. Omdat ik gebruik maak van de API, kan ik de stijl makkelijk aanpassen met een regeltje tekst.

Zo pas ik eenvoudig een monotone kleurstelling toe:

En om de route nog iets meer te laten opvallen pas ik de kleur van de routes aan naar een rood-roze kleur:

Dat ziet er al een stuk beter uit. Maar als je goed kijkt, valt er iets op: de kaart klopt niet helemaal.

Ik heb de kaart op gevoel samengesteld, omdat ik redelijk in kan schatten tot waar ik meestal loop. Zo kon ik snel testen of het me überhaupt zou lukken om de kaart als achtergrond te gebruiken. Maar helemaal links loopt mijn route uit beeld. En dat kan natuurlijk niet.

De volgende stap is om de kaart automatisch in te lezen op basis van… de data! Zo weet ik zeker dat de kaart altijd de gehele route omvat.

Kaarten inlezen op basis van data

Als ik de kaart inlees via de Mapbox API, moet ik aangeven wat de bbox (de bounding box) is. Dit is de rechthoek waarvan ik de kaart wil ontvangen.

Op basis van mijn hardlooproutes kan ik ophalen wat de bbox van mijn data is. Deze bestaat uit vier data punten:

  • Het westelijkste punt van al mijn routes.
  • Het oostelijkste punt van al mijn routes.
  • Het noordelijkste punt van al mijn routes.
  • Het zuidelijkste punt van al mijn routes.

Deze informatie stellen me in staat om een vierkant te maken (de bounding box) waarbinnen alle punten vallen:

Nu heb ik nog een uitdaging. Mijn bbox kan een andere vorm hebben dan de vorm van de kaart die ik uiteindelijk wil maken:

Als de lichtgrijze vorm de bbox vanuit de data is, moet ik ervoor zorgen dat deze in mijn uiteindelijke vorm past, de donkergrijze vorm. Daarom bereken ik welke ruimte ik boven en onder de lichtgrijze bbox moet toevoegen om tot dezelfde verhouding te komen als het donkergrijze kader.

Maar als ik dat de eerste keer doe, maak ik een fout.

En die fout zie je hier.

Omdat ik mijn hardlooproutes goed ken, zie ik direct dat er iets niet in de haak is. Je kan het zien bij het stuk langs het kanaal (het meest zuidelijke stuk van mijn routes).

Op de eerdere kaarten was duidelijk te zien dat ik daar langs het kanaal afloop. Maar nu lijk ik langzaam van het kanaal weg te lopen (en dwars door een bos heen te gaan). En dat klopt niet.

Wat gaat hier mis?

Bij het berekenen van mijn bbox heb ik de afstand tussen twee locaties fout berekend. Ik keek naar het verschil tussen de minimale en maximale breedtegraad en de minimale en maximale lengtegraad. Maar dat moet ik niet doen. Ik moet berekenen wat de afstand in kilometers is tussen die twee punten. En omdat onze wereld een hele grote bol is, gaat dat net even wat anders.

Ik zoek wat uitleg op Wikipedia, vind iemand die zo aardig is om te vertellen hoe ik het in Python kan berekenen (de programmeertaal die ik gebruik), pas mijn code aan en probeer het nog eens:

Bingo! Ik loop weer netjes langs het kanaal af.

En dit keer komt de kaart automatisch voort uit mijn hardloop data.

Puntes op de i

Nu wil ik nog een paar dingen aanpassen:

  1. Wederom een titel toevoegen, zodat je weet om welke data het gaat.
  2. De locatie van de titel automatisch bepalen o.b.v. de ingelezen data, zodat het voor elke dataset op dezelfde plek staat.
  3. De route wat marge geven zodat de lijn niet direct tegen de rand van de kaart aan komt.
  4. Het copyright blok aanpassen, want die stijl vloekt wat met de rest van de stijl.

En met deze aanpassingen kom ik tot het volgende resultaat:

Best wel tof, al zeg ik het zelf 🙂

En wederom test ik het op een trailrun die op vakantie liep. Ik pas alleen de hardloopdata aan, draai mijn code opnieuw, et voila:

Oké, dit is best wel tof.

Tot een paar weken terug had ik nog niet met hardloopdata gewerkt.

En inmiddels kan ik data-gedreven routekaarten genereren.

Het einddoel is nog niet bereikt, maar dit is wel een mooie mijlpaal om even van te genieten.


Doe het zelf

Ben je bekend met Python en wil je zelf aan de slag met deze code? Bekijk dan mijn repository op GitHub.

Nog niet bekend met Python en datavisualisatie en wil je het leren? Neem dan contact op.