JMSL Erste Schritte:

Visualisierung mit Chart


Das JMSL Package Chart dient zur Erstellung von Graphiken (charts :), und deren Ausgabe auf dem Bildschirm, in eine Datei, oder auf einem Drucker. Wir werden uns hier auf das "Plotten" von Funktionen und diskreter Daten beschränken. Im weiteren betrachten wir anhand eines Beispiels, wie man Graphen von Funktionen und einzelne Punkte (Daten) in einem Fenster ausgeben kann.

Vorbereitung (allgemein):
Als allererstes betrachten wir den Aufbau eines solchen Diagramm. Es ist nach einem "Baum-Prinzip" strukturiert, und lässt sich wie folgt darstellen:
Wir betrachten an dieser Stelle natürlich nur den für uns interessanten Teil des gesamten Baumes, der vollständige Baum lässt sich in der entsprechenden API-Dokumentation finden.

Die Knoten des oben abgebildeten Baumes sind Java-Objekte. Die Wurzel (root) eines solchen Diagramm ist immer das Objekt chart, an den dann alle anderen Objekte (Knoten) "angehängt" werden.
Nun betrachten wir die Knoten einzeln an einem Beispiel. Als erstes wollen wir uns die Punkte (-3,4), (0,2) und (6,7) in einem Koordinatensystem anzeigen lassen. Dazu erstellen wir eine Java-Klasse "MyChartBoard", die wie folgt aussieht:


Gehen wir nun den Quelltext Zeile für Zeile durch:
  • Zeile 1 und 2: Hier werden die benötigten Packages eingebunden: java.awt wird für die Fensterdarstellung benötigt, und natürlich die com.imsl.chart selbst;
  • Zeile 4: Das ist die Deklarationszeile der Klasse. Das Besondere an dieser Zeile ist, dass mit extends JFrameChart angegeben wird, dass unsere neue Klasse von der Klasse JFrameChart abgeleitet wird, und somit die Eigenschaften von ihr erbt;
  • Zeile 7 bis 9: Hier wird der Konstruktor unserer Klasse deklariert. Mit super(); wird an dieser Stelle angegeben, dass als erstes der Konstruktor der Elternklasse aufgerufen werden soll;
  • Zeile 12 bis 13: Die main-methode unserer Klasse, die nichts anderes macht, als eine Instanz der Klasse MyChartBoard zu erstellen, d.h. es wird der Konstruktor aufgerufen;

Vorbereitung (chart):
Jetzt haben wir also einen "Rahmen" geschaffen in dem wir nun unseren "Baum" aufbauen wollen: und zwar brauchen wir als ersten den Wurzelknoten, d.h. ein Objekt der Klasse Chart. Dieses erstellen wir aber nicht neu, weil es schon von dem Konstruktor der Elternklasse erstellt wurde. Wir brauchen es also nur anzufordern, und zwar mit getChart(). Am Beispiel sieht das dann wie folgt aus:


  • Zeile 9: Mit dem Aufruf setSize(int Breite, int Hoehe) setzen wir die Größe des anzuzeigenden Fensters;
  • Zeile 10: Wie schon erwähnt, sieht man hier, dass eine neue Variable MyChart deklariert wird, die auf das Chart-Objekt verweist, das bereits vorhanden ist (von dem Konstruktor der Elterklasse erzeugt).
  • Zeile 12 Hier erzeugen wir ein neues Objekt der Klasse AxisXY (vgl. Diagramm), das gleichzeiting an das Chart angehängt wird, indem wir in dem Konstruktoraufruf AxisXY( MyChart ); darauf verweisen;
  • Zeile 15 Der Aufruf show(); bewirkt, dass das Anzeigefenster samt Inhalt nach der Konstruktion angezeigt wird;
Um das Ganze etwas näher zu erklären: ein Chart-Objekt ist so etwas wie eine "Zeichenfläche", mit der wir zunächst folgende Sachen machen können/wollen:
  • in ihr zeichnen
  • sie in einem Fenster anzeigen
  • ihre Größe setzen (verändern)
Das ist aber noch nicht alles. Wir hatten noch einen AxisXY-Objekt erzeugt: das ist aber nicht anderes, als ein Karthesisches Koordinatensystem, das in MyChart eingezeichnet wird, weil wir es dort angebunden haben.

Jetzt sollte alles da sein, um den ersten Versuch durchzuführen: das Programm sollte fehlerfrei kompilierbar sein (sonst den Quelltext nochmal vergleichen ;), und beim Aufrufen sieht das Ergebniss dann so aus: MyChartBoard

Bem. (Chart-Fenster): der Package Chart sorgt dafür, dass ein Ausgabefenster erzeugt wird, das bereits eine "Zeichenfläche", und eine Menüleiste beinhaltet. Die Menüleiste enthält unter anderem das Menue "File", mit sehr nützlichen Funktionen:
  • "Save as.." (speichern unter): erlaubt die erzeugte Grafik in einer Datei, im PNG-Format abzuspeichern;
  • "Print" (drucken): ermöglicht das Ausdrucken der erzeugten Grafik auf einem Drucker :)

Diskrete Punkte:
Nun haben wir es fast geschafft. Wir haben also eine Zeichenfläche, mit einem Koordinatensystem, wo wir unsere Punkte einzeichnen können. Dazu müssen aber erst ein paar Dinge geklärt werden: wenn man sich das Diagramm von oben anschaut, so sieht man, dass wir an ein AxisXY Objekt der Klasse Data (und nur solche) anhängen können. Falls wir also etwas einzeichnen wollen, müssen wir erst daraus einen Data-Objekt erzeugen. Dazu stellt die Klasse Data verschiedene Konstruktoren zur Verfügung, wir betrachten hier die zwei wichtigsten:
  • Data(ChartNode parent, double[] x, double[] y)
  • Data(ChartNode parent, ChartFunction cf, double a, double b)
