Daten mit deck.gl auf Google Maps visualisieren
Es ist nicht leicht, große Datenmengen auf einer Karte zu visualisieren? Unser Entwickler Robert erklärt in diesem Tutorial, wie man mit nur 160 Zeilen JavaScript Daten aus Google Sheets laden und mithilfe von deck.gl auf Google Maps visualisieren kann.
Wir werden dazu einen großen, frei zugänglichen Datensatz mit Kraftwerken aus aller Welt nutzen. Das verspricht eine spannende Visualisierung. Vielleicht können wir damit Muster in der Energieproduktion finden? Am Ende wird das Ergebnis dann so aussehen:
Wir benötigen Daten
Beim World Resources Institute können wir uns ein CSV mit allen Kraftwerken herunterladen und in Google Sheets hochladen.
Da wir nicht alle Daten aus dem Dokument benötigen, können wir unnötige Spalten entfernen. Dadurch reduzieren wir die Datenmenge, die für die Visualisierung geladen werden muss. Wir werden uns auf die sechs Spalten beschränken, die unten zu sehen sind. Das Beispiel-Sheet gibt es hier und kann gern wiederverwendet werden.
Um zu zeigen, wie Energie produziert wird, färben wir die Punkte auf der Karte abhängig vom Typ des Kraftwerks ein. Die Größe des Punktes beschreibt dabei die Kapazität des Kraftwerks. Latitude und Longitude verwenden wir natürlich, um die Punkte auf der Karte zu verorten.
Kein natives Rendern von großen Datenmengen mit Google Maps
Ungefähr 30.000 Kraftwerke sind in dem Datensatz aufgeführt. So große Datenmengen auf einer Google-Karte zu visualisieren ist nicht ganz so einfach. Mit dem Data Overlay der Google Maps API bekommt man leider Performanceprobleme beim Rendern einer so großen Menge an Daten. Andere Methoden, wie z.B. ein SVG-Overlay, machen schon bei ein paar Hundert Punkten Probleme beim Rendern. Deswegen schauen wir uns deck.gl an.
Was ist deck.gl?
deck.gl wurde 2016 veröffentlicht und brachte WebGL-basiertes Rendern mithilfe der Grafikkarte auf digitale Karten. Das verspricht gute Render-Performance! Lange Zeit funktionierte dies leider nicht mit Google Maps. Seit der Veröffentlichung von Version 7 im April 2019 gibt es nun aber offiziellen Support für deck.gl auf Google Maps. Schauen wir uns an, wie wir beides zusammen implementieren können!
Natürlich müssen wir deck.gl zu unserer Visualisierung hinzufügen:
<script src="https://unpkg.com/deck.gl@7.0.9/dist.min.js"></script>
Eine Google Map erzeugen
Als Basis für die Visualisierung benötigen wir eine Google Map. Dazu muss die Google Maps API geladen werden. Zunächst benötigen wir einen API key und können sie dann einbinden:
<script src="https://maps.googleapis.com/maps/api/js?key=###YOUR_KEY###&callback=initMap"></script>
In dem script tag wird ein Callback definiert, welcher die Karte erzeugt, wenn die API geladen wurde:
let map; function initMap() { map = new google.maps.Map(document.getElementById('map'), { center: {lat: 17, lng: 0}, minZoom: 3, zoom: 3, clickableIcons: false, disableDefaultUI: true, zoomControl: true }); }
Daten aus Google Sheets laden
Die Daten über die Kraftwerke liegen noch in unserem Google Sheet. Damit die Daten im JavaScript geladen werden können, muss das Dokument für das Web veröffentlicht werden. Im Spreadsheet unter “Datei” -> “Im Web veröffentlichen” klickt ihr auf den Veröffentlichen-Button.
Mit einem script tag kann das Sheet nun geladen werden. Dazu muss die ID von dem Sheet in der URL des script tags eingefügt werden. Diese findet man in der URL des Sheets nach dem /d/
. In unserem Beispiel lautet die ID 1MsFYOQlys_jyTACIZRbk3VWX9qaUdfrsr_r2Y-oxuZo
.
Am Ende des script tags definieren wir einen Callback, der aufgerufen wird, wenn die Daten geladen wurden:
<script
src="https://spreadsheets.google.com/feeds/list/###SHEET_ID###/1/public/values?alt=json-in-script&callback=createOverlay">
</script>
Die Daten können wir uns nun in dem Callback anschauen:
function createOverlay(spreadsheetData) {
console.log(spreadsheetData);
}
Ein deck.gl GeoJSON Overlay erzeugen
Google Sheets liefert ein JSON in einer merkwürdig geschachtelten Struktur aus. Um diese Daten zu visualisieren, erzeugen wir zunächst ein GeoJSON:
const data = {
type: 'FeatureCollection',
features: spreadsheetData.feed.entry.map(item => {
return {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [
Number(item.gsx$longitude.$t),
Number(item.gsx$latitude.$t)
]
},
properties: {
name: item.gsx$name.$t,
country: item.gsx$countrylong.$t,
capacity: Number(item.gsx$capacitymw.$t) || 0,
primaryFuel: item.gsx$primaryfuel.$t
}
}
})
};
Informationen wie die Kapazität und die Art des Kraftwerks werden zu den properties des GeoJSON hinzugefügt, damit wir diese zum Styling verwenden können.
Um das GeoJSON zur Karte hinzuzufügen, erzeugen wir einen GeoJsonLayer
von deck.gl:
const geojsonLayer = new GeoJsonLayer({
id: 'geojsonLayer',
data: data,
pickable: true,
pointRadiusMinPixels: 2,
pointRadiusMaxPixels: 140,
wrapLongitude: true,
getRadius: d => d.properties.capacity * 40,
getFillColor: d => fuelColorMapping[d.properties.primaryFuel] || [100, 100, 100, 194]
});
Das GeoJSON geben wir in den Layer mit hinein. Um den Radius der Punkte zu berechnen, verwenden wir die Kraftwerkskapazität aus den properties. Die Farbe wird über die property primaryFuel
definiert. An dieser Stelle verwenden wir ein Objekt, das als Key den Typ und als Wert ein Farb-Array hat.
Wir haben nun einen Layer, aber auf der Karte ist noch nichts zu sehen.
Einen deck.gl Layer zu Google Maps hinzufügen
Die Karte und der Layer müssen noch miteinander verknüpft werden, damit wir unsere Visualisierung sehen können. deck.gl bietet ein GoogleMapsOverlay
an, was genau das macht:
const overlay = new GoogleMapsOverlay({
layers: [geojsonLayer]
});
overlay.setMap(map);
Yay! Die Daten erscheinen nun auf der Karte!
Interessant, wie die Wasserkraftwerke auf der Welt verbreitet sind. Die Zahl der Kohlekraftwerke vor allem in China und Indien wirkt erschreckend angesichts der gegenwärtigen Klimakrise.
Ein Info Window bei Klick öffnen
Die Daten auf der Karte zu sehen ist toll, aber Informationen über die Kapazität und den Namen des Kraftwerks zu sehen wäre auch interessant. Dazu verwenden wir ein Info Window:
const infowindow = new google.maps.InfoWindow({
content: ''
});
map.addListener('click', event => {
const picked = overlay._deck.pickObject({
x: event.pixel.x,
y: event.pixel.y,
radius: 4,
layerIds: ['geojsonLayer']
});
if (!picked) {
infowindow.close();
return;
}
infowindow.setContent(
`<div>
<div><b>${picked.object.properties.name}</b></div>
<div>${picked.object.properties.country}</div>
<div><b>capacity:</b> ${picked.object.properties.capacity}</div>
<div><b>type:</b> ${picked.object.properties.primaryFuel}</div>
</div>
);
infowindow.setPosition({
lng: picked.lngLat[0],
lat: picked.lngLat[1]
});
infowindow.open(map);
});
Wenn auf die Karte geklickt wird, überprüfen wir, ob in unserem Overlay ein Element an dieser Stelle zu finden ist. Ist keines zu finden, wird das Info Window geschlossen. Ansonsten nutzen wir die Daten aus den properties des GeoJSON des Kraftwerks und öffnen das Info Window an der Position.
Zusammenfassung
Daten aus Google Sheets laden und eine Visualisierung auf Google Maps mit einem deck.gl GeoJsonLayer zu erzeugen, funktioniert erstaunlich einfach – mit nur wenigen Zeilen Code. Die Visualisierung von großen Daten ist damit deutlich leichter geworden. Hoffentlich hilft dieser Artikel beim Einstieg!
Was werdet ihr visualisieren? Lasst es uns auf Twitter @ubilabs wissen oder schreibt uns an info@ubilabs.com!
Schaut euch bei Interesse den kompletten Quellcode des Beispiels an. Das Beispiel gibt es hier auch in voller Größe zu erkunden: deck-gl-on-google-maps.glitch.me.