Big Data im Netz visualisieren: So funktioniert die JavaScript-Bibliothek D3

Big Data im Netz visualisieren (Grafik: mamanamsai2 / iStock)
D3 ist eine der mächtigsten unter der Vielzahl aktuell verfügbarer JavaScript-Bibliotheken zur Datenvisualisierung. Bereits die D3 Gallery verrät, dass von einfachen Datentabellen über aufwendig gestylte und animierte Charts bis hin zu hochkomplexen und auch interaktiven Diagrammen scheinbar nur den Fähigkeiten des Entwicklers Grenzen gesetzt sind. Nicht zuletzt die Tatsache, dass die Bibliothek unter der BSD-Lizenz veröffentlicht wird, macht einen genaueren Blick auf diese Library sehr lohnenswert.
Data-Driven Documents
D3 steht für „Data-Driven Documents“ und wird seit 2011 von Mike Bostock als Open-Source-Bibliothek für Datenvisualisierung auf Github veröffentlicht, kontinuierlich erweitert und optimiert. Die Bibliothek erlaubt die Manipulation des DOM von HTML-Dokumenten auf der Grundlage von Datensätzen. Dafür nutzt sie die Möglichkeiten moderner Browser wie Chrome, Safari, Firefox, Opera oder IE9+ sowie der aktuellen Webstandards CSS3, HTML5 und SVG.
Müssen auch ältere Browser unterstützt werden, bietet sich eher das Pendant R2D3 an. Dabei handelt es sich um ein angepasstes D3, das durch die Kombination mit der Library Raphaël bis zum IE7 lauffähig ist. Allerdings sind hier die Entwicklungszyklen wesentlich länger und weit hinter dem Stand der aktuellen D3-Version, weshalb ein Einsatz nicht wirklich zu empfehlen ist.
Bei der Entwicklung von D3 wird besonderer Wert auf eine maximale Flexibilität gelegt. Hohe Performance in der Verarbeitung großer Datenmengen und die Möglichkeit der dynamischen Manipulation von Animationen und Interaktionen sind weitere Features des Frameworks.

Mit D3 lassen sich hervorragende Visualisierungen auf Datenbasis erstellen, die mit Animationen und Möglichkeiten zur Nutzerinteraktion erweiterbar sind. (Screenshot: d3js.org)
Dieses besteht neben dem Core aus den Komponenten Scales, SVG, Time, Layouts, Geography, Geometry und Behaviours. Im Kern verankert sind unter anderem Funktionen zur Auswahl von DOM-Elementen, zur Erstellung von Animationen, Verarbeitung von Daten und Manipulation von Farben. Die Bezeichnungen der anderen Komponenten deuten bereits auf ihre Funktionen hin. Eine detaillierte Erklärung findet sich in der API-Referenz von D3. Darüber hinaus kann man die Funktionalität wie bei jQuery über Plugins erweitern, sollten die integrierten Möglichkeiten einmal doch nicht ausreichen. Eine weitere Ähnlichkeit zu jQuery ist das praktische Chaining, also das Verketten von Funktionen.
DER EINSTIEG IN D3
Anhand eines einfachen Beispiels, in Anlehnung an Swizec Tellers „Data Visualisation with D3.js“, lassen sich die Grundlagen von D3 nachvollziehen. Als Datenbasis sollen hier die unter den t3n-Mediadaten veröffentlichten t3n-Facts dienen. Das Ziel ist die vergleichende Darstellung aktueller Reichweiten der verschiedenen t3n-Kanäle als Visualisierung in einem Säulendiagramm.
Zu Beginn dieses Tutorials ist es notwendig, die D3-Library herunterzuladen und in ein HTML5-Dokument einzubinden. Dies muss nicht im Head-Bereich, sondern kann kurz vor dem schließenden Body-Tag geschehen. Alternativ zum Download ist es auch möglich, das Skript zum Testen direkt von d3js.org einzubinden.
D3 EINBINDEN
<script xsrc="js/d3.min.js" charset="utf-8"></script>
Listing 1
Es ist empfehlenswert, den Beispielcode auf einem Server auszuführen, um mögliche Probleme mit den Sicherheitsvorkehrungen des Browsers bei einem AJAX-Request zu umgehen. Der Localhost des Entwicklungsrechners ist hier meist eine geeignete Lösung.
Die nachfolgend aufgeführte Projektstruktur ist nicht direkt für die Arbeit mit D3 notwendig. Sie dient vielmehr als Konvention zur klaren Trennung von Inhalt, Struktur und Funktionalität zwecks besserer Übersichtlichkeit und Wartbarkeit. Das direkte Integrieren der Daten in das Anwendungsskript ist ebenso wenig empfehlenswert, wie HTML mit Inline-Style-Angaben anzureichern.
ALLGEMEINE PROJEKTSTRUKTUR
projekt/ |- css/ |- main.css |- data/ |- data.json |- js/ |- d3.min.js |- app.js index.html
Listing 2
In dem minimalen HTML-Gerüst spiegelt sich die Projektstruktur wieder, und es bildet die Basis zur Visualisierung der Daten. Neben der Einbindung von Stylesheets und Skripten empfiehlt es sich, einen DIV-Container bereitzustellen, in den später das Säulendiagramm gerendert wird. Der Container erhält die frei gewählte ID „bar-chart“ als eindeutigen Selektor.
BASIC HTML
<!doctype html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>d3js | t3n Social-Media-Reichweiten im Vergleich</title> <link rel="stylesheet" href="css/main.css"> </head> <body> <div id="bar-chart"></div> <script xsrc="js/d3.min.js"></script> <script xsrc="js/app.js"></script> </body> </html>
Listing 3
DATEN MIT FORMAT
D3 zeichnet sich unter anderem dadurch aus, dass es mit den unterschiedlichsten Dateiformaten umgehen kann. TEXT, JSON, XML, HTML, CSV oder TSV lassen sich – eine valide Datenstruktur vorausgesetzt – problemlos verarbeiten. Da sich JSON für kleinere, strukturierte Datenmengen sehr gut eignet, werden die t3n-Facts als Schlüssel-Werte-Paare in einem JSON-Array als Datei data.json abgelegt. Der Name der Datei ist auch hier frei wählbar. Gleiches gilt für den Aufbau der validen JSON-Datei.
DATA.JSON
[ {"channel":"Magazin-Leser","quantity": 54000}, {"channel":"Registrierte User","quantity": 42000}, {"channel":"Twitter-Follower","quantity": 38800}, {"channel":"Twitter-Follower","quantity": 38800}, {"channel":"Facebook-Fans","quantity": 70000}, {"channel":"Google+-Follower","quantity": 51700}, {"channel":"t3n-Newsletter-Empfänger","quantity": 21000}, {"channel":"RSS-Feed-Abonnenten","quantity": 17000} ]
Listing 4
POSITION BEZIEHEN
Nun gilt es, sich der Datei app.js zu widmen, die den Code zur Generierung des Säulendiagramms aufnehmen soll. Zuerst werden die Dimensionen des Diagramms und dessen Randabstände bestimmt. In den Variablen „leftPadding“ und „bottomPadding“ legen wir einen größeren Abstand nach links und unten fest, der für die Darstellung der Achsenlabels notwendig ist.
APP.JS: DIMENSIONEN DES DIAGRAMMS
var width = 600, height = 300, padding = 20, leftPadding = 100; bottomPadding = 120;
Listing 5

