Part 14

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.


Darstellung des Radfahrer-Datensatzes

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]);
}
Beispielausgabe
0: Päivämäärä 1: Huopalahti (asema) 2: Kaisaniemi 3: Kulosaaren silta et. 4: ...

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));
}
Beispielausgabe

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:

Diagramm zur Unterstützung der Parteien RKP und VIHR

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);
});
Programmierübung:

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:

shanghai

Sie müssen hierfür den Artemis Server verwenden und die entsprechende Aufgabe lösen.

Hier klicken.

Programmierübung:

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]);
Beispielausgabe

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:

chart relative support

Daten für ähnliche Diagramme finden Sie in den PX-Web-Datenbanken von Statistics Finland


Sie müssen hierfür den Artemis Server verwenden und die entsprechende Aufgabe lösen.

Hier klicken.

Programmierübung:

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.

saastolaskuri

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:

saastolaskuri 1

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):

saastolaskuri 2

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):

saastolaskuri 3

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.


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.

Ein Balkendiagramm, das die Bevölkerungszahlen der nordischen Länder zeigt

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…

Programmierübung:

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.

kuvaaja liittyman nopeus

Diese Übung hat keine automatischen Tests oder Musterlösungen, sodass Sie bei der Definition eines faireren Vergleichs einige Freiheiten haben.


Sie müssen hierfür den Artemis Server verwenden und die entsprechende Aufgabe lösen.

Hier klicken.

Programmierübung:

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.


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.

Ein Diagramm, das das Gesetz der großen Zahlen veranschaulicht

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.

Sie haben das Ende dieses Abschnitts erreicht! Weiter zum nächsten Abschnitt: