Visualisierung von Daten
Das Sprichwort „Ein Bild sagt mehr als tausend Worte“ beschreibt das Ziel der Datenvisualisierung treffend. Die Datenvisualisierung zielt darauf ab, Informationen in einer prägnanten, aber verständlichen Form darzustellen. Visualisierungen können wichtige Punkte hervorheben und den Nutzenden nützliche Informationen liefern, wie z. B. Zusammenfassungen von Daten.
Das Bild unten zeigt eine Anwendung, die es ermöglicht, Statistiken über Radfahrende anzuzeigen. Die verwendeten Statistiken stammen aus dem Datensatz der Stadtplanungsbehörde Helsinki (CC-BY), den Sie unter https://www.avoindata.fi/data/en/dataset/helsingin-pyorailijamaarat finden.

Beim Vergleich der im Bild gezeigten Statistiken mit dem Dateiformat – unten sind einige Zeilen als Beispiel aufgeführt – werden die Vorteile deutlich. Im ursprünglichen Datensatz werden die Werte stündlich präsentiert, während für die Visualisierung monatliche Zusammenfassungen erstellt wurden. Der Originaldatensatz enthält auch alle Beobachtungsorte, während in der Visualisierung der Nutzende einen bestimmten Punkt auswählen kann.
Päivämäärä;Huopalahti (asema);Kaisaniemi;Kulosaaren silta et.;... ke 1 tammi 2014 00:00;;1;;;;;;2;5;3;;11;;;7;8 ke 1 tammi 2014 01:00;;3;;;;;;6;5;1;;8;;;5;4 ke 1 tammi 2014 02:00;;3;;;;;;1;1;1;;14;;;2;11 ke 1 tammi 2014 03:00;;2;;;;;;0;2;0;;7;;;5;3 ...
Daten im oben gezeigten Format können zeilenweise als Strings verarbeitet werden. Die Zeilen werden in Stücke aufgeteilt, die mit einer Listenstruktur verarbeitet werden können. Eine Möglichkeit, dies zu tun, ist die folgende:
String row = "Päivämäärä;Huopalahti (asema);Kaisaniemi;Kulosaaren silta et.;..."
String[] pieces = row.split(";");
for (int i = 0; i < pieces.length; i++) {
System.out.println(i + ": " + pieces[i]);
}
Wir werden uns einige Muster der Datenvisualisierung ansehen und eine Technik kennenlernen, um sich verändernde Daten zu visualisieren.
Diagramme
Java bietet viele vorgefertigte Klassen zum Zeichnen verschiedener Diagrammtypen an. Zu den Diagrammtypen gehören unter anderem Flächendiagramme, Balkendiagramme und Liniendiagramme.
Als nächstes werfen wir einen Blick auf die Verwendung sowohl eines Liniendiagramms als auch eines Balkendiagramms. Es könnte sich lohnen, auch einen Blick in Oracles (zum Teil veraltete) Anleitung zum Thema zu werfen, die Sie hier finden: https://docs.oracle.com/javafx/2/charts/jfxpub-charts.htm.
Liniendiagramm
Liniendiagramme können verwendet werden, um Veränderungen im Laufe der Zeit darzustellen. Die Daten werden als Linie dargestellt, die Punkte in einem zweidimensionalen Koordinatensystem verbindet, wobei die x-Achse die Zeit und die y-Achse den Wert der Variablen zu jedem Zeitpunkt darstellt. Ein Liniendiagramm kann auch mehrere verschiedene Variablen enthalten.
Schauen wir uns die Anwendung eines Liniendiagramms auf reale Daten an. Statistics Finland bietet Daten zu den Gesamtstimmen und dem relativen Stimmenanteil bei den finnischen Kommunalwahlen in den Jahren 1968-2008 an. Die Originaldaten finden Sie hier: https://tilastokeskus.fi/til/kvaa/2008/kvaa_2008_2010-07-30_tau_002.html. Einige Datenpunkte wurden zur Visualisierung entnommen – hier konzentrieren wir uns auf den relativen Stimmenanteil. Unsere Daten verwenden Tabulatoren zur Trennung (d. h. das Zeichen '\t').
Party 1968 1972 1976 1980 1984 1988 1992 1996 2000 2004 2008 KOK 16.1 18.1 20.9 22.9 23.0 22.9 19.1 21.6 20.8 21.8 23.4 SDP 23.9 27.1 24.8 25.5 24.7 25.2 27.1 24.5 23.0 24.1 21.2 KESK 18.9 18.0 18.4 18.7 20.2 21.1 19.2 21.8 23.8 22.8 20.1 VIHR - - - - 2.8 2.3 6.9 6.3 7.7 7.4 8.9 VAS 16.9 17.5 18.5 16.6 13.1 12.6 11.7 10.4 9.9 9.6 8.8 PS 7.3 5.0 2.1 3.0 5.3 3.6 2.4 0.9 0.7 0.9 5.4 RKP 5.6 5.2 4.7 4.7 5.1 5.3 5.0 5.4 5.1 5.2 4.7
Es ist möglich, eine der oben gezeigten Zeilen folgendermaßen zu teilen:
String row = "Party 1968 1972 1976 1980 1984 1988"
List<String> pieces = Arrays.asList(row.split("\t"));
for (int i = 0; i < pieces.size(); i++) {
System.out.println(i + ": " + pieces.get(i));
}
0: Party 1: 1968 2: 1972 3: 1976 4: 1980 5: 1984 6: 1988
Die Verwendung eines Liniendiagramms erfordert, dass wir die Achsen des Koordinatensystems definieren, das Liniendiagramm, das diese Achsen verwendet, erstellen und die Daten in das Liniendiagramm einfügen. Unsere erste Konzeptualisierung der Anwendung sieht wie folgt aus. Das Programm versucht, die Unterstützung der Partei RKP in den Jahren 1968-2008 zu visualisieren.
@Override
public void start(Stage stage) {
// create the x and y axes that the chart is going to use
NumberAxis xAxis = new NumberAxis();
NumberAxis yAxis = new NumberAxis();
// set the titles for the axes
xAxis.setLabel("Year");
yAxis.setLabel("Relative support (%)");
// create the line chart. The values of the chart are given as numbers
// and it uses the axes we created earlier
LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
lineChart.setTitle("Relative support in the years 1968-2008");
// create the data set that is going to be added to the line chart
XYChart.Series rkpData = new XYChart.Series();
rkpData.setName("RKP");
// and single points into the data set
rkpData.getData().add(new XYChart.Data(1968, 5.6));
rkpData.getData().add(new XYChart.Data(1972, 5.2));
rkpData.getData().add(new XYChart.Data(1976, 4.7));
rkpData.getData().add(new XYChart.Data(1980, 4.7));
rkpData.getData().add(new XYChart.Data(1984, 5.1));
rkpData.getData().add(new XYChart.Data(1988, 5.3));
rkpData.getData().add(new XYChart.Data(1992, 5.0));
rkpData.getData().add(new XYChart.Data(1996, 5.4));
rkpData.getData().add(new XYChart.Data(2000, 5.1));
rkpData.getData().add(new XYChart.Data(2004, 5.2));
rkpData.getData().add(new XYChart.Data(2008, 4.7));
// add the data set to the line chart
lineChart.getData().add(rkpData);
// display the line chart
Scene view = new Scene(lineChart, 640, 480);
stage.setScene(view);
stage.show();
}
Wenn wir das Programm starten, stellen wir einige Probleme fest (versuchen Sie es auszuführen und sehen Sie sich die Daten an). Die Klasse, die wir zur Erstellung der Achsen verwendet haben, NumberAxis, bietet auch einen anderen Konstruktor an. Sie können die unteren und oberen Grenzen sowie die Anzahl der Schritte zwischen ihnen als Parameter an den Konstruktor übergeben. Setzen wir die untere Grenze auf 1968, die obere Grenze auf 2008 und die Anzahl der Schritte auf 4.
@Override
public void start(Stage stage) {
// create the x and y axis
NumberAxis xAxis= new NumberAxis(1968, 2008, 4);
// .. der restliche Code bleibt gleich
Das Hinzufügen der Unterstützungszahlen einer weiteren Partei kann auf ähnliche Weise im Programm erfolgen. Im folgenden Beispiel fügen wir die Partei VIHR zum Diagramm hinzu – die Partei ist seit 1984 aktiv.
@Override
public void start(Stage stage) {
// create the x and y axes that the chart is going to use
NumberAxis xAxis = new NumberAxis();
NumberAxis yAxis = new NumberAxis();
// set the titles for the axes
xAxis.setLabel("Year");
yAxis.setLabel("Relative support (%)");
// create the line chart. The values of the chart are given as numbers
// and it uses the axes we created earlier
LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
lineChart.setTitle("Relative support in the years 1968-2008");
// create the data set that is going to be added to the line chart
XYChart.Series rkpData = new XYChart.Series();
rkpData.setName("RKP");
// and single points into the data set
rkpData.getData().add(new XYChart.Data(1968, 5.6));
rkpData.getData().add(new XYChart.Data(1972, 5.2));
rkpData.getData().add(new XYChart.Data(1976, 4.7));
rkpData.getData().add(new XYChart.Data(1980, 4.7));
rkpData.getData().add(new XYChart.Data(1984, 5.1));
rkpData.getData().add(new XYChart.Data(1988, 5.3));
rkpData.getData().add(new XYChart.Data(1992, 5.0));
rkpData.getData().add(new XYChart.Data(1996, 5.4));
rkpData.getData().add(new XYChart.Data(2000, 5.1));
rkpData.getData().add(new XYChart.Data(2004, 5.2));
rkpData.getData().add(new XYChart.Data(2008, 4.7));
// add the data set to the line chart
lineChart.getData().add(rkpData);
// create another data set that's going to be added to the chart
XYChart.Series vihrData = new XYChart.Series();
vihrData.setName("VIHR");
// and single data points into the data set
vihrData.getData().add(new XYChart.Data(1984, 2.8));
vihrData.getData().add(new XYChart.Data(1988, 2.3));
vihrData.getData().add(new XYChart.Data(1992, 6.9));
vihrData.getData().add(new XYChart.Data(1996, 6.3));
vihrData.getData().add(new XYChart.Data(2000, 7.7));
vihrData.getData().add(new XYChart.Data(2004, 7.4));
vihrData.getData().add(new XYChart.Data(2008, 8.9));
// add the data set to the line chart
lineChart.getData().add(vihrData);
// display the line chart
Scene view = new Scene(lineChart, 640, 480);
stage.setScene(view);
stage.show();
}
Das Programm sollte wie folgt aussehen, wenn es gestartet wird:

Jeder Datenpunkt wurde im obigen Programmcode manuell hinzugefügt – das fühlt sich für Programmierende etwas umständlich an. Die Lösung besteht darin, die Daten in eine geeignete Datenstruktur zu laden, diese Datenstruktur zu durchlaufen und die darin enthaltenen Daten in das Diagramm einzufügen. Eine gute Kandidatin für diese Datenstruktur ist eine HashMap, die die Namen der Parteien als Schlüssel verwendet. Die Werte der HashMap sind Paare von Zahlen, die das Jahr und die entsprechende Unterstützungszahl darstellen. Das Hinzufügen von Daten in das Diagramm wird nun viel einfacher.
// die zuvor erstellten Achsen und das Liniendiagramm
// Daten wurden zuvor gelesen -- das folgende Objekt enthält die Daten
Map<String, Map<Integer, Double>> values = // an anderer Stelle erstellt
// durchlaufen Sie die Parteien und fügen Sie sie dem Diagramm hinzu
values.keySet().stream().forEach(party -> {
// ein anderes Datenset für jede Partei
XYChart.Series data = new XYChart.Series();
data.setName(party);
// fügen Sie die Unterstützungszahlen der Partei zum Datensatz hinzu
values.get(party).entrySet().stream().forEach(pair -> {
data.getData().add(new XYChart.Data(pair.getKey(), pair.getValue()));
});
// und fügen Sie das Datenset dem Diagramm hinzu
lineChart.getData().add(data);
});
Shanghai (Part14_01)
Shanghai
Universitäten werden jährlich verglichen. Ein international anerkannter Bewerter ist die Shanghai Ranking Consultancy, die jährlich eine Vergleichsliste international bekannter Universitäten veröffentlicht. Die Liste enthält auch das Ranking für jede Universität. Die Universität Helsinki hat in den Jahren 2007-2017 folgende Platzierungen erreicht:
2007 73 2008 68 2009 72 2010 72 2011 74 2012 73 2013 76 2014 73 2015 67 2016 56 2017 56
Erstellen Sie in der Klasse ShangaiApplication
ein Programm, das zeigt, wie sich das Ranking der Universität Helsinki in diesen Jahren verändert hat. NB! Verwenden Sie kein Layout in der Anwendung – geben Sie das Liniendiagrammobjekt direkt als Parameter des Szenenkonstruktors an. Beachten Sie auch, dass die Scene auch die Breite und Höhe des Anzeigebereichs als Parameter benötigt.
Das von der Anwendung gezeichnete Ergebnis könnte wie folgt aussehen:

Wie reiche ich meine Lösung ein?
Sie müssen hierfür den Artemis Server verwenden und die entsprechende Aufgabe lösen. Hier klicken.
FinnishParties (Part14_02)
Finnische Parteien
Die Übungsbasis enthält die Klasse PartiesApplication
. Erstellen Sie darin eine Anwendung, die die relative Unterstützung der wichtigsten finnischen Parteien in den Jahren 1968-2008 anzeigt. Das Projekt enthält die Rohdaten, die in den vorherigen Beispielen verwendet wurden, und diese können in der Datei „partiesdata.tsv“ gefunden werden.
Die relative Unterstützung muss für jede Partei angezeigt werden, sodass eine separate Linie jede von ihnen im Liniendiagramm darstellt. Setzen Sie immer den Namen des XYChart.Series-Objekts auf den Parteinamen, der in den Daten gefunden werden kann (mithilfe der Methode setName).
Beim Erstellen der x-Achse, die das Liniendiagramm verwendet, beachten Sie bitte, dass das erste Jahr, das die Statistiken abdecken, das Jahr 1968 ist.
Tab-getrennte Zeichenfolgen können folgendermaßen in Teile aufgeteilt werden:
String string = "KOK 16.1 18.1 20.9";
String[] pieces = string.split("\t");
System.out.println(pieces[0]);
System.out.println(pieces[1]);
System.out.println(pieces[2]);
System.out.println(pieces[3]);
KOK 16.1 18.1 20.9
Um eine Gleitkommazahl aus einem Zeichenfolgenwert zu erstellen, der eine Gleitkommazahl enthält, können Sie die Methode valueOf der Klasse Double verwenden. So zum Beispiel Double.valueOf("16.1");
.
Die Visualisierung, die von der
Anwendung erstellt wird, sollte in etwa wie folgt aussehen:

Daten für ähnliche Diagramme finden Sie in den PX-Web-Datenbanken von Statistics Finland
Wie reiche ich meine Lösung ein?
Sie müssen hierfür den Artemis Server verwenden und die entsprechende Aufgabe lösen. Hier klicken.
SavingsCalculator (Part14_03)
Sparrechner (3 Teile)
In dieser Übung werden Sie ein Programm implementieren, um die Summe auf einem Sparkonto zu berechnen und anzuzeigen. Der Nutzende kann dem Rechner eine Summe angeben, die jeden Monat gespart werden soll, sowie den jährlichen Zinssatz, und der Rechner zeigt, wie die Ersparnisse über 30 Jahre hinweg wachsen.

Benutzungsoberfläche
Implementieren Sie zuerst die Benutzungsoberfläche der Anwendung. Die Komponenten der Anwendung können mit einem BorderPane verwaltet werden. In der Mitte des BorderPane fügen Sie ein Liniendiagramm (LineChart) hinzu, das zwei numerische Achsen (NumberAxis) hat. Am oberen Rand des BorderPane fügen Sie eine VBox-Komponente hinzu, die zwei BorderPanes enthält. Das erste BorderPane (oben) enthält links den Text "Monatliche Ersparnis", in der Mitte einen Schieberegler und rechts einen Text, der den Schieberegler beschreibt. Das zweite BorderPane (unterhalb des ersten) hat links den Text "Jährlicher Zinssatz", in der Mitte einen Schieberegler und rechts einen Text, der den Schieberegler beschreibt.
Sie können Tipps zur Verwendung der Slider-Klasse finden, indem Sie nach „javafx slider“ googeln (z.B. hier).
Definieren Sie die Schieberegler so, dass die minimale monatliche Ersparnis 25 und das Maximum 250 beträgt. Der minimale jährliche Zinssatz beträgt 0 und das Maximum 10. Die x-Achse des Liniendiagramms zeigt Jahre von 0-30 an. Die y-Achse muss sich an die angezeigten Werte anpassen.
In dieser Phase sollte die Anwendung so aussehen:

Anzeigen der Ersparnisse
Nachdem die Benutzungsoberfläche vollständig ist, beginnen Sie mit der Implementierung der Funktionalität des Programms.
Ändern Sie die Benutzungsoberfläche so, dass, wenn der Nutzende die Summe ändert, die jeden Monat gespart werden soll (durch Verschieben des oberen Schiebereglers), das Liniendiagramm aktualisiert wird, um den Ersparnisbetrag der neuen monatlichen Summe anzuzeigen. Zum Beispiel, wenn der monatliche Sparbetrag 50 beträgt, sollte das Liniendiagramm eine Linie zeigen, die die Werte [(0,0), (1,600), (2,1200), (3,1800),...] anzeigt.
In dieser Phase sollte die Anwendung wie folgt aussehen (wenn der monatliche Sparbetrag 50 beträgt):

Anzeigen der Ersparnisse und des Zinssatzes
Ändern Sie die Benutzungsoberfläche so, dass sie auch den Zinssatz anzeigt. Das Liniendiagramm sollte zwei Linien haben, eine, die nur die monatlichen Ersparnisse anzeigt, und eine, die die monatlichen Ersparnisse und den Zinssatz anzeigt.
Berechnen Sie den Zinssatz jährlich basierend auf den erwarteten Ersparnissen am Ende des Jahres. Zum Beispiel, wenn die monatliche Sparsumme 50 beträgt und der jährliche Zinssatz 5% beträgt, sollte das Liniendiagramm eine Linie zeigen, die die Werte [(0,0), (1, 630), (2, 1291.5), (3, 1986.075),...] anzeigt.
In dieser Phase sollte die Anwendung wie folgt aussehen (wenn der monatliche Sparbetrag 50 und der jährliche Zinssatz 10% beträgt):

In der Grafik sehen wir den Zinseszinseffekt unserer Ersparnisse, wenn auch mit einem sehr optimistischen Zinssatz. Wenn Sie die Anwendung abgeschlossen und eingereicht haben, können Sie zum Beispiel berechnen, wie sich das Sparen von 25 Euro pro Monat mit einem jährlichen Zinssatz von 4% über 50 Jahre hinweg entwickelt.
Wie reiche ich meine Lösung ein?
Sie müssen hierfür den Artemis Server verwenden und die entsprechende Aufgabe lösen. Hier klicken.
Balkendiagramme
Balkendiagramme werden verwendet, um kategorische Daten zu visualisieren. Die Daten werden als Balken dargestellt – jeder Balken repräsentiert eine bestimmte Kategorie, und seine Höhe (oder Länge) repräsentiert den mit der Kategorie verbundenen Wert. Beispiele für Daten, die gut mit Balkendiagrammen illustriert werden können, sind Bevölkerungen von Ländern oder Marktanteile von Geschäften oder Produkten.
Schauen wir uns die Verwendung eines Balkendiagramms zur Visualisierung der Bevölkerungszahlen der nordischen Länder an. Die verwendeten Daten stammen aus dem Wikipedia-Artikel über die nordischen Länder (abgerufen am 6.12.2019, Bevölkerungszahlen sind Schätzungen aus dem Jahr 2018).
Iceland, 343518 Norway, 5372191 Sweden, 10313447 Finland, 5537364 Denmark, 5809502
Wir werden die JavaFx-Klasse BarChart verwenden. Wie bei Liniendiagrammen müssen auch hier die Achsen definiert und Daten zum Diagramm hinzugefügt werden. In diesem Fall verwenden wir jedoch die Kategorieachse CategoryAxis, um die x-Achse zu definieren. Mit der CategoryAxis-Klasse ist der Typ der Achsenwerte ein String. Dies muss auch in den Daten berücksichtigt werden, die dem Diagramm hinzugefügt werden.
@Override
public void start(Stage stage) {
CategoryAxis xAxis = new CategoryAxis();
NumberAxis yAxis = new NumberAxis();
BarChart<String, Number> barChart = new BarChart<>(xAxis, yAxis);
barChart.setTitle("Populations of the Nordic countries");
barChart.setLegendVisible(false);
XYChart.Series populations = new XYChart.Series();
populations.getData().add(new XYChart.Data("Sweden", 10313447));
populations.getData().add(new XYChart.Data("Denmark", 5809502));
populations.getData().add(new XYChart.Data("Finland", 5537364));
populations.getData().add(new XYChart.Data("Norway", 5372191));
populations.getData().add(new XYChart.Data("Iceland", 343518));
barChart.getData().add(populations);
Scene view = new Scene(barChart, 640, 480);
stage.setScene(view);
stage.show();
}
Der obige Quellcode erzeugt folgendes Diagramm.

Wie Sie sehen, folgt das Diagramm der Reihenfolge, in der die Kategorien dem Programm zugeführt werden, da die x-Achse mit der CategoryAxis-Klasse definiert wurde. Im vorherigen Beispiel wurden die Länder nach Bevölkerungszahl geordnet. Versuchen Sie, das Programm so zu ändern, dass die nordischen Länder im Diagramm nach Namen geordnet werden. Nach dem Start der Anwendung werden Sie verstehen, warum diese Form der Visualisierung selten verwendet wird…
UnfairAdvertisement (Part14_04)
Unfaire Werbung
Es heißt, „Es gibt drei Arten von Lügen: Lügen, verdammte Lügen und Statistiken“. Der Spruch mag nicht ganz falsch sein, da manche Statistiken absichtlich schwer verständlich gemacht werden.
Die Anwendung in der Übungsvorlage zeigt eine Visualisierung, die in der Werbung eines fiktiven Unternehmens verwendet wird. Die Visualisierung zeigt die Geschwindigkeit ihres Internets und hebt sich dabei deutlich von der Konkurrenz ab.
Der Vergleich ist jedoch nicht wirklich fair und vermittelt einen falschen Eindruck von der tatsächlichen Situation. Ändern Sie das Programm so, dass der Vergleich fairer wird.

Diese Übung hat keine automatischen Tests oder Musterlösungen, sodass Sie bei der Definition eines faireren Vergleichs einige Freiheiten haben.
Wie reiche ich meine Lösung ein?
Sie müssen hierfür den Artemis Server verwenden und die entsprechende Aufgabe lösen. Hier klicken.
CyclingStatistics (Part14_05)
Fahrradstatistiken
In der Übungsbasis gibt es eine fertige Anwendung, die Fahrradstatistiken als Liniendiagramm darstellt. Ändern Sie das Programm so, dass es statt eines Liniendiagramms ein Balkendiagramm verwendet. Alle Verweise auf Liniendiagramme müssen im Laufe der Bearbeitung entfernt werden.
Wie reiche ich meine Lösung ein?
Sie müssen hierfür den Artemis Server verwenden und die entsprechende Aufgabe lösen. Hier klicken.
Visualisierung dynamischer Daten
Software wird auch verwendet, um sich kontinuierlich ändernde Informationen zu visualisieren. Beispielsweise sucht die Software, die zur Überwachung von Aktienkursen verwendet wird, ständig nach den neuesten Kursen und zeigt diese dem Nutzenden an. Ebenso ruft Wettersoftware Daten von Wetterstationen ab
und zeigt die neuesten Informationen den Nutzenden an. Software, die zur Überwachung von Serveranwendungen entwickelt wurde, funktioniert auf ähnliche Weise, indem sie in bestimmten Intervallen die verschiedenen Teile der Serveranwendung pingt, um auf Antworten zu prüfen.
Die AnimationTimer-Klasse kann auch verwendet werden, um dynamische Daten zu visualisieren. Mit der AnimationTimer-Klasse kann eine Anwendung erstellt werden, die regelmäßig neue Informationen für die Anwendung abruft oder generiert.
Das folgende Beispiel veranschaulicht das Gesetz der großen Zahlen. Dieses Gesetz ist ein Phänomen, das mit der Wahrscheinlichkeitsrechnung zusammenhängt und besagt, dass der Durchschnitt einer Zufallsvariablen mit zunehmender Anzahl von Wiederholungen dem erwarteten Wert der Zufallsvariablen immer näher kommt. In der Praxis nähert sich zum Beispiel der Durchschnitt der Würfe eines sechsseitigen Würfels dem Wert 3,5, wenn die Anzahl der Würfe zunimmt. In ähnlicher Weise nähert sich bei einem Münzwurf das Verhältnis von Kopf zu Zahl mit zunehmender Anzahl von Münzwürfen einem Verhältnis von „fifty-fifty“.
@Override
public void start(Stage stage) {
// Die Klasse Random wird verwendet, um die Würfe zu randomisieren
Random random = new Random();
NumberAxis xAxis = new NumberAxis();
// y-Achse repräsentiert den Durchschnitt der Würfe. Der Durchschnitt liegt immer zwischen [1-6]
NumberAxis yAxis = new NumberAxis(1, 6, 1);
LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
// Entfernen von Elementen des Diagramms, z. B. Kreisen auf Punkten
lineChart.setLegendVisible(false);
lineChart.setAnimated(false);
lineChart.setCreateSymbols(false);
// wir erstellen eine Variable, die die Daten darstellt, und fügen sie dem Diagramm hinzu
XYChart.Series average = new XYChart.Series();
lineChart.getData().add(average);
new AnimationTimer() {
private long previous;
private long sum;
private long count;
@Override
public void handle(long current) {
if (current - previous < 100_000_000L) {
return;
}
previous = current;
// den Würfel werfen
int number = random.nextInt(6) + 1;
// wir erhöhen die Summe und inkrementieren die Zählung
sum += number;
count++;
// wir fügen dem Diagramm einen neuen Datenpunkt hinzu
average.getData().add(new XYChart.Data(count, 1.0 * sum / count));
}
}.start();
Scene scene = new Scene(lineChart, 400, 300);
stage.setScene(scene);
stage.show();
}
Das Bild unten zeigt ein Beispiel für die Anwendung in Verwendung. Der Würfel wurde fast 100 Mal geworfen.

Aufmerksame Leser*innen haben möglicherweise bemerkt, dass der Quellcode der Anwendung das Diagramm beim Hinzufügen von Daten nicht neu gezeichnet hat. Was ist da los?
Diagramme wie LineChart und BarChart verwenden eine Datenstruktur, die das ObservableList-Interface implementiert, um interne Daten zu speichern. Sammlungen, die das ObservableList-Interface implementieren, bieten die Möglichkeit, auf Änderungen in den Sammlungen zu lauschen. Wenn ein neuer Datensatz zur Liste hinzugefügt wird, wie z. B. ein neuer Datenpunkt für den Durchschnitt, informiert die Liste alle Objekte, die auf Änderungen der Liste hören, über diese Änderung. Diagramme wie LineChart und BarChart sind intern so aufgebaut, dass sie auf Änderungen in den angezeigten Informationen reagieren. Wenn sich die Daten ändern, wird das Diagramm automatisch aktualisiert.
In einigen Situationen möchten wir möglicherweise nur die letzten 100 Beobachtungen der sich dynamisch ändernden Daten anzeigen. Dies kann im vorherigen Beispiel erreicht werden, indem die automatische Werteberechnung der x-Achse des NumberAxis-Objekts deaktiviert wird (mit der Methode setAutoRanging(false)) und die folgende Überprüfung am Ende der handle-Methode der AnimationTimer-Klasse hinzugefügt wird.
if (average.getData().size() > 100) {
average.getData().remove(0);
xAxis.setLowerBound(xAxis.getLowerBound() + 1);
xAxis.setUpperBound(xAxis.getUpperBound() + 1);
}
Die Anwendung zeigt nun nur die letzten 100 Beobachtungen den Nutzenden an.