Linux-Magazin-Logo Die Zeitschrift für Linux-Professionals

Datenreihen mit Tcl-Programmen visualisieren

Bildhafte Kurven

Carsten Zerbst

Das Sprichwort "Ein Bild sagt mehr als tausend Worte" gilt auch beim Anzeigen großer Datenmengen. Für die meisten Diagrammtypen genügen wenige Zeilen Tcl-Code, um Messwerte oder Ergebnisse auf dem Bildschirm grafisch ansprechend und übersichtlich darzustellen.

Nackte Zahlenkolonnen aus Berechnungen oder Messungen wirken unübersichtlich - ein Diagramm ist gefragt. Egal ob er die Antwortzeiten eines Webservers, die Lufttemperatur und -geschwindigkeit oder die Ergebnisse einer komplexen Simulation analysiert, erst ein Balken- oder Tortendiagramm oder ein x-y-Graph gibt dem Betrachter die gewünschte Übersicht. Mit Tcl/Tk haben Programmierer die Wahl zwischen mehreren Techniken, um diese Daten anzuzeigen. Selbst eigene Diagrammtypen sind leicht zu implementieren.

Das Canvas-Widget aus Tk eignet sich als robuste und leistungsfähige Basis für eigene Diagramme. Kluge Entwickler greifen dennoch auf vorhandenen Code zurück. Wer einen x-y-Graphen erzeugen muss, wird bei Steve Cassidys Emugraph-Paket[1] fündig. Es ist komplett in Tcl geschrieben und beschränkt sich auf eine einzige Datei: »graph.tcl« enthält alles Notwendige. Das Paket zeichnet vollständige Diagramme inklusive Achsenbeschriftung in ein Canvas-Widget.

Kurvendiagramme mit Emugraph

Das Programm in Listing 1 zeigt, wie einfach mit Emugraph eigene Diagramme erstellt sind. Der Code verwendet als Beispieldaten die seit dem Jahr 1701 aufgezeichneten Temperaturmessung aus Berlin Tempelhof, die Datenreihen enthalten für jeden Monat und jedes Jahr den Mittelwert. Das Ergebnis ist in Abbildung 1 zu sehen.

Listing 1: x-y-Diagramm mit Emugraph

01 #!/bin/sh
02 #\
03 exec wish $0 $@
04 
05 source emu-graph1.1.2/tcl/graph.tcl
06 
07 # Datensätze
08 set Januar [list 1702 2.0 1708 1.4 1730 1.8 1749 2.6 1760 -.8 1775 -.8 1800 -3.4 1820 -5.8 1840 -2.3 1860 2.0 1900 .9 1920 1.9 1950 -1.4 1970 -4.1 1990 4.1]
09 set April [list 1702 2.6 1708 6.1 1730 9.0 1749 8.0 1760 9.9 1775 7.6 1800 13.9 1820 10.3 1840 8.2 1860 7.9 1900 7.7 1920 10.8 1950 7.9 1970 6.4 1990 9.5]
10 set Juli [list 1702 16.0 1708 12.1 1730 16.8 1749 18.0 1760 19.5 1775 21.0 1800 16.2 1820 15.9 1840 18.8 1860 17.6 1900 20.8 1920 18.9 1950 18.4 1970 18.1 1990 18.1]
11 set Oktober [list 1702 7.5 1708 1.4 1730 5.0 1749 8.2 1760 10.5 1775 10.1 1800 8.0 1820 9.8 1840 9.9 1860 8.5 1900 10.0 1920 6.4 1950 8.4 1970 9.9 1990 10.8]
12 set Dezember [list 1702 .6 1708 -4.6 1730 1.0 1749 3.2 1760 4.9 1775 2.3 1800 -.4 1820 -2.8 1840 4.7 1860 -2.1 1900 3.4 1920 .0 1950 -1.0 1970 2.0 1990 1.2]
13 set Jahresmittel [list 1702 6.8 1708 6.2 1730 8.6 1749 9.2 1760 10.2 1775 10.3 1800 8.4 1820 7.9 1840 9.2 1860 8.4 1900 9.7 1920 9.1 1950 9.3 1970 8.8 1990 10.8]
14 
15 # Widgets erzeugen
16 canvas .c -width 600 -height 400 -bg white
17 pack .c
18 emu_graph::emu_graph graph -canvas .c -width 400 -height 300
19 
20 # Daten schreiben
21 graph data Januar   -points 1 -lines 1 -coords $Januar -colour red
22 graph data April    -points 1 -lines 1 -coords $April -colour yellow
23 graph data Juli     -points 1 -lines 1 -coords $Juli -colour green
24 graph data Oktober  -points 1 -lines 1 -coords $Oktober -colour cyan
25 graph data Dezember -points 1 -lines 1 -coords $Dezember -colour blue
26 graph data Jahresmittel  -lines 1 -coords $Jahresmittel -colour gray
27 
28 # Legende erstellen
29 set y 30
30 .c create text 500 [incr y 20] -text Januar -fill red
31 .c create text 500 [incr y 20] -text April -fill yellow
32 .c create text 500 [incr y 20] -text Juli -fill green
33 .c create text 500 [incr y 20] -text Oktober -fill cyan -tag Oktober
34 .c create text 500 [incr y 20] -text Dezember -fill blue
35 .c create text 500 [incr y 20] -text Jahresmittel -fill gray
36 
37 # Anzeige ändern
38 .c itemconfigure Januar -dash {2 4}
39 .c itemconfigure Jahresmittel -width 2
40 
41 # Werte in Canvas-Koordinaten umwandeln
42 set x1900 [graph x2canvas 1900]
43 set y5    [graph y2canvas 5]
44 .c create text $x1900 $y5 -text "\u00D7"
45 .c create text $x1900 $y5 -text "1900, 5\u00b0 cel." -anchor sw

Abbildung 1: Mit dem Emugraph-Paket von Steve Cassidy sind x-y-Diagramme schnell programmiert. Der Code für diese Kurven ist in Listing 1 zu sehen.

Nachdem die Daten definiert sind (Zeilen 8 bis 13) legt der Befehl »emu_graph::emu_graph« ein Diagrammobjekt an (Zeile 18). Das Kommando enthält neben dem Namen des Graphen »graph« auch noch ein Canvas-Widget, das die Daten anzeigen soll. Unter dem Graph-Namen steht nun ein neues Kommando zur Verfügung, das unter anderem die Datensätze entgegennimmt. Diese müssen als eine Liste vorliegen, in der sich x- und y-Werte abwechseln.

graph data Name -colour Farbe -coords Koordinaten

Dieser Aufruf übergibt die Daten an Emugraph. Um das Zeichnen der Kurven und der Umrandung kümmert sich das Paket, es skaliert die Daten auch sinnvoll. Der Kurvenname dient später zur Identifikation des Datensatzes im Canvas, er sollte also einmalig sein. Weitere Einträge wie eine Legende muss der Programmierer selbst implementieren. Um Platz für eine Legende zu schaffen, hat der Code in Zeile 18 das Emugraph-Feld kleiner angelegt als das Canvas-Widget in Zeile 16. Die Legende besteht aus Text und Linien in der gleichen Farbe wie die Daten (Zeile 29 bis 35).

Emugraph weist den Linien und Punkten den Datensatznamen als Tag zu, damit lassen sich jederzeit deren Attribute ändern. Zeile 38 weist der Januar-Kurve ein Strichmuster zu und Zeile 39 ändert die Strichstärke der Jahresmittelwerte. Das geschieht mit den normalen Canvas-Optionen, hier mit dem Linientyp und der Linienstärke.

Punkte hervorheben

Oft ist es erforderlich, einzelne Punkte in der Kurve hervorzuheben. Die Kommandos »x2canvas« und »y2canvas« helfen dabei, sie verwandeln die Koordinaten aus dem Datenmodell in die Canvas-Koordinaten. Im Beispiel wird der Wert 5 Grad Celsius im Jahr 1900 durch ein kleines Kreuz und den entsprechenden Text markiert (Zeile 42 bis 45). Die Kommandos »canvas2x« und »canvas2y« arbeiten genau umgekehrt. Mit ihrer Hilfe könnte das Programm die aktuelle Cursorposition in Jahres- und Temperaturwerte umrechnen und in einer Statuszeile ausgeben.

