Klimawandel verstehen
Eine Website, die D3.js nutzt, um Klimawandeldaten visuell zu analysieren. Visualisierungen umfassen Linien- und Stacked-Area-Charts globaler Klimadaten sowie eine detaillierte Choropleth-Karte und weitere Darstellungen kanadischer Wetterdaten.
Typ
D3.js Website
Jahr
2018
Angewandte Fähigkeiten
- D3.js
- Front-End
Team
- Eigenes Projekt
<h2>Die Aufgabe</h2>
<p>Als Übung interaktiver Datenvisualisierung planten wir, Klimawandeldaten umfassend zu visualisieren. Unser Ziel war, komplexe Datensätze in einfache Diagramme zu verdichten, die Mechanismen, Ursprünge und lokale Auswirkungen des Klimawandels in Kanada vermitteln. Um Nutzer anzusprechen, entwickelten wir einfache Interaktionen wie Pop-up-Tooltips sowie komplexere wie Brushing, Darstellungswechsel und Animation.</p>
Das Ergebnis
Klimawandel verstehen
Vier farbcodierte Liniendiagramme globaler CO₂-Emissionen und atmosphärischer Konzentration sowie ein Stacked-Area-Chart der CO₂-Emissionen nach Region.
<h3>Auswirkungen des Klimawandels verstehen</h3>
<p>Mit der Choropleth-Karte Kanadas und seiner Provinzen und Territorien können Nutzer kanadische Wetterdaten – einschließlich Temperatur und Niederschlag – nach Jahr, Monat und Provinz erkunden. Zusätzlich gibt es ein Spider-Chart der globalen Temperaturanomalie über die Zeit. Beide Diagramme sind dynamisch abfragbar und animierbar.</p>
<h3>Zusammenfassung der Klimawandelauswirkungen</h3>
<p>Die Summary-Charts zeigen einen Zusammenhang – oder dessen Fehlen – zwischen CO₂-Emissionen und Wetteranomalien. Vier Liniendiagramme der mittleren kanadischen Wettertemperatur, des Niederschlags und deren Anomalien sind mit einem Liniendiagramm globaler CO₂-Emissionen gruppiert.</p>
Prozess
Wir entwickelten das Projekt zu zweit über zwei Monate hinweg – unsere erste Erfahrung mit D3.js. Früh definierten wir zwei zentrale Fragen, die das Projekt beantworten sollte:
- Was sind die Beitragsfaktoren zum Klimawandel?
- Da der Klimawandel das Wetter beeinflusst: Gibt es Anzeichen dafür, dass sich das kanadische Wetter abnormal verhält?
Nach der Fragestellung suchten wir relevante Daten. Die meisten mussten von Ausreißern und fehlerhaften Werten bereinigt werden. Am komplexesten war der kanadische Wetterdatensatz: Mehrere große Datensätze mussten manuell zusammengeführt, bereinigt, sortiert und monatliche sowie jährliche Durchschnitte berechnet werden.
In der finalen Phase entwickelten wir die D3.js-gesteuerten Visualisierungen und bauten die Website, die zugleich als Projektbericht dient. Die meisten Diagramme – einschließlich Linien- und Stacked-Area-Charts – waren relativ unkompliziert. Mit Abstand am komplexesten war die Choropleth-Karte kanadischer Wetterdaten. Die visuelle Zuordnung von Daten zu Geografie und Farbe war anspruchsvoll, das Ergebnis lohnte sich: Die Karte bietet eine ansprechende, interaktive Möglichkeit, einen großen Wetterdatensatz schnell zu durchsuchen und lokale sowie bundesweite Beobachtungen zu machen.
Der Code
Das Projekt ist in HTML, CSS und JS entwickelt; für die Visualisierungen nutzen wir die datengetriebene Bibliothek D3.js. Die Umsetzung aller Visualisierungen war anspruchsvoll, da D3 für uns neu war – besonders die Ketten-Syntax war anfangs umständlich. Der allgemeine Workflow lädt Daten, wählt DOM-Elemente aus und fügt SVG-Elemente mit bestimmten, an die Daten gebundenen Attributen ein. Im Auszug unten wird das kanadische Wetterdaten-Diagramm in drawMap() gerendert; die Farbe jeder Provinz wird Temperatur- oder Niederschlagsdaten je nach Nutzereingabe zugeordnet. Der Auszug enthält ab Zeile 58 auch Hover-Interaktionen für einzelne Provinzen: Die Provinz wird hervorgehoben und die Legende über updateDataData() aktualisiert (im Beispiel nicht gezeigt).
// CODE SNIPPET, NOT THE FULL FILE /////////////////////////////////////////////////////////////////////////////////////// DRAW MAP (called on load and on interactions)var gTopo;function ready(error, topo) { gTopo = topo; updateDate(); drawMap();}////////////////////////// drawMap() - draws map comprised of individual provinces, styled according to current interaction statefunction drawMap() { //clear old map if (d3.selectAll(".oldChart")) { d3.selectAll(".oldChart").remove(); } //--------------------------------------------- Draw the map svg.append("g") .attr("class", "oldChart") .selectAll("path") .data(gTopo.features) .enter() .append("path") //----------------------------------------- Draw each province .attr("d", d3.geoPath() .projection(projection) ) // Set the color of each province .attr("fill", function (d, i) { var output; if (usingMonth){ switch(curColorCode){ case colorCoding.T: output = colorScaleT(-getValueByMonth(dataNest, convertName(d.properties.NAME), curYear, curMonth, "tMean")); break; case colorCoding.TD: output = colorScaleTD(-getValueByMonth(dataNest, convertName(d.properties.NAME), curYear, curMonth, "tDiff")); break; case colorCoding.P: output = colorScaleP(getValueByMonth(dataNest, convertName(d.properties.NAME), curYear, curMonth, "pMean")); break; case colorCoding.PD: output = colorScalePD(getValueByMonth(dataNest, convertName(d.properties.NAME), curYear, curMonth, "pDiff")); break; } } else { switch(curColorCode){ case colorCoding.T: output = colorScaleT(-getValueByYear(dataNest, convertName(d.properties.NAME), curYear, "tMean")); break; case colorCoding.TD: output = colorScaleTD(-getValueByYear(dataNest, convertName(d.properties.NAME), curYear, "tDiff")); break; case colorCoding.P: output = colorScaleP(getValueByYear(dataNest, convertName(d.properties.NAME), curYear, "pMean")); break; case colorCoding.PD: output = colorScalePD(getValueByYear(dataNest, convertName(d.properties.NAME), curYear, "pDiff")); break; } } return output; }) .style("stroke", "transparent") .attr("class", function(d){ return "Country" } ) .style("opacity", 1) // Listen for mouse interactions .on("mouseover", mouseOver ) .on("mouseleave", mouseLeave );}///////////////////////////////////////////////////////////////////////////////////////////////////// Hoverlet mouseOver = function(d) { // Interact with individual provinces only if toggled to Provincial data if (!showingCanada){ // To highlight the province, set all others to .5 opacity d3.selectAll(".Country") .transition() .duration(200) .style("opacity", .5) d3.select(this) .transition() .duration(200) .style("opacity", 1) // Update province label in the legend, call updateDateData() to update t and p values in the legend curProvince = d.properties.NAME; lblProvince.text(d.properties.NAME); updateDateData(false); } else { // If toggled to Canadian data, highlight Provincial data button while hovering document.getElementById("canadaMapShowProvincial").classList.add("highlightPbtn"); }}let mouseLeave = function(d) { d3.selectAll(".Country") .transition() .duration(200) .style("opacity", 1) d3.select(this) .transition() .duration(200) .style("stroke", "transparent") if (showingCanada) document.getElementById("canadaMapShowProvincial").classList.remove("highlightPbtn");}