Es müssen nicht immer Balken oder Torten sein – D3 ermöglicht mannigfaltige Visualisierungen, die Big Data begreifbar machen. (Screenshit: github.com)
Als nächstes brauchen wir eine Skala für die x-Achse. Beim Säulendiagramm nutzt man dafür die Ordinalskala, die D3 mit der Funktion ordinal() bereitstellt. rangeRoundBands sorgt dann dafür, dass die Auswahl an zu verarbeitenden Werten in separate Säulen unterteilt wird.
Diese Funktion verhindert zudem Antialiasing-Artefakte bei der Darstellung durch Nutzung von ganzen Zahlen.Für das Beispiel kommen später die Werte mit dem Schlüssel „quantity“ aus data.json zum Einsatz, welche hier zwischen 17000 und 70000 liegen. leftPadding und width-padding legen den Bereich fest, in dem die Säulen aufgeteilt werden. Auch der Abstand zwischen den Säulen lässt sich einstellen. Im Beispiel besitzt er den Zahlenwert 0.1.
Zur linearen Skalierung der y-Achse nutzen wir die Funktion linear(). Der Bereich für die Darstellung der Achse wird mit height – bottomPadding sowie padding definiert. Zu beachten ist hierbei, den Bereich umgekehrt anzugeben, da D3.js immer von y=0 ausgeht.
APP.JS: SKALIERUNG DER ACHSEN
... var x = d3.scale.ordinal() .rangeRoundBands([leftPadding, width - padding],0.1); var y = d3.scale.linear() .range([height - bottomPadding, padding]);
Listing 6
Die Definition der beiden Achsen erfolgt nun mit Hilfe des Funktionsaufrufs d3.svg.axis(). Der folgenden Funktion scale() wird mit den Variablen x oder y jeweils übergeben, welche Skalierung genutzt werden soll. Die Lage der Achsenbezeichnung bestimmt man mit Hilfe von orient().
APP.JS: DEFINITION DER ACHSEN
... var abscissa = d3.svg.axis().scale(x).orient("bottom"); var ordinate = d3.svg.axis().scale(y).orient("left");
Listing 7
Bevor die JSON-Daten geladen werden können, muss nun noch das SVG-Element definiert und dem DIV-Container #bar-chart zugewiesen werden. Zur einfacheren Verwendung wird dies ebenfalls als Variable angelegt. Abschließend erfolgt die Deklaration des Objekts data, welches später mit Daten befüllt wird.
APP.JS: DATEN PER AJAX LADEN
... var svg = d3.select("#bar-chart").append("svg") .attr("width", width).attr("height", height); var data;
Listing 8
AJAX INKLUSIVE: LADEN VON DATENSÄTZEN
Eines der Hauptargumente für den Einsatz von D3.js ist die Möglichkeit des asynchronen Ladens von Daten. Dafür stehen komfortable Funktionen zum Datenimport bereit. Der folgende Funktionsaufruf erzeugt einen AJAX-Request, um die JSON-Datei zu laden, parst den zurückgelieferten Text und speichert ihn in das JavaScript-Objekt data. Ab hier wird der weitere Code innerhalb dieses Callbacks geschrieben, um auf die Daten zugreifen zu können.
APP.JS: DEFINITION DES SVG ELEMENTS
... d3.json("./data/data.json", function(data) { // weiterer Code innerhalb dieses Callbacks });
Listing 9
Die zuvor definierten Skalen für x- und y-Achse müssen nun einem Wertebereich zugeordnet werden. Mit der D3-Funktion domain() lassen sich die Werte aus dem gefüllten data-Objekt auf die Achsen mappen. Der Wertebereich der x-Achse ist hier eine Auflistung einzelner Werte, die mit data.map(function(d) { return d.channel; }) der Achse zugeordnet werden. Die Daten lassen sich dabei über den Schlüssel channel auswählen. Für die y-Achse wird der Wertebereich ausgehend von 0 bis zum größten Wert innerhalb des Datensatzes via d3.max() mit dem Schlüssel quantity festgelegt.
APP.JS: ZUWEISUNG DER DOMAINS
... x.domain(data.map(function(d) { return d.channel; })); y.domain([0, d3.max(data, function(d) { return d.quantity; })]); ...
Listing 10
DAS DIAGRAMM ZEICHNEN
Dem SVG-Element wird zunächst ein Element g hinzugefügt. Letzterem werden die Klassen axis und abscissa mitgegeben, über die es dann per CSS gestylt werden kann. Mit Hilfe des transform-Attributes erfolgt die Positionierung der x-Achse innerhalb des Diagramms. Da die zugehörigen Labels recht lang sind, ist es sinnvoll, diese leicht zu drehen und mit etwas Abstand zur Achse zu positionieren. Die abschließend aufgerufene Funktion call() mit der Variablen abscissa wendet die vorherigen Funktionen auf die jeweilige Achse an.
Das Zeichnen der y-Achse ist in diesem Fall weniger umfangreich zu beschreiben, da die Labels nicht positioniert werden müssen. Es genügt, die entsprechenden Argumente auszutauschen. Die Aufteilung und Beschriftung der Achse(n) wird vollständig von D3.js übernommen.
APP.JS: ZEICHNEN DER ACHSEN
... // Zeichnen der x-Achse svg.append("g") .attr("class", "axis abscissa") .attr("transform", "translate(0, "+ (height - bottomPadding)+")") .call(abscissa) // Positionierung der Label .selectAll("text") .style("text-anchor", "end") .attr("dx", "-.5em") .attr("dy", ".15em") .attr("transform", function(d) { return "rotate(-25)" } ); // Zeichnen der y-Achse svg.append("g") .attr("class", "axis ordinate") .attr("transform", "translate("+(leftPadding)+", 0)") .call(ordinate); ...
Listing 11
Damit ist alles bereit, um das Diagramm zu zeichnen. Um die einzelnen Werte innerhalb einer Säule als SVG-Text anzeigen zu können, wird ein Objekt namens barChart erstellt. Dieses enthält den Funktionsaufruf selectAll(„rect“), der im SVG-Objekt alle übergebenen Rechtecke auswählt. Der Funktion data() werden die Daten zur Verfügung gestellt, und enter() gibt nun genau die zuvor selektierten Elemente zurück.
Dem barChart-Objekt fügt man nun mittels append(„rect“) die Säulen auf Basis der Daten hinzu. Das Class-Attribut erleichtert auch hier späteres Styling. Schließlich gilt es noch, die Positionierung zu x- und y-Achse vorzunehmen und die Breite der Säulen mit der Funktion x.rangeBand() zuzuordnen.
Um dem Diagramm Dynamik zu verleihen, werden die Säulen noch mit transition() animiert. Ziel ist es, sie von der x-Achse aus zeitversetzt zu ihrem jeweiligen Maximalwert anwachsen zu lassen. Dazu erhalten die Säulen vor dem Aufruf der Animation eine Höhe von 0. Die Funktion delay() ist für die Verzögerung der Animation zuständig, duration() bestimmt die Dauer in Millisekunden.

Per CSS lassen sich die Säulen, der Text und die Achsen des Diagramms individuell gestalten. (Grafik: t3n)
Abschließend gilt es noch, SVG-Text für die Werte in den Säulen mit Hilfe von .append(„text“) zu ergänzen. Hierzu werden die Zahlenwerte zunächst zu den Achsen und Säulen positioniert. Da die meisten D3-Elemente gleichzeitig Objekte und Funktionen sind, lassen sich hier die anfangs definierten Variablen x und y für die Positionierung nutzen, zum Beispiel mit return x(d.channel). Nach der Ausrichtung des Textankers fehlt nur noch die Textausgabe, welche die Aufgabe der Funktion text() ist.
APP.JS: ZEICHNEN DES DIAGRAMMS
... var barChart = svg.selectAll("rect") .data(data) .enter(); // Säulendiagramm zeichnen barChart.append("rect") .attr("class", "bar") .attr("x", function(d) { return x(d.channel); }) .attr("y", height - bottomPadding ) .attr("width", x.rangeBand()) .attr("height", 0) // Animation der Balkenhöhe .transition() .delay(function(d, i) { return i * 80; }) .duration(800) .attr("y", function(d) { return y(d.quantity); }) .attr("height", function(d) { return height - bottomPadding - y(d.quantity); } ); // Werte als SVG-Text in Säulen anzeigen und positionieren barChart.append("text") .attr("x", function(d) { return x(d.channel); }) .attr("y", function(d) { return y(d.quantity); }) .attr("dx", x.rangeBand()/2) .attr("dy", "1.5em") .attr("text-anchor", "middle") .text(function(d) { return (d.quantity); }); ...
Listing 12
Mit der Einbindung einer Stylesheet-Datei und ein wenig CSS lässt sich das SVG-Diagramm ansprechend stylen.
Fazit
Neben klassischen Diagrammarten wie Balken- oder Säulendiagrammen lassen sich mit D3 auch komplexere Arten wie Treemaps oder Akkorddiagramme realisieren. Sucht man ein Werkzeug, um schnell ein paar Charts auf einer Webseite einzubinden, wäre D3 aufgrund seiner Komplexität und seiner granulären Kontrollmöglichkeiten wohl nicht das passende Mittel der Wahl. Auch der Zeitaufwand für die Einarbeitung ist nicht zu unterschätzen. Wer sich jedoch einmal für D3 entschieden hat, dem steht ein mächtiges Werkzeug zur Visualisierung von Daten zur Verfügung.