Da Emugraph auf dem Tk-Canvas basiert, ist es nicht nur zur Anzeige geeignet. Das Canvas bietet bereits den Export in das Postscript-Format an, Mats Bengtssons »can2svg«[2] gibt das Diagramm auch als SVG (Scalable Vector Graphics) aus. Hierzu sind nur die folgenden zwei Kommandos nötig:

source can2svg.tcl
can2svg::canvas2file .c test.svg

SVG wäre das ideale Format, um Diagramme im Web zu präsentieren. Leider unterstützen die aktuellen Browser SVG kaum, also sind Bitmaps gefragt. Auch hier hat Tcl eine Menge zu bieten. Wem die eingebauten Formate nicht genügen, der greift auf Jan Nijtmans IMG-Paket[3] zurück. Es unterstützt eine ganze Reihe von Formaten und erzeugt sogar Screenshots von Tk-Widgets[4].

Abbildung 2: Ein x-y-Diagramm lässt sich auch mit dem »graph«-Widget aus dem BLT-Paket erzeugen (Listing 2). BLT ist leistungsfähiger als Emugraph.

Viele Widgets dank BLT

Reichen die Fähigkeiten des Emugraph-Pakets, dann ist es als reine Tcl-Lösung erste Wahl. Die nur 800 Zeilen große Datei »graph.tcl« lässt sich direkt in die eigenen Quellen integrieren. Wer mehr braucht, wird beim BLT-Paket fündig. Diese kompilierte Erweiterung bringt unter anderem Widgets für x-y- und Balkendiagramme mit.

BLT ist fertig übersetzt in den meisten Linux-Distributionen enthalten. Wer lieber manuell installiert, findet die Quellen der aktuellen Version 2.4.z auf[5]. Dort liegt auch »slides.pdf«, die interessante Präsentation stellt viele BLT-Features vor. Neben den Diagrammen und Graphen enthält BLT einen Layout-Manager für Tabellen, ein Treeview- und ein Notebook-Widget, es unterstützt Drag & Drop und bringt eigene Datentypen mit: »vector« und »tree«.

Die BLT-Diagramme haben sehr viele Optionen, sie müssen den Vergleich mit Diagrammtools wie Grace[6] nicht scheuen. Das Listing 2 zeichnet ein x-y-Diagramm mit BLT und benutzt dabei einige Darstellungsoptionen. Nachdem es das »graph«-Widget erzeugt hat (Zeile 17), konfiguriert das Programm in Zeile 18 bis 20 die Abszisse (x), die Ordinate (y) und die Legende. Der Anzeigebereich der Ordinate ist in Zeile 19 fest vorgegeben. So bleibt etwas mehr Platz für die Legende, als wenn sich BLT selbst darum kümmern würde.

Listing 2: x-y-Diagramm mit BLT

