Mich interessieren Daten. Oft kann man Daten in Tabellenform aber schwer fassen. Deshalb habe ich versucht Daten die österreichischen Bundesländer zu visualisieren.
D.h. konkret möchte ich die Arbeitslosenquote der Bundesländer farblich als Österreichkarte darstellen. Dafür brauchen wir als erstes eine Karte Österreichs als *.svg Datei. Die ist schnell auf Wikipedia gefunden: Map of Austria.
Vorbereiten der Vektorgrafik
Ich habe diese Karte zwecks einfacherer Analyse in Processing leicht modifiziert. Das ist sehr einfach, da es sich bei .svg Dateien eigentlich nur um XML Dateien handelt. Man kann sie einfach in jedem Texteditor öffnen. Unter Linux geschieht das dann auch noch gleich mit Code-Highlighting. Folgende Tags wurden von mir einfach aus der Datei entfernt.
<title>Austria</title>
<desc>Political map of Austria</desc>
<filter id="f1">
<feGaussianBlur in="SourceGraphic" stdDeviation="10"/>
</filter>
<path id="Shadow" filter="url(#f1)" ..........................................>
Modifizierte Datei:

Data Mining
Das Aufspüren und Aufbereiten der Daten ist in diesem Fall sehr einfach. Die Statistik Austria bietet sie in verschiedenen Formen an. Ich beschränke mich vorerst auf die Quote der Bundesländer im Jahr 2010 und kopiere die ensprechende Tabelle.
Die erste Visualisierung
Die .svg Datei Österreichs wird geladen und dann in die einzelenen Pfade der Bundesländer zerlegt. Die Daten der Arbeitslosenzahlen werden in einem Array in einer Reihe, den Pfaden der Bundesländern entsprechend abgelegt. Dann wird jeder Pfad gezeichnet und entsprechend der ArbeitslosenQuote eingefärbt.
Starte Applet

// PShape Objekte erzeugen
PShape austria;
PShape[] bundesl;
//Titel
String title="Arbeitslosenqote Bundesländer 2010";
// Daten von Statistik Austria
float[] arblQuote = {
3.9, //Burgenland
3.9, //Carinthia
3.6, //Lower_Austria
3.7, //Upper_Austria
2.9, //Salzburg
4.2, //Styria
2.8, //Tyrol
3.9, //Vorarlberg
7.3 //Vienna
};
//Grundfarbe der Visualisierung
int col=210;
void setup() {
size(900, 500);
//Vektorgrafik laden
austria = loadShape("Map_of_Austria.svg");
//Pfade der einzelnen Bundesländer extrahieren
bundesl = austria.getChildren();
//Formatierung des Originals deaktivieren
austria.disableStyle();
noLoop();
colorMode(HSB, 360, 100, 100);
textAlign(CENTER, CENTER);
}
void draw() {
background(0, 0, 100);
stroke(col, 20, 99);
//Zeichnen der Bundesländer
for (int i=0; i<bundesl.length; i++) {
//Füllfarbe festlegen
fill(col, arblQuote[i]*13, 100);
//Zeichnen der Pfade
shape(bundesl[i], 0, 0);
println(bundesl[i].getName());
}
//Titel
textSize(20);
text(title, width/4,height*1/20);
}
Legende:
Eine Legende wäre jetzt natürlich noch nett. Dafür sollte man natürlich auch noch den Farbbereich automatisch an den Wertbereich der Daten anpassen.
starte Applet

