Tcl/Tk-Benutzeroberflächen für gnuplot programmieren
Aus BraLUG-Wiki
Inhaltsverzeichnis |
Motivation
Wenn man aufgezeichnete Messreihen in Diagrammen visualisieren möchte, gibt es viele Möglichkeiten dies zu tun. Zum einen kann man mit der Programmiersprache seiner Wahl versuchen das Zeichnen der Kurven von Hand zu programmieren bzw. nutzt eine der vielleicht vorhandenen Bibliotheken. Im Fall von Tcl/Tk wird man dabei z.B. mit den Paketen Diagrams und plotchart fündig.
Aber warum so kompliziert? Auch mit den erwähnten Bibliotheken wird das Zeichnen von Diagrammen kein Kinderspiel, weil trotzdem noch erheblich viel Code geschrieben muss, um ein zufriedenstellendes Ergebnis zu erzielen. Schaut man sich die Dokumentation von gnuplot an, fragt sich der Tcl-Programmierer, warum es dort den Ausgabetyp "Tkcanvas" gibt, der Name suggeriert, es muss irgendetwas mit Tcl/Tk zu tun haben...
Stimmt, dem ist wirklich so! Die Ausgabe des Plot-Ergebnisses wird in Form von Tcl-Sourcecode generiert, welcher sämtliche Canvas-Widget-Befehle zum Zeichnen des Diagrammes enthält. Dieser Sourcecode muss dann eigentlich nur noch in der eigenen Applikation eingebunden/aufgerufen werden. In der Folge soll hier das Grundprinzip kurz beschrieben werden.
gnuplot-Eingabe/-Parametrisierung
Erster Schritt ist natürlich gnuplot anzuweisen, was überhaupt gezeichnet werden soll. Da gnuplot eine eigene Shell besitzt, über die man Parameter einstellen und Kommandos absetzen kann, kommt ein weitere Mechanismus von Tcl zum tragen: das Öffnen einer Pipe zu gnuplot, über die man einfach lesend und schreibend zugreifen kann:
set pid [open "| gnuplot" "w"] puts $pid "set ytics $gvar(ytics)" puts $pid "set xdata time" puts $pid "set timefmt '%Y-%m-%dT%H:%M:%S'" puts $pid "set format x '%H.%M\\n%d.%m'" puts $pid "set autoscale y" puts $pid "set autoscale x" puts $pid "set xrange \['$gvar(xmin)':'$gvar(xmax)'\]" puts $pid "set yrange \[$gvar(ymin):$gvar(ymax)\]" puts $pid "set xlabel 'Zeit'" puts $pid "set ylabel 'Temperatur'" puts $pid "set datafile separator '|'" puts $pid "set grid ytics xtics" puts $pid "set terminal tkcanvas size $gvar(dx),$gvar(dy)" puts $pid "set output 'canvas.tk'" puts $pid "plot \"< sqlite3 temperatur '$gvar(sql)'\" using 1:2 index 0 title 'Sensor 1' with lines" close $pid
Es wird also die Pipe mit dem Tcl-Befehl open schreibend geöffnet. Als Ergebnis bekommt man einen Filedeskriptor zurück, welcher in der Variablen pid gespeichert wird. Über diesen Deskriptor erfolgen dann die ganz normale Ausgaben (Tcl-Befehl puts), welche über die Pipe zu gnuplot gesendet werden. Im obigen Code-Fragment sieht man auch, dass die Ausgaben mit einigen Variablen gespickt sind ($gvar(...)), welche an anderen Stellen des Tcl-Programmes (z.B. in einem kleinen Parameter-Dialog) gesetzt werden.
Entscheidend für die Ausgabe des Plots, in Form von wiederverwerdbaren Tcl-Code, sind die beiden folgenden Zeilen:
puts $pid "set terminal tkcanvas size $gvar(dx),$gvar(dy)" puts $pid "set output 'canvas.tk'"
Es wird also der Terminaltyp "Tkcanvas" gesetzt und die Ausgabedatei lautet canvas.tk, welche später noch benötigt wird.
Das Bereitstellen der Daten für das Diagramm erfolgt in dieser Zeile:
puts $pid "plot \"< sqlite3 temperatur '$gvar(sql)'\" using 1:2 index 0 title 'Sensor 1' with lines"
In diesem Beipiel handelt es sich um eine sqlite-Datenbank (temperatur). Die SQL-Anweisung zum Auslesen der Daten steht in der Variable $gvar(sql). Die Ausgabe von sqlite wird direkt an den gnuplot-Befehl plot, erweitert um einige weitere Parameter (using, index, title etc.), angehangen.
Also wie man sieht, schon mal recht einfach und elegant lösbar.
gnuplot-Ausgabe
Jetzt kommt der spannendste und einfachste Teil: die Integration der Plot-Ausgabe im eigenen Tcl-Programm. Wie oben schon beschrieben, wird gnuplot durch die Angabe des Ausgabetyps "Tkcanvas" dazu veranlasst, sämtliche Elemente des Diagrammes als Canvas-Elemente zu generieren und in einer Datei (hier canvas.tk) abzuspeichern.
Die Einbindung dieser Datei in der Tcl-Applikation erfolgt wie folgt:
canvas .g -width $gvar(dx) -height $gvar(dy) -bg white pack .g -in .top ... source canvas.tk exec rm canvas.tk gnuplot .g
Es wird also ein Canvas-Widget (.g) als Container, der das Diagramm später aufnehmen soll, definiert und in der eigenen Programmoberfläche entsprechend angezeigt (Tcl-Befehl pack). Danach wird die Datei canvas.tk mit dem Tcl-Befehl "source" gelesen und ausgeführt (im obigen Beispiel wird die Datei gleich wieder gelöscht, da sie in der Folge nicht mehr benötigt wird). In dem eingezogenen Script-Fragment von gnuplot ist u.a. auch eine Prozedure "gnuplot" definiert, welche im Prinzip die pack-Anweisungen für sämtliche Diagramm-Elemente enthält. Diese Prozedur muss in der eigenen Anwendung aufgerufen werden, einziges Übergabeparameter ist die Bezeichnung des vorher definierten Canvas-Widgets, in dem gezeichnet werden soll (hier .g).
Tja, das war es, das Diagramm ist gezeichnet! Die gnuplot-Entwickler müssen ein Herz für Tcl-Programmierer gehabt haben...
Beispiel