01 #!/bin/sh
02 #\
03 exec wish $0 $@
04 
05 package require BLT
06 
07 # Datensätze
08 set Jahre [list 1702 1708 1730 1749 1760 1775 1800 1820 1840 1860 1900 1920 1950 1970 1990 ]
09 set Januar [list 2.0 1.4 1.8 2.6 -.8 -.8 -3.4 -5.8 -2.3 2.0 .9 1.9 -1.4 -4.1 4.1]
10 set April [list 2.6 6.1 9.0 8.0 9.9 7.6 13.9 10.3 8.2 7.9 7.7 10.8 7.9 6.4 9.5]
11 set Juli [list 16.0 12.1 16.8 18.0 19.5 21.0 16.2 15.9 18.8 17.6 20.8 18.9 18.4 18.1 18.1]
12 set Oktober [list 7.5 1.4 5.0 8.2 10.5 10.1 8.0 9.8 9.9 8.5 10.0 6.4 8.4 9.9 10.8]
13 set Dezember [list .6 -4.6 1.0 3.2 4.9 2.3 -.4 -2.8 4.7 -2.1 3.4 .0 -1.0 2.0 1.2]
14 set Jahresmittel [list 6.8 6.2 8.6 9.2 10.2 10.3 8.4 7.9 9.2 8.4 9.7 9.1 9.3 8.8 10.8]
15 
16 # Widgets erzeugen
17 blt::graph .graph -title "Temperaturen \u00ABBerlin Tempelhof\u00BB" -plotrelief flat -bg white
18 .graph axis configure x -title "Jahr"
19 .graph axis configure y -title "Temperatur \[\u00B0 Celsius\]" -min -10 -max +30
20 .graph legend configure -position @370,40 -relief flat -background white -raised 1
21 pack .graph
22 
23 # interaktives Zoomen
24 Blt_ZoomStack .graph
25 
26 # Werte hinzufügen
27 .graph element create Januar \
28     -xdata $Jahre -ydata $Januar \
29     -color red -dashes {4}
30 .graph element create April \
31     -xdata $Jahre -ydata $April \
32     -color yellow -symbol diamond
33 .graph element create Juli \
34     -xdata $Jahre -ydata $Juli \
35     -color green -pixels 2 -smooth natural
36 .graph element create Oktober \
37     -xdata $Jahre -ydata $Oktober \
38     -color  cyan -dashes {4}
39 .graph element create Dezember \
40     -xdata $Jahre -ydata $Dezember \
41     -color blue -dashes {8 4} \
42     -pixels 5  -symbol triangle
43 .graph element create Jahresmittel \
44     -xdata $Jahre -ydata $Jahresmittel \
45     -color gray80  -linewidth 2

Abbildung 3: BLT hat verschiedene Diagrammtypen im Repertoire. Für Balkendiagramme ist das »barchart«-Widget zuständig, siehe Listing 3.

Interaktiv zoomen

Der Aufruf »Blt_ZoomStack .graph« sorgt in Zeile 24 dafür, dass der Benutzer mit der linken Maustaste einen Bereich zum Zoomen aufziehen kann. Ein Klick mit der rechten Maustaste führt ihn zurück zum kompletten Diagramm.

Die Daten für das BLT-Graph-Widget sind anders aufgebaut als bei Emugraph: Während Letzterer die Daten als eine Liste von Wertepaaren erwartet, trennt BLT dies in zwei Listen, je eine pro Achse. Die Datensätze (Zeile 8 bis 14) fallen damit übersichtlicher aus, da sie die Stützpunkte auf der x-Achse nur einmal aufführen müssen (»Jahre«). Folgendes Kommando fügt eine Kurve in das Diagramm ein:

.graph element create Name -xdata x -ydata y

Wie in Listing 2 ab Zeile 27 zu sehen, stehen bei BLT viele Optionen für Farbe, Strichart und -stärke, Symbolart und -größe sowie Interpolation zur Auswahl. In Zeile 35 sorgt beispielsweise die Option »-smooth natural« für eine geglättete Juli-Kurve. Für die Optionen empfiehlt sich ein Blick in die Dokumentation oder in eines der vielen Beispiele. Letztere finden sich im »demos«-Unterverzeichnis von BLT. Suse legt dieses Verzeichnis in »/usr/lib/blt/demos« ab.

Balkendiagramme: Oft die bessere Variante

Nicht bei allen Datenquellen sind x-y-Diagramme die ideale Wahl, häufig passen Balkendiagramme besser. Listing 3 zeigt diese Variante mit Hilfe von BLT-Widgets, es verwendet »blt::bartchart«. Um einen Balken in das Diagramm einzufügen, ist folgendes Kommando nötig:

.balken element create Name -x x-Wert -y y-Wert

Listing 3: Balkendiagramm mit BLT