Bem.: Ein Objekt der Klasse ChartNode (oder einer abgeleiteten Klasse) kann als Knoten (vgl. Diagramm) ein Chart, oder ein anderes ChartNode "angehängt" werden, z.B. die Klassen AxisXY und Data werden von ChartNode abgeleitet.


Um unsere Punkte darzustellen verwenden wir den ersten Konstruktor. Dieser erzeugt einen Data-Objekt in dem das Array y gegen das Array x geplottet wird. Dabei ist das Array x ein Datenfeld, das Punkte der x-Achse beinhaltet, und das Array y beinhaltet die entsprechenden Funktionswerte (also Werte auf der y-Achse).
Bem.: beide Arrays müssen natürlich gleichlang sein!


Wir müssen unseren Quelltext wie folgt erweitern:


  • Zeile 16 und 18: Die double Arrays x und y enthalten die x- bzw. y-Koordinaten der Punkte die wir plotten wollen;
  • Zeile 20: Hier wird aus den Arrays x und y ein Objekt der Klasse Data erzeugt, und an MyAxis angehängt;
Nach dem erfolgreichem Kompilieren, und Ausführen sollte das Ergebnis wie folgt aussehen: MyChartBoard

Bem.: Die Verbindungslinien zwischen den Punkten werden standardmäßig eingezeichnet. Mit dem Aufruf der Methode setDataType(int value) lassen sich aber auch andere Darstellungarten wählen.


Plotten einer Funktion
Als letztes Thema in diesem Tutorium lernen wir, wie man mit Chart eine Funktion plotten kann. Das ganze betrachten wir wiederum anhand einer Beispielfunktion...sagen wir Sinus ... Auch hier müssen wir erst einen Data-Objekt erzeugen, aber wie schon erwähnt, müssen wir hier einen anderen Konstruktor verwenden als für diskrete Punkte, nämlich
  • Data(ChartNode parent, ChartFunction cf, double a, double b)
Anders als bei dem Konstruktor für diskrete Punkte müssen wir mit ChartFunction cf die zu plottende Funktion übergeben, die dann über dem Intervall [a,b] geplottet wird.

ChartFunction ist ein Interface mit nur einer Methode f(double x). Diese Methode muss den Wert der zu plottenden Funktion zurückliefern.
Wir definieren also innerhalb unserer Klasse eine neue Klasse MyFunction, die wie folgt aussieht:


Wie wir sehen, ist es eine einfache innere Klasse, die das Interface ChartFunction implementiert (Zeile 1). Das einzige, was die Klasse MyFunction beinhaltet ist die Methode f(double x) (Zeile 2 bis 4), die als Rückgabewert zu dem Parameter x gerade tan(x) zurückliefert. Diese Methode überschreibt die gleichnamige Methode des Interface ChartFunction, somit kann ein Data-Objekt auf unsere Funktion zugreifen.

Nun wollen wir das Ganze in unser Programm einbauen:


  • Zeile 38 bis 42: An dieser Stelle wurde nur die Deklaration der Klasse MyFunction, die eben beschrieben wurde, eingefügt;
  • Zeile 24: Hier erzeugen wir ein Objekt der Klasse MyFunction
  • Zeile 26: Hier wird aus dem MyFunction-Objekt Sin und den Grenzen -6 und 6 ein Objekt der Klasse Data erzeugt, und an MyAxis angehängt;
Im Prinzip ist also die Vorgehensweise genauso wie beim Plotten diskreter Daten.

Nach dem Kompilieren, sollte das Programm beim Ausführen folgendes Ergebnis liefern: MyChartBoard

Zusatz: (Legende)
Will man mehrere Graphen gleichzeitig in einem Fenster darstellen, so kann es schnell unübersichtlich werden, weil standartmäßig wird alles einheitlich schwarz, und ohne Beschriftung dargestellt.

Die Klasse Data stellt für die Farbveränderung die Methode setLineColor(Color c) bereit. Wir wollen aber nicht nur die Graphen farblich kennzeichnen, sondern auch eine Legende erzeugen, wo die Graphen auch beschriftet sind ;)
Das geht fast genau so einfach, wie mit Farbe: für die Beschriftung eines Graphen ist die Methode setTitle(String txt) der Klasse Data verantwortlich.

Eingebaut in unseren Beispiel sieht das dann wie folgt aus:


  • Zeile 26 und 35: Hier wird jeweils die Farbe der Graphen gesetzt. Zu beachten ist an dieser Stelle, dass als Parameter hier ein Objekt der Klasse Color übergeben werden muss. Diese Klasse befindet sich in dem Package java.awt. Um die Klasse Color benutzen zu können müssen wir also java.awt importieren, (vgl. Zeile 1).
  • Zeile 24 und 33: Hier setzen wir die Beschriftung der Graphen, die in der Legende erscheinen soll ("\n" bedeutet Zeilenumbruch);
  • Zeile 38: Analog zu Chart wurde von der Super-/Eltern-Klasse ein Objekt der Klasse Legend schon angelegt, und beinhaltet bereits die Beschriftungen, sowie die Farbmarkierungen der Graphen. In dieser Zeile wird also lediglich, mit MyChart.getLegend() ein Verweis auf sie geholt, und der Aufruf der Methode setPaint(true) bewirkt, dass die Legende gezeichnet wird.
Sollte nun das ganze kompilierbar sein ;) , so wird beim Aufruf folgendes Ergebniss erzeugt: MyChartBoard

...na, das kann sich doch sehen lassen, oder?!! ;)

Letzter änderung am 18.10.04 durch Heinrich Mellmann @Mail: mellmann@mathematik.hu-berlin.de