Blog der Heimetli Software AG

Geburtenrate 1960 - 2008

Im Buch Visualize this von Nathan Yau wird gezeigt wie eine Histogramm-Matrix gezeichnet werden kann. Die Matrix ist aber recht umfangreich und nicht so schnell zu durchschauen. Deshalb habe ich mir zum Ziel gesetzt diese Graphik zu animieren.

Dank der D3.js Library ist dies auch gelungen, wie Sie hier sehen koennen.

1960

Nach dem Ablauf der Animation können Sie mit diesem Slider ein Jahr auswählen

Direkter Vergleich 1960 und 2008

Obwohl man mit dem Diagramm oben einzelne Jahre gezielt auswählen und anzeigen kann, ist es immer noch recht schwierig den Unterschied zwischen dem Anfang und dem Ende der Periode zu erfassen. Das brachte mich auf die Idee, diese beiden Graphiken zu überlagern. In hellem Grau ist die Verteilung im Jahre 1960 dargestellt, Steelblue zeigt die Daten von 2008.

Datenquelle und Datentransformation

Die Rohdaten stammen von Nathan Yau. Auf seiner Site flowingdata.com stellt er sie als CSV zum Download bereit.

In diesem CSV sind die Raten der einzelnen Länder für jedes Jahr aufgelistet. Es braucht also eine Datentransformation um sie in die gewünschte Form zu bringen.

Man könnte natürlich die Werte aus dem CSV mit JavaScript im Browser aggregieren, aber ich habe sie schon in der notwendigen Form auf den Server gestellt.

Der erste Schritt war recht einfach, denn R kann die Daten nicht nur plotten sondern auch die Plotdaten ausgeben. Das war mit einem kleinen Programm schnell erledigt:

birth <- read.csv("http://datasets.flowingdata.com/birth-rate.csv")

breaks = c(2.5, 7.5, 12.5, 17.5, 22.5, 27.5, 32.5, 37.5, 42.5, 47.5, 52.5, 57.5, 62.5)
for( year in colnames(birth)[-1]) {
  print(year)
  data <- birth[year]
  data <- data[!is.na(data) & data < 100]
  h    <- hist(data,plot=FALSE,breaks=breaks)
  print( h$density * 500 )
}

Wenn es einen Weg gibt, diese Daten schön formatiert auszugeben, dann habe ich ihn auf jeden Fall nicht gefunden. Die Ausgabe sieht so aus:

[1] "X1960"
 [1]  0.000000  0.000000  6.635071 10.900474  7.582938  4.739336  7.582938
 [8] 11.374408 27.014218 20.853081  3.317536  0.000000
[1] "X1961"
 [1]  0.000000  0.000000  6.097561  8.536585  7.317073  4.268293  4.878049
 [8] 12.195122 30.487805 21.951220  4.268293  0.000000

Der zweite Schritt erforderte eine ganze Menge Tüfteln bis er gelang:

sed -E -e '1,2d' -e 's/\[[0-9]\]//' -e 's/[X"]//g' -e 's/^ +//' histograms.txt | awk 'BEGIN {print "["} NR % 3 == 1 { printf(" {\"year\":%d,", $1 )} NR % 3 == 2 {gsub(" +",",");printf("\"values\":[%s",$0)} NR % 3 == 0 {gsub(" +",",");printf(",%s]}%s\n",$0,NR!=147?",":"")} END {print "]"}'

Diese Pipeline erzeugt ein JSON-File für den Browser. Sie können histograms.json herunterladen falls Sie es ansehen oder selber benutzen wollen.

Update 21.11.2018

Bei R stolpere ich immer wieder zufällig über Funktionen die ich langei und erfolglos gesucht habe...

Mit cat wird das Erzeugen der JSON-Daten sehr viel einfacher:

birth <- read.csv("http://datasets.flowingdata.com/birth-rate.csv")

breaks = c(2.5, 7.5, 12.5, 17.5, 22.5, 27.5, 32.5, 37.5, 42.5, 47.5, 52.5, 57.5, 62.5)

cat( "[" )
for( year in colnames(birth)[-1]) {
  cat( "{\"year\":\"", substring(year,2,5), "\",\"values\":[", sep="" )
  data <- birth[year]
  data <- data[!is.na(data) & data < 100]
  h    <- hist(data,plot=FALSE,breaks=breaks)
  cat( h$density * 500, "]},", sep="," )
}
cat( "]" )

Dieses Programm hat nur noch einen kleinen Schönheitsfehler, nämlich dass vor dem Ende des Arrays immer ein Komma steht. Das wuerde man sicher auch noch hinkriegen, aber sed löst das elegant:

./r.bat formatted.r | sed '1,2d;s/,]/]/g'

Für Leser die ganz genau hinsehen: das Batch-File macht am Anfang ueberflüssige Ausgaben und deshalb werden die ersten zwei Zeilen gelöscht. sed für Windows kam mit Git bash auf den Computer.