Ansatz zur automatischen Auswahl von Linienfarben in Diagrammen

Ein Problem bei der (automatischen) Erzeugung von Liniendiagrammen liegt in der Auswahl von unterscheidbaren Farben. In diesem Artikel wird ein Ansatz entwickelt, der dieses Problem lösen soll.

Ausgangspunkt ist zunächst der RGB-Farbraum. Um verschiedene Farben zu erzeugen, können einfach zufällige Farben aus dem RGB-Raum ausgewählt werden. Die folgende Darstellung zeigt eine derart getroffene Auswahl von zehn verschiedenen Linienfarben (rechtsklicken um neue Zufallsfarben zu erzeugen):

Die Nachteile dieses Ansatzes sind offensichtlich und sind vor allem auch Nachteile des Farbmodells. Selbst eine gleichverteilte Auswahl von Farben im RGB-Raum würde mitunter zu nahezu identischen Farben führen. Daher habe ich mich im Folgenden auf den HSL-Farbraum konzentriert. Wie alle wahrnehmungsorientierten Farbräume enthält auch der HSL-Raum die Dimension Farbwert – ein Wert zwischen 0° und 360° der den Farbton bestimmt. Die folgende Darstellung zeigt die Auswahl von 10 Farben mit gleichem Abstand im Farbraum (in diesem Fall 36°):

Wie man sieht bekommt man dadurch 10 Ausschnitte aus dem Regenbogenspektrum. Bei genauerem Hinsehen fallen aber immer noch Nachteile auf: So sind vor allem die beiden Grün- und Blautöne schwer voneinander zu unterscheiden. Um eine mögliche Ursache dafür zu nennen mache ich einen kurzen Ausflug zur Wahrnehmungspsychologie. Auf unserer Netzhaut befinden sich zwei Typen von Rezeptorzellen, die sog. Stäbchen und Zapfen. Während die Stäbchen vor allem zum Sehen in der Dämmerung benutzt werden, dienen Zapfen zum Farbsehen. Nun gibt es unter den Zapfen-Zellen wiederum drei verschiedene Typen, wovon jeder zur Wahrnehmung bestimmter Farbfrequenzen geeignet ist. Um die Sache kurz zu machen, es gibt jeweils einen Zapfentyp für rote, grüne und blaue Farbfrequenzen. Und jetzt kommts: die Verteilung der Zapfenzellen ist in etwa 10:1:1 (rot zu grün zu blau). Daher fällt es Menschen naturgemäß leichter, Rottöne voneinander zu unterscheiden als Blau- oder Grüntöne.

Ich habe versucht, diesen Umstand über eine Transferfunktion für die Farbtöne auszugleichen. Die folgende Abbildung zeigt oben einen Farbwertverlauf ohne und unten mit Korrektur. Wie man sehen kann, habe ich einfach den Bereich für grüne und blaue Farbtöne “zusammengedrückt”, um mehr Spielraum zwischen Rot und Gelb zu bekommen.

oben: normaler HSL-Verlauf, unten: HSL-Verlauf mit Farbtonkorrektur

oben: normaler HSL-Verlauf, unten: HSL-Verlauf mit Farbtonkorrektur

Wählt man die 10 Zufallsfarben nun aus diesem, korrigierten Spektrum, erhält man folgendes Resultat:

Die Farbtonkorrektur hat etwas zur Unterscheidbarkeit der grünen und blauen Linien beigetragen. Für den günstigen Fall, das die Linienhelligkeit keine weitere Bedeutung in der Visualisierung hat, kann man die Unterscheidbarkeit der Linien weiter steigern, indem man abwechselnd helle und dunkle Linien verwendet:

Zur Erzeugung der Abbildungen habe ich die ActionScript-Klasse PerceptualColor verwendet. Die Farbwertkorrektur wird über die folgende Klasse HueCorrection gelöst. Ein- und Ausgabe für die Funktion correctHue ist ein Farbwinkel zwischen 0 und 360°.

public class HueCorrection
{
	private static var _tf:Array = [
		[10,5], [30,45], [50,70],
		[70,94], [110,100], [125,115],
		[145,148],[161,174], [182,179],
		[188,185],
		[210,225], [250,255]
	];
 
	public static function correctHue(hue:Number):Number {
		var h:uint = hue / 360 * 255;
		var new_hue:Number;
		var lx:Number = 0;
		var ly:Number = 0;
 
		for (var i:uint=0; i<_tf.length; i++) {
			if (h == _tf[i][1]) {
				new_hue = _tf[i][0];
				break;
			} else if (h < _tf[i][1]) {
				new_hue = lx + ((_tf[i][0] - lx) / (_tf[i][1] - ly)) * (h - ly);
				break;
			}
			lx = _tf[i][0];
			ly = _tf[i][1];
		}
		return new_hue / 255 * 360;
	}
}

Visualisierung von Easing-Funktionen

Easing-Funktionen werden verwendet, um sanftere Bewegungsabläufe in Tweens zu erzeugen1. Die Funktionen berechnen in Abhängigkeit von der verstrichenen Zeit t, dem Startwert s, der gewünschten Wertänderung c und der Gesamtdauer der Animation d einen neuen Wert für den Ort eines Objektes. Natürlich können Easing-Funktionen auch für alle ander Arten von zeitlichen Wertänderungen benutzt werden, wie beispielsweise zur Rotation von Objekten oder zur Änderung einer Lautstärke.

function easing(t:Number, s:Number, c:Number, d:Number):Number {
	// calculate new value
	return value;
}

Rober Penner hat eine ganze Reihe von Easing-Funktionen gesammelt, die mitlerweile in vielen Animations-Frameworks für ActionScript oder JavaScript integriert sind.

Natürlich sind Beispielanimationen gut geeignet, um dazu finden sich auch schon ausführliche Beispiele im Internet. Ein anderer Weg zur Visualisierung von Easing-Funktionen ist die einfache Darstellung in einem Funktionsgraph.

Dazu gibt es unter janitor61.com eine schöne Übersicht der Funktionsgraphen im PDF-Format:

Quelle: http://www.janitor61.com/?p=24

Quelle: http://www.janitor61.com/?p=24

Bei der näheren Betrachtung dieser Darstellung haben mich folgende Punkte gestört:

  1. Da sowohl die Achsen als auch die Funktionsgraphen in schwarz gezeichnet wurden, kann man sie schwer auseinanderhalten. So geht beispielsweise aus der Abbildung der Funktion Circ.easeOut nicht hervor, wo der Funktionsgraph endet.
  2. Die Graphen können nur schwer miteinander verglichen werden, da die einzelnen Typen (easeIn, easeOut, easeInOut) in der Darstellung nicht über- oder nebeneinander stehen.
  3. Die vollständige Umrahmung der Koordinatensysteme (aka. “Chart Junk”2) stört bei der Betrachtung der Diagramme.

Die folgende Visualisierung verbessert die angesprochenen Punkte:

verbesserte Visualisierung

verbesserte Visualisierung

Die Darstellung wurde in ActionScript3 erzeugt, daher gibt soll an dieser Stelle auch auf die interaktive Version verwiesen werden.