01 #!/bin/sh
02 #\
03 exec wish $0 $@
04 package require BLT
05 
06 # Widgets erzeugen
07 blt::barchart .balken
08 pack .balken
09 Blt_ZoomStack .balken
10 
11 # Achsen und Legende konfigurieren
12 .balken axis configure y -title "Mittelwert \[\u00B0 Celsius\]"
13 .balken axis configure x -title "Jahr" -stepsize 10
14 .balken legend configure -hide yes
15 
16 # Werte hinzufügen
17 set Jahresmittel [list 1970 8.8 red  1975 10.3 yellow  1980 8.3 green  1985 8.7 cyan  1990 10.8 blue  1992 10.5 magenta]
18 foreach {jahr wert farbe} $Jahresmittel {
19   .balken element create $jahr \
20     -x $jahr -y $wert -fg $farbe
21 }

Die weiteren Optionen sind identisch zum »blt::graph«-Widget. Beide Widgets können das erstellte Diagramm sowohl als Postscript wie auch als Bitmap exportieren. Mit dem »blt::vector«-Kommando (statt »list« in Zeile 17) wären übrigens auch riesige Datenmengen (über 10000 Punkte) problemlos handhabbar. E

Soll ein Graph viele Kurven enthalten, stellt sich schnell das Problem, ihnen eine geeignete Farbe zu geben. Oft kennt der Programmierer nicht die Zahl der Kurven, die seine Software gleichzeitig darstellen muss. Dennoch müssen die Farben möglichst unterschiedlich aussehen. Einige Lösungen dazu sind im Tclers Wiki aufgeführt[10].

Auf dieser Seite haben sich mehrere Tcl-Experten des Problems angenommen. Peter Lewerin berechnet mit seinem »distinctHueLabels« im HSV-Farbraum (Hue, Saturation, Value) die gewünschte Menge Stützpunkte und rechnet die Ergebnisse ins RGB-Modell um (Rot, Grün, Blau). John Droggitis veröffentlichte auf derselben Wiki-Seite eine optimierte Version.

Große Auswahl

Mit den beiden vorgestellten Erweiterung Emugraph und BLT lassen sich in eigenen Programmen Daten als x-y- oder Balkendiagramme darstellen. Es gibt aber noch weitere wichtige Diagrammtypen, die den Tcl-Programmierern nicht verwehrt sind. Arjen Markus möchte demnächst ein Diagrammpaket in Tklib integrieren, das auch Tortengrafiken, Polar- und einfache 3D-Diagramme darstellt[8]. Bis es so weit ist, kann man die Quellen direkt von Arjen erhalten.

Für Tortendiagramme bietet Jean-Luc Fontaine sein Tk-Piechart[7] an, siehe Abbildung 4. Es zeichnet 2D- und 3D-Tortendiagramme in einem Canvas-Widget. Wie bei Jean-Luc zu erwarten, ist dieses Widget mit der objektorientierten Tcl-Erweiterung Stooop programmiert (Simple Tcl Only Object Oriented Programming).

Abbildung 4: Ansprechende Tortendiagramme lassen sich mit Jean-Luc Fontaines Tk-Piechart erzeugen. Dieses Diagramm stammt aus den Demo-Skripten des Pakets.

Nicht immer ist der Griff zu fertigen Erweiterungen notwendig. In Abbildung 5 ist ein Diagramm der Leuchtdichteverteilung dargestellt. Solche Aufnahmen sind beim Messen von Scheinwerfern - etwa Fahrradlampen - üblich[9]. Diese Messung ist Teil einer Anwendung, die einen Aufbau mit zwei Steppermotoren und einem kalibrierten Photometer steuert. Das Diagramm wird mit weniger als 150 Zeilen Tcl erzeugt, hier ging das Schreiben schneller als die Suche nach einer fertigen Lösung. Das Skript ist in den Beispieldateien zu diesem Artikel enthalten[16]. (fjl)

Abbildung 5: Die Leuchtdichte-Verteilung einer Fahrradlampe mit den wesentlichen Messstellen für eine Beleuchtungsmessung. Für diese Grafik sind nur 150 Zeilen Tcl-Code nötig.

Abbildung 6: Im Tile-Projekt experimentiert Joe English mit Themes unter Tcl/Tk. Die Applikationen sollen moderner aussehen und besser zur jeweiligen Plattform passen.

Abbildung 7: Der Audioplayer Snackamp dient gleichzeitig als Web- und Shoutcast-Server. Hier ist der Inhalt dieser Fernsteuerfunktion in einem Browser zu sehen. Im Vordergrund läuft XMMS und spielt eine von Snackamp ausgestrahlte Datei.

