Interaktive Karten mit QGIS, tippecanoe, Martin und MapLibre GL JS
Interaktive Karten im Web erfreuen sich heutzutage großer Beliebtheit, um diverse statistische Daten anschaulich visualisieren und analysieren zu können. Funktionen ermöglichen es, einzelne Aspekte gezielt ein- und auszublenden oder weitere Hintergrundinformationen abzurufen.
Wir beschreiben die technische Umsetzung einer interaktiven Österreich-Karte, die Bevölkerungsdaten von 2002 bis 2022 visualisiert.
Datenquellen
- Grenzen der Gemeinden, Bezirke und Bundesländer als Vektor-Shapefiles von Statistik Austria
- Hintergrund (Grenzen, urbane Gebiete, Straßen) von Natural Earth.
- Entwicklung der Bevölkerungszahlen von Statistik Austria.
QGIS
QGIS ist eine umfangreiche Open-Source-Software zur Bearbeitung, Analyse und Präsentation geografischer Informationen. Die Software ermöglicht es, eigene Karten mit Symbolen und Beschriftungen zu entwerfen. Daten können aus verschiedenen Quellen importiert und kombiniert werden. Wir haben umfangreiche Möglichkeiten, die Karte zu bearbeiten und mit eigenen Ebenen zu ergänzen.
Um neue Ebenen anzulegen, ziehen wir unsere Shapefiles (.shp) aus oben genannten Quellen einfach in das QGIS-Fenster.
QGIS bietet die Möglichkeit, Karten direkt als mbtiles-Datei zu exportieren. Diese Funktion ist jedoch sehr eingeschränkt. Da wir es genauer wissen wollen, exportieren wir die Ebenen als einzelne GeoJSON-Dateien (rechte Maustaste über Ebene -> Export -> Objekte speichern als...). Dabei ist es wichtig, das Koordinatenbezugssystem EPSG:4326 - WGS 84 auszuwählen. Die Dateinamen sollten mit Bedacht gewählt werden. Unsere späteren Ebenen werden die selben Namen tragen (schnucki.geojson -> staatsgrenze.geojson).
Vektorkacheln mit tippecanoe erzeugen
Um für die Kartendarstellung jeweils nur die benötigten Daten nachzuladen, konvertieren wir die großen GeoJSON-Dateien unter Beibehaltung von Ebenen und Objektdaten in eine einzige .mbtiles-Vektorkacheldatei - eine SQLite-Datenbank.
Dazu nutzen wir einen aktuellen Fork des Kommandozeilentools tippecanoe (ursprünglich Mapbox).
Wir holen die Quellen und kompilieren:
apt install build-essential libsqlite3-dev zlib1g-dev git
git clone https://github.com/felt/tippecanoe.git
cd tippecanoe
make -j
make install
Einfaches Beispiel der Verwendung:
tippecanoe -o austria.mbtiles -z4 -z9 -S1 -ab staatsgrenze.geojson bezirke.geojson...
Mit -o legen wir den Output auf "austria.mbtiles" fest. Mit -z4 stellen wir die minimale Zoomstufe und mit -z9 die maximale ein. Mit -S1 können wir die Vektoren simplifizieren. Damit keine unregelmäßigen Grenzen entstehen, zieht -ab Punkte verschiedener Ebenen auf gemeinsame Koordinaten zusammen. Hintenrum füttern wir die aus QGIS exportierten geojson Dateien.
Die enorme Funktionalität von tippecanoe ist hier beschrieben.
Martin - Vector Tiles Server
Die Auslieferung der Vektorkacheln in einer virtuellen Verzeichnisstruktur (Z/X/Y) lassen wir von Martin erledigen.
Dazu laden wir die unserer Plattform entsprechende Version von der Release-Seite des Projekts herunter und entpacken das Archiv nach /opt/martin.
Wir kopieren unsere austria.mbtiles-Datei nach /opt/martin und machen Martins Binary-Datei ausführbar:
chmod +x /opt/martin/martin
Zu Testzwecken starten wir den Server:
./martin -l 0.0.0.0:4000 austria.mbtiles
Martin sollte nun in einem Browser unter http://{IP-Adresse}:4000 erreichbar sein. Unter http://{IP-Adresse}:4000/austria (= Dateiname) /Z/X/Y stehen die Kacheln bereit.
Die Konfiguration kann in einer yaml-Datei vorgenommen werden - siehe Doku.
Da wir unsere Tiles auf der Webseite über https ausliefern wollen, aktivieren wir die Apache Proxy-Module...
a2enmod proxy
a2enmod proxy_http
...leiten das Verzeichnis /vtiles auf Martin um...
<VirtualHost *:443>
ServerName domain.org
DocumentRoot /var/www/domain
ProxyPass /vtiles http://127.0.0.1:4000/ retry=0
ProxyPassReverse /vtiles http://127.0.0.1:4000/
SSLCertificateFile /pfad/fullchain.pem
SSLCertificateKeyFile /pfad/privkey.pem
</VirtualHost>
...starten Apache neu...
systemctl restart apache2
...und starten Martin auf localhost:
./martin -l 127.0.0.1:4000 austria.mbtiles
Unsere Österreich-Karte ist nun unter https://domain.org/vtiles/austria erreichbar.
Einrichten von Martin als Service -> /etc/systemd/system/martin.service:
[Unit]
Wants=network.target
[Service]
ExecStart=/opt/martin/martin -l 127.0.0.1:4000 /opt/martin/austria.mbtiles
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable martin
sudo systemctl start martin
MapLibre GL JS
Die Darstellung der Karte übernimmt MapLibre GL JS, ein Open-Source Community-Fork von Mapbox GL JS. Die JavaScript-Bibliothek rendert verschiedene Quellformate auf einem GPU-beschleunigten WebGL-Canvas.
Die Darstellung der Karten wird in einer Style-Spezifikation festgelegt, in der die Quellen, Ebenen und deren Aussehen definiert werden:
{
"version": 8,
"name": "Austria",
"sources": {
"austria": {
"type": "vector",
"tiles": [
"https://fatvalley.at/vtiles/austria/{z}/{x}/{y}"
],
"minzoom": 1,
"maxzoom": 10
}
},
"layers": [
{
"id": "lineLayer_Staatsgrenze",
"source": "austria",
"source-layer": "aborder",
"type": "line",
"paint": {
"line-color": "#888888",
"line-width": 4
}
},
{
"id": "fillLayer_Bezirke",
"source": "austria",
"source-layer": "bezirke_conv",
"type": "fill",
"paint": {
"fill-color": "#bcc3d2"
}
},
{
"id": "lineLayer_Bezirke",
"source": "austria",
"source-layer": "bezirke_conv",
"type": "line",
"paint": {
"line-color": "#888888",
"line-width": 1
}
}
]
}
Hier werden aus unserer Vektor-Quelle die Staatsgrenze als Linienebene, die Bezirke einmal als Füllebene und einmal als Linienebene übereinandergelegt.
Und hier noch ein wenig JavaScript:
const map = new maplibregl.Map({
container: 'map',
style: mapstyle, // siehe oben - oder URL zu style.json
minzoom: 1,
maxzoom: 10,
zoom: 6.4,
// Kartenmittelpunkt
center: [13.3458, 47.6964],
//Festlegen der initialen Kartenränder
bounds: [
[9.293, 46.182], // Südwest
[17.432, 49.095] // Nordost
],
//Festlegen der maximalen Kartenränder
maxBounds: [
[6.759, 44.904], // Südwest
[20.746, 50.185] // Nordost
],
});
map.addControl(new maplibregl.NavigationControl());
Hier die oben gezeigte minimale Demo.
Datenaufbereitung
Die Daten zur Anzeige können wir von der Statistik Austria Website als CSV-Datei (Comma Seperated Values) herunterladen. Für jedes Jahr stehen für jede Gemeinde die Einwohnerzahlen, gegliedert nach Alter, zur Verfügung. Insgesamt reden wir hier von ca. 7,6 Millionen eingetragenen Zeilen im CSV oder in Summe 360MB Daten. Viel zu viel, um diese in unserer Karte zu verwerten!
Um die Daten für die Anzeige auf unserer Karte verwenden zu können, müssen wir sie vereinfachen und konvertieren. Wir schreiben uns JavaScript-Funktionen, die folgende Schritte vornehmen:
- Fetch von den Statistik-Austria Servern
- Parsen der CSV-Daten zu einem JavaScript-Array
- Auslesen und Zuteilen der Daten (Name und Bevölkerungsanzahl) je nach Gemeinde/Bezirk/Bundesland
- Zusammenführen der unterschiedlichen Quellen (Gemeinde, Bezirk, Bundesland) in ein einzelnes Array
- Zuweisung der Farbe (Hex-Wert) je nach Bevölkerungsanzahl (je weniger, desto heller)
- Abspeichern der fertigen Daten als JSON
Die Grundlage ist gelegt. Bitte Senf an: office@fatvalley.at