/* @pjs preload="Map_of_Austria.svg"; */
// PShape Objekte erzeugen
PShape austria;
PShape[] bundesl;
//Titel and Source
String title="Arbeitslosenqote Bundesländer 2010";
String source=" Quelle: Statistik Austria";
// Daten von Statistik Austria
float[] arblQuote = {
3.9, //Burgenland
3.9, //Carinthia
3.6, //Lower_Austria
3.7, //Upper_Austria
2.9, //Salzburg
4.2, //Styria
2.8, //Tyrol
3.9, //Vorarlberg
7.3 //Vienna
};
//Grundfarbe der Visualisierung
int col=210;
void setup() {
size(900, 500);
//Vektorgrafik laden
austria = loadShape("Map_of_Austria.svg");
//Pfade der einzelnen Bundesländer extrahieren
bundesl = austria.getChildren();
//Formatierung des Originals deaktivieren
austria.disableStyle();
noLoop();
colorMode(HSB, 360, 100, 100);
textAlign(CENTER, CENTER);
rectMode(CENTER);
}
void draw() {
background(0, 0, 100);
stroke(col, 20, 99);
// Koordinatensystem speichern
pushMatrix();
translate(0, 30);
//Zeichnen der Bundesländer
for (int i=0; i<bundesl.length; i++) {
//Füllfarbe festlegen
fill(col, map(arblQuote[i],getMinValue(arblQuote),getMaxValue(arblQuote),20,100), 100);
//Zeichnen der Pfade
shape(bundesl[i], 0, 0);
println(bundesl[i].getName());
}
//Koordinatensystem repositionieren
popMatrix();
//Legende zeichnen
legende(10, 50, 2.8, 7.3);
text(source, width/2, height*19/20);
//Titel
textSize(20);
text(title, width/4, height*1/20);
}
void legende(int x, int y, float valMin, float valMax) {
pushMatrix();
translate(x+10, y+10);
fill(0, 0, 0);
text("Legende:", 30, 0);
translate(0, 25);
//Min und Max Werte für die Beschriftung finden
int minVal=floor(valMin);
int maxVal=ceil(valMax);
float step= (float) (maxVal-minVal)/5;
//Farbfelder und Beschriftungen zeichnen
for (int i =0; i<6; i++) {
fill(col, map(minVal+step*i,getMinValue(arblQuote),getMaxValue(arblQuote),20,100), 100);
rect (0, i*20, 20, 10);
String legValue = " %";
fill(0, 0, 0);
text( (float)round(((float) minVal+step*i) * 100 )/100+" %", 30, i*20);
}
popMatrix();
}
float getMaxValue ( float[] vals) {
float [] values= new float [vals.length];
arrayCopy(vals,values);
Arrays.sort(values);
return values[values.length-1];
float getMinValue ( float[] vals) {
float [] values= new float [vals.length];
arrayCopy(vals,values);
Arrays.sort(values);
return values[0];
}
Beschriftung:
Damit das Ganze einen echten Mehrwert gegenüber der konventionellen Erstellung in einem Grafikprogramm bietet, sollte das Programm die Grafik automatisch beschriften. Dafür müssen wir die in der original-.svg Datei englischsprachigen Titel durch deutschsprachige ersetzen.
Die Quoten und Namen der Bundesländer sollen in der Mitte der jeweiligen Pfade platziert werden. Dafür müssen wir die minimalen und maximalen x und y Koordinaten aller Punkte eines Pfades ermitteln. Dann zeichnen wir genau in die Mitte.
Starte Applet

Änderungen zum Beispiel vorher:
- Hintergrundfarbe geändert, damit die Beschriftung besser lesbar wird.
background(0, 0, 80);
- In draw() werden die Koordinaten der Beschriftungstexte ermittelt und dann gezeichnet.
<pre>//Zeichnen der Quoten
fill(360,0,100);
float [] coords = new float [2];
coords= getCoords(bundesl[i].getChild(0));
textSize(18);
text( (float)round(((float) arblQuote[i]) * 100 )/100+" %", coords[0],coords[1]);
- Funktion zur Ermittlung der Koordinaten.
float [] getCoords (PShape thisShape) {
float xMax=0;
float yMax=0;
float xMin=100000;
float yMin=100000;
float [] coords = new float [2];
//Ermitteln der maximalen und minimalen Pfad-Koordinaten
for (int i =0; i<thisShape.getVertexCount(); i++) {
if (thisShape.getVertexX(i)>xMax) xMax=thisShape.getVertexX(i);
if (thisShape.getVertexY(i)>yMax) yMax=thisShape.getVertexY(i);
if (thisShape.getVertexX(i)<xMin) xMin=thisShape.getVertexX(i);
if (thisShape.getVertexY(i)<yMin) yMin=thisShape.getVertexY(i);
}
coords[0]=(xMin+xMax)/2;
coords[1]=(yMin+yMax)/2;
return coords;
}
Interaktivität:
starte Applet

- Erweitern der Datenbasis
Damit in unserer Anwendung nun auch Entwicklungen sichtbar werden, verwende ich nicht nur die Daten aus dem Jahr 2010, sondern eine ganze Tabelle mit den Daten der Jahre 1995-2010, wie sie von Statistik Austriaveröffentlicht werden. Damit diese von Processing auf einfache Weise automatisch eingelesen werden können, habe ich eine .csv Tabelle der folgender Struktur erstellt:
- unnötige Spalten und Zeilen gelöscht
- die , durch . ersetzt
- die Bundesländer-Beschriftung von links nach rechts kopiert
- im Sketch Ordner als list.csv gespeichert
Download: list.csv
1995;1996;1997;1998;1999;2000;2001;2002;2003;2004;2005;2006;2007;2008;2009;2010;
3.8;4.2;4.3;3.4;3.6;3.2;4.1;4.3;4.2;5.6;6;5;3.7;3.6;4.6;3.9;Burgenland
3;2.9;3.4;3.5;3.5;3.1;3.2;2.7;3.4;4.6;4.8;4.4;3.9;3.4;4.2;3.9;Kärnten
3.4;3.8;3.8;4.4;3.3;3;3.2;3.6;3.5;4.2;4.3;4;3.6;3.4;4.3;3.6;Niederösterreich
3.2;3.7;3.5;3.5;3.5;3.1;2.9;3.1;3.3;3.7;4;3.2;3.2;2.6;4;3.7;Oberösterreich
2.7;3.2;3.2;3.4;2.7;2.3;1.9;2.8;2.2;3.7;3.2;3.1;3;2.5;3.2;2.9;Salzburg
3.5;4.1;4;3.8;3.2;3.2;3.7;3.8;4;3.7;4.1;3.9;3.7;3.4;4.6;4.2;Steiermark
2.9;3.2;3.4;2.9;2.5;2.5;2.3;2;2.6;3.3;3.5;2.9;2.8;2.4;2.9;2.8;Tirol
3.3;3.9;3.9;3.6;3.5;2.4;2.4;2.5;4.1;4.1;5.3;4.4;3.6;3.9;4.9;3.9;Vorarlberg
5.3;5.9;6.3;6.3;5.7;5.7;5.8;7.3;7.8;8.9;9.1;8.8;8.3;6.7;7.5;7.3;Wien
- Automatisches Einlesen der Daten aus einer .csv -Datei
Hier habe ich als Ausgansbasis ein Skript von che-wei wang verwendet: http://cwwang.com/2008/02/23/csv-import-for-processing/. Mit ein paar kleinen Modifikationen liest es auch in unserem Programm die .csv-Datei ein. Und speichert die Daten in einem 2-dimenstionalen Array.
- Ermitteln der minimalen und maximalen Werte
Das ist jetzt nicht mehr ganz so einfach, wie vorher, aber kein allzu großes Problem, das in setup() erledigt wird:
//Ermitteln der minimalen und maximalen Werte für die Farbwahl
for (int j=0; j<csv[0].length;j++) {
for (int i=0; i<arblQuote.length;i++) {
arblQuote[i]=parseFloat(csv[i+1][j]);
}
if (getMinValue(arblQuote)<minVal) minVal=getMinValue(arblQuote);
if (getMaxValue(arblQuote)>maxVal) maxVal=getMaxValue(arblQuote);
}
Damit werden dann in weiterer Folge unsere Werte mit konstanten Farbwerten über alle Jahre hinweg beschriftet.
- Übertragen der Jahreszahlen und des aktuell gewählten Jahres in entsprechende Variablen
//Auslesen der Jahre
years=new int[csv[0].length-1];
for (int i=0; i< csv[0].length-1;i++) {
years[i]=parseInt(csv[0][i]);
}
selYear=0;
- In draw(): Daten des aktuellen Jahres übertragen.
//Daten des aktiven Jahres laden
for (int i=0; i<arblQuote.length;i++) {
arblQuote[i]=parseFloat(csv[i+1][selYear]);
}
- Für jedes Bundesland den Namen anzeigen, wenn sich die Maus darüber befindet. (Funktioniert beim Bundesland Tirol nur bedingt!)
//Namen anzeigen
if (bundesl[i].getChild(0).contains(mouseX, mouseY)) {
fill(0, 0, 40);
textSize(14);
text(bundesl[i].getName(), coords[0], coords[1]+20);
}
- Interface, für die Auswahl der Jahre
int yearSelector (int [] years) {
noFill();
pushMatrix();
strokeWeight(1.5);
//Linie zeichnen
stroke(0, 70, 90);
line(width-5, 0, width-5, height);
strokeWeight(1);
//Beschriftung
translate(width-50, -10);
for (int i=0; i<years.length; i++) {
translate(0, height/years.length);
//Hervorheben des gewählten Jahres
if (years[i]==years[selYear]) {
fill(0, 70, 90);
triangle(35, 0, 45, -10, 45, 10);
textSize(24);
fill(360);
}
else {
textSize(12);
fill(0, 0, 60);
}
text(years[i], 0, 0);
}
popMatrix();
return selYear ;
}
- Mausaktivität abrufen um damit das gewünschte Jahr zu wählen
//Mausposition auswerten
void mouseMoved () {
if (mouseX > width-60 && mouseX<width) {
selYear=(int) map(mouseY, 0, height, 0, years.length);
}
}
Und diverse kleinere Modifikationen, z.B.: die Anpassung der Textpositionen an die Länge des Textinhalts usw. Den gesamten Quellcode findest du im Applet.
Gefällt mir Wird geladen …