Das Neueste

Peter Spjuth[11] ist vielen Tcl-Entwicklern als Autor des »LabeledFrame«-Widgets bekannt. Mit Nagelfar und Eskil bringt er jetzt einen Hauch nordische Mythologie in die Tcl-Welt. Hinter den mythischen Namen verbergen sich ein Codechecker und ein Diff-Tool.

Insbesondere der Codechecker Nagelfar ist sehr interessant. Er spürt sogar problematische Stellen im Skript auf, die syntaktisch korrekt sind. Beispielsweise warnt er vor vergessenen Dollarzeichen.

Hübsche Hüllen für Tcl/Tk-Programme

Joe English will mit seinem Tile-Paket[12] das Aussehen von Tk aufpolieren. Ähnlich wie Javas AWT basiert Tk auf Motif und fällt damit in der glitzernden Gnome/KDE/Windows-XP-Welt unangenehm auf. Tile dient als Spielwiese, um plattformübergreifendes Themeing für Tk zu erkunden (Abbildung 6).

Mit den Tclkits[15] verschnüren viele Tcl-Entwickler ihre Anwendungen mit den nötigen kompilierten Erweiterungen. Die Anwender freut's, sie können neue Programme sehr einfach ausprobieren - herunterladen und aufrufen genügt. Ein lohnendes Beispiel ist das neue Snackamp[13]. Mit diesem Audioplayer behält man dank des guten Medienmanagers auch in einer großen Anzahl an MP3- und Ogg-Vorbis-Dateien die Übersicht.

Tcl als Musik-Multitalent

Über seinen integrierten Webserver lässt sich Snackamp sogar von einem Browser fernsteuern. Außerdem arbeitet das Programm als Shoutcast-Server. Per Browser kann man einzelne Dateien oder ganze Playlisten anfordern und sie mit einer weiteren Snackamp-Instanz, mit XMMS oder einem ähnlichen Streaming-Client abspielen (Abbildung 7). Schneller und einfacher kommt keiner zu seinem privaten Shoutcast-Server.

Tclkits sind aber nicht die einzige Technik zum Verpacken von Tcl-Anwendungen. Dennis LaBelle stellt mit Freewrap 5.6[14] die neueste Version seines Wrappers vor. Damit lassen sich Tcl-Skripte und Bibliotheken schnell zu einem ausführbaren Programm schnüren.

Infos

[1] Emugraph: [http://emu.sourceforge.net/graph/emu_graph.html]

[2] Export eines Canvas-Widgets nach SVG: [http://hem.fyristorg.com/matben/download/can2svg.tcl]

[3] IMG-Paket: [http://sourceforge.net/projects/tkimg]

[4] Screenshots erstellen mit dem IMG-Paket: [http://mini.net/tcl/1404]

[5] BLT: [http://blt.sourceforge.net]

[6] Grace: [http://plasma-gate.weizmann.ac.il/Grace/]

[7] Tk-Piechart: [http://jfontain.free.fr]

[8] Arjen Markus: [http://mini.net/tcl/10878]

[9] Beleuchtungsmessung: [http://www.enhydralutris.de/Fahrrad/#beleuchtung]

[10] Farbwahl: [http://mini.net/tcl/666]

[11] Peter Spjuth: [http://spjuth.pointclark.net/Tcl.html]

[12] Tile: [http://tktable.sourceforge.net/tile/]

[13] Snackamp: [http://snackamp.sf.net]

[14] Freewrap: [http://freewrap.sf.net]

[15] Carsten Zerbst, "Sterngucker - Tcl-Module zu einer ausführbaren Datei verschnüren": Linux-Magazin 01/04, S. 100

[16] Listings zum Download: [ftp://ftp.linux-magazin.de/pub/magazin/2004/05/Feder-Lesen/]

Der Autor

Carsten Zerbst arbeitet bei Atlantec an einem PDM-System für den Schiffbau. Daneben beschäftigt er sich mit dem Einsatz von Tcl/Tk.