Jfreechart continuous series mit fester Länge

TDO88

Bekanntes Mitglied
Hallo Zusammen,

ich habe einen kontinuierlichen Datenstrom an Messwerten von einem Messgerät, die ich gerne in einem Scatterplot darstellen würde.
Die Werte werden quasi als Lissajous Graf dargestellt.
Ich möchte aber immer nur die letzen z.B. 500 Werte darstellen.
Also wenn mein series1.getItemCount() >= 500 ist, möchte ich das erste Item wieder vergessen und dann das neue Item einfügen.

Der Codeausschnitt dazu sieht bei mir aktuell so aus:
Java:
Point pCh1 = new Point();

pCh1 = GetCoordinates(swRawX, s2wRawX);

series1.add(pCh1.x, pCh1.y);
if(series1.getItemCount() >= 500) {
    series1.remove(0);
}
panel.validate();

Das ganze läuft in einer Schleife recht schnell durch. (Die Initialisierung der Point Variable läuft nicht in der Schleife)
Ich bekomme jedoch immer wieder, aber nicht immer folgenden Fehler:

Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 499, Size: 499
at java.util.ArrayList.rangeCheck(ArrayList.java:657)
at java.util.ArrayList.get(ArrayList.java:433)
at org.jfree.data.xy.XYSeries.getRawDataItem(XYSeries.java:634)
at org.jfree.data.xy.XYSeries.getX(XYSeries.java:645)
at org.jfree.data.xy.XYSeriesCollection.getX(XYSeriesCollection.java:358)
at org.jfree.data.xy.AbstractXYDataset.getXValue(AbstractXYDataset.java:77)
at org.jfree.chart.renderer.xy.XYLineAndShapeRenderer.drawSecondaryPass(XYLineAndShapeRenderer.java:1121)
at org.jfree.chart.renderer.xy.XYLineAndShapeRenderer.drawItem(XYLineAndShapeRenderer.java:916)
at org.jfree.chart.plot.XYPlot.render(XYPlot.java:3738)
at org.jfree.chart.plot.XYPlot.draw(XYPlot.java:3271)
at org.jfree.chart.JFreeChart.draw(JFreeChart.java:1229)
at org.jfree.chart.ChartPanel.paintComponent(ChartPanel.java:1628)
at javax.swing.JComponent.paint(JComponent.java:1056)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5210)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1579)
at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1502)
at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
at javax.swing.JComponent._paintImmediately(JComponent.java:5158)
at javax.swing.JComponent.paintImmediately(JComponent.java:4969)
at javax.swing.RepaintManager$4.run(RepaintManager.java:831)
at javax.swing.RepaintManager$4.run(RepaintManager.java:814)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
at javax.swing.RepaintManager.access$1200(RepaintManager.java:64)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

Kann mir jemand helfen, warum dieser Fehler auftritt und was ich tun kann, damit das stabil läuft?

Vielen Dank und Gruß
 

TDO88

Bekanntes Mitglied
Ich habe eine Klasse, die prinzipiell so augebaut ist:
Java:
class SinCosDataPollThread extends Thread {
    int iflags;
    
    SinCosDataPollThread(int flags) {
        this.iflags = flags;
    }
    
    @Override
    public void run()
    {
        synchronizes(this)
        {
            ...
            Point pCh1 = new Point();
            ...
            while(run) {
                ...//Hole Daten aus dem Messgerät und schreibe Sie in swRawX und s2wRawX
                pCh1 = GetCoordinates(swRawX, s2wRawX);
                series1.add(pCh1.x, pCh1.y);
                if(series1.getItemCount() >= 1000) {
                    series1.clear();
                }
            }
        }
    }
    private Point GetCoordinates(double sin, double cos)
    {
        //Berechne Koordinaten
    }
}

Passiert also eigentlich alles in einem Thread
 
K

kneitzel

Gast
Damit hast Du doch zwei Threads. Zum einen den, den, den Du dort hast - denn du wirst ja eine Instanz erzeigen und dann start() aufrufen, oder?
Und die Exception kam aus dem EDT - der versucht halt wohl die Daten zum Anzeigen zu lesen.

Wenn Du mit mehreren Threads auf Daten zugreifst, dann musst Du ggf. synchronisieren. Also wenn Du da Daten löschst, dann darf in der Zeit der EDT nicht zugreifen. Und umgekehrt: während der EDT Daten ausliest, wirst Du nichts löschen dürfen.

Oder du verlagerst das Löschen generell in den EDT. Du könntest mit SwingUtilities.invokeLater das Löschen im EDT Thread machen lassen. Denn das Hinzufügen ist ja unkritisch bezüglich des Löschens. Aber ich wäre da auch recht vorsichtig und würde auf jeden Fall thread Safe Collections nutzen....
 

TDO88

Bekanntes Mitglied
Okay, vielen Dank für die Rückmeldung.
Ja, der Thread wird von einem anderen Thread aufgerufen, das stimmt natürlich. Jedoch dachte ich, dass der diesen nicht beeinflusst, da er diesen Thread aufruft und wartet, bis dieser abgeschlossen ist. Dann muss ich mir mal das Thema thread safe Collections mal anschauen.
Ich dachte zunächst, dass es an der remove Methode liegt.
Diese remove Methode ist überladen (siehe Datei Remove) und ich weiß nicht so recht, ob er die richtige Methode wählt.
Der Graph wird aufgebaut und solange nur Elemente hinzugefügt werden, ist ein Kreis der Punkte zu erkennen (Adjust1). Sobald er anfängt Daten zu löschen, scheinen die Werte um die Null herum zu verschwinden (Adjust2)
Kann es sein, dass die falsche Methode benutzt wird und nicht der Index=0 gelöscht wird, sondern alle Werte mit dem X-Wert = 0?
Wenn ja, wie kann ich dem beibringen, dass er bitte nur den Index löscht?
Dennoch werde ich mir das Thema thread safe collections mal anschauen und versuchen damit noch was zu retten.
 

Anhänge

  • Adjust1.png
    Adjust1.png
    34,8 KB · Aufrufe: 31
  • Adjust2.png
    Adjust2.png
    35,6 KB · Aufrufe: 28
  • Remove.png
    Remove.png
    20,4 KB · Aufrufe: 32
K

kneitzel

Gast
Also wenn du da einen Aufruf remove(0); hast, dann ist 0 ein int Literal und er sollte remove(int) aufrufen und nicht remove(Number).

Aber das wäre dann nur bei dem Code aus dem ersten Post ... später hast Du da ja einen clear() Aufruf oder so ... Also hat der Code sich ggf. schon geändert und evtl. hast Du ja keinen int mehr sondern eine Number (Also z.B. ein Integer).
 

TDO88

Bekanntes Mitglied
Ich habe das clear mal probeweise da stehen gehabt, damit ich schauen kann, wie es aussieht, wenn ich den zyklisch einfach komplett neu erstellen lasse.
Die beiden Bilder aus meinem letzten Post sind aber mit dem remove(0) gemacht.
 

mihe7

Top Contributor
Ja, der Thread wird von einem anderen Thread aufgerufen, das stimmt natürlich. Jedoch dachte ich, dass der diesen nicht beeinflusst, da er diesen Thread aufruft und wartet, bis dieser abgeschlossen ist.
Es geht um den EDT und der wartet nicht und soll auch nicht warten, sonst friert die GUI ein.

Während im EDT gezeichnet, also über die Messwerte iteriert wird, werden in Deinem Thread ggf. Messwerte gelöscht -> ArrayIndexOutOfBoundsException.

Wenn ich es richtig verstehe, muss gar kein paralleler Zugriff auf die Inhalte der Liste erfolgen. In dem Fall würde ich einfach hergehen und einen Ringbuffer und eine Liste verwenden. Den Ringbuffer füllst Du in run() und anschließend erzeugst Du eine neue Liste, die die alte - thread-safe - ersetzt. Die Liste kann - ebenfalls thread-safe - vom EDT abgerufen werden.
 

TDO88

Bekanntes Mitglied
Hallo,
sorry, dass ich mich jetzt erst melde, aber ich hatte im Moment noch andere Baustellen.
Also, wenn möglich sollte der Ablauf so sein:
1. Wertepaar aus Messgerät auslesen
2. Wertepaar auf dem Graphen anzeigen
3. if(Anzahl der Werte > Grenzwert) Ältestes Wertepaar löschen
So, dass sich ein kontinuierlicher Werteverlauf zeigen lässt. Es ist eine Lissajous Darstellung, welche möglichst ein Kreis mit r=1 ist. Je nachdem, wie gut die Signalqualität des Messgerätes ist.
Das mit dem series.clear() war wie gesagt nur mal ein Versuch, was mir aber optisch nicht gefällt.
Ein RingBuffer wäre top. Es gibt aber keine Möglichkeit einen RingBuffer direkt auf einen Scatterplot zu geben oder?
 

mihe7

Top Contributor
Wichtig ist nur, dass Du beim Zeichnen nicht auf etwas zugreifst, das in einem anderen Thread verändert werden könnte. Das kannst Du per Thread-Synchronisation erreichen oder Du sorgst eben dafür, dass der betreffende Code im EDT ausgeführt wird oder Du erzeugst jeweils eine neue Liste oder .... Am einfachsten erscheint mir, die Änderung der Daten im EDT vorzunehmen.

Was die Möglichkeiten von JFreeChart betrifft, da müsste ich jetzt erst nachlesen.
 

TDO88

Bekanntes Mitglied
Guten Morgen,
ich habe jetzt noch etwas rumprobiert, aber leider komme ich immer zu dem gleichen Ergebnis...
Ich habe folgenden Grundaufbau:
Java:
public class My_API extends javax.swing.JFrame {
    private class AdjustThread extends Thread
    {
        int flags;
        
        AdjustThread(int flags) {
            this.flags = flags;
        }
            @Override
            public void run()
            {
                synchronized(this)
                {
                    //Vorbereitende Funktionen
                    //LissajousPlot wird aufgerufen
                    ...
                }
            }
        }
    }
    private class LissajousPlot extends JFrame {
        private LissajousPlot(String title, int iflags) {
            super(title);
            //hier wird des Fenster mit dem Plot erstellt
        }
    }

}

Vorher hatte ich noch einen weiteren Thread, der dann die Daten aus dem Gerät ausliest und in die series des Plots schiebt, wie oben gesehen.
Ich habe diesen Teil (Daten auslesen und in series schieben und bei Anzahl > 500 => series1.remove(0)) mal testweise in die AdjustThread eingebaut und auch in den LissajousPlot eingebaut, aber beides resultiert in den oben beschriebenen Exceptions und Verhalten. Also es macht keinen Unterschied.
Ganz blöd gefragt, welches ist denn dann jetzt der EDT? Ich bin jetzt davon ausgegangen, dass er der AdjustThread ist, weil der den Rest aufruft?!
 

TDO88

Bekanntes Mitglied
Daraus werde ich gerade nicht so ganz schlau, um ehrlich zu sein. Wo müsste ich das Abfragen reinpacken, damit es im EDT läuft und die Exception hoffentlich verschwinden?
 

mihe7

Top Contributor
Du musst einfach dafür sorgen, dass der Zugriff auf die Daten synchronisiert wird.

EDIT: Vergiss das, wir hatten ja gesagt, den Code in den EDT auszulagern. Das geht per SwingUtilities.invokeLater, wie @kneitzel unten schon geschrieben hat.
 
K

kneitzel

Gast
Wenn Du in Swing etwas im EDT laufen lassen willst, dann startest Du dieses entweder innerhalb eines Events (Da bist Du im EDT, also z.B. wenn Du auf ein Butten Click reagierst) oder wenn Du in einem eigenen Thread bist, dann verlagerst Du es mittels SwingUtilities.invokeLater in den EDT.
 

TDO88

Bekanntes Mitglied
Ich habe in meinem Thread jetzt mal das invokeLater eingebaut, leider bleibt die GUI dann hängen. Also ich sehe zwar z.B. Pop-Ups, aber es wird nur der Rahmen des Pop-Ups dargestellt. Der Inhalt fehlt komplett.
 

TDO88

Bekanntes Mitglied
Also sobald ich das aufrufe, friert mein Fenster ein. Dann ist nichts mehr bedienbar.
Habe es jetzt z.B. mal hier eingebaut:
Java:
series1.add(pCh1.x, pCh1.y);
if(series1.getItemCount() >= 1000) {
    SwingUtilities.invokeLater(this);
    series1.remove(0);
}

Sobald der ItemCount überschritten wird und die If Bedingung True wird friert das Fenster ein und ist nicht mehr bedienbar?!
 

LimDul

Top Contributor
Ja, das ist ja auch falsch.

Du lagerst damit deinen Thread *komplett* in invokeLater aus. Das kann nicht klappen.
Du willst nur den Befehl series1.remove auslagern.

Java:
if(series1.getItemCount() >= 1000) {
    SwingUtilities.invokeLater(()->series1.remove(0));
}
 

TDO88

Bekanntes Mitglied
AHHH.... okay. Vielen Dank für die Hilfe.
Damit konnte ich jetzt zumindest verhindern, dass die Exceptions auftreten. Das ist jetzt der Fall.
Leider habe ich immernoch das Problem mit dem Verschieben des Diagramms.
Mit dieser series1 und dem remove(0) wollte ich ja im prinzip so etwas wie einen Ringbuffer erzeugen.
Wenn der ItemCount >= 1000 ist, soll der "älteste" Wert wieder entfernt werden, sodass ich ein dynamisches Diagramm bekomme, mit nie mehr als z.B. 1000 Punkten.
Es wird allerdings leider immer der Punkt mit dem niedrigsten X-Wert gelöscht und nicht der "älteste". Ich habe das jetzt mal langsam beobachtet, wenn das Diagramm schon deutlich verschoben wurde.
Es werden manchmal neue Punkte erzeugt und direkt wieder gelöscht.
Beispiel:
1000 Punkte.png
So sieht es auch, bis die 1000 Punkte erreicht sind.

Dann fängt er an die X-Werte zu löschen... Nach einer kurzen Seit passiert das:
NeuerPunkt.png
Er hat schon den kompletten linken Teil des Kreises verschluckt und dann kommt ein neuer Punkt (links markiert) durch das series.add dazu.
Die Remove Methode löscht dann aber wieder genau diesen Punkt:
Remove(0).png

Die Remove(0) Methode löscht also scheinbar nicht das 0. Element (das "älteste"), sondern das Element mit dem kleinsten X-Wert.

Was kann man dagegen tun?
 

LimDul

Top Contributor
Ist/wird die ArrayList sortiert? Weil eigentlich sollte das Element an Stelle 0 bei einer unsortierten ArrayList das älteste sein

Edit: Ich sehe gerade series1 ist keine ArrayList sondern ein eigener Datentyp?
 

TDO88

Bekanntes Mitglied
Eigentlich nicht.
So wird sie erzeugt:
Java:
private final XYSeries series1 = new XYSeries("");

einer Collection hinzugefügt:
Java:
//Create dataset
XYSeriesCollection CollectionCh1 = new XYSeriesCollection();
series1.clear();
CollectionCh1.addSeries(series1);

und die Daten bearbeitet:
Java:
SwingUtilities.invokeLater(()->series1.add(temp.x, temp.y));
if(series1.getItemCount() >= 1000) {
    SwingUtilities.invokeLater(()->series1.remove(0));
}

Das ist alles, was ich damit mache.
 

TDO88

Bekanntes Mitglied
Na endlich.... Mega.
Vielen, vielen Dank. Jetzt läuft das so, wie ich es möchte und es wird nur das älteste Element gelöscht.
Jetzt muss ich es nur noch hinbekommen, dass der Plot sich nicht andauernd neu selbst skaliert, sondern immer in X und Y Werte von -1 bis +1 anzeigt.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
G jFreeChart Allgemeine Java-Themen 5
H JFreechart createMultiplePieChart Allgemeine Java-Themen 2
M Suche Alternative zu JFreeChart Allgemeine Java-Themen 11
T jfreechart Linien/Punkttyp anpassen Allgemeine Java-Themen 1
S JFreechart: ValueMarker mit der Maus ziehen? Allgemeine Java-Themen 12
A JFreeChart funktioniert nicht :( Allgemeine Java-Themen 6
M Swing JFreechart x-Achse DateAxis, start im Ursprung Allgemeine Java-Themen 3
S Performante Visualisierung groẞer Datenmengen (ohne JFreeChart) Allgemeine Java-Themen 22
M Swing JFreeChart Domain Axis Label Abstand zu TickUnitLabel Allgemeine Java-Themen 9
S AWT JFreeChart in ein Label Allgemeine Java-Themen 7
J JFreeChart - Mehrere X-Achsen Einteilungen Allgemeine Java-Themen 3
T JFreeChart Diagramm speichern - Problem mit ImageIO nach Projektexport Allgemeine Java-Themen 3
B JFreeChart -> TimeSeries-Plot -> mehr y-Achsen Allgemeine Java-Themen 2
F JFreeChart Größe anpassen Allgemeine Java-Themen 8
K JFreeChart - Einträge in DomainAxis anpassen Allgemeine Java-Themen 2
I 2D-Grafik JFreeChart ChartPanel Problem mit dynamischer Grösse Allgemeine Java-Themen 3
O JFreeChart: ständiges Updaten der Chart stoppen Allgemeine Java-Themen 4
M Diagramm mit JfreeChart Allgemeine Java-Themen 8
M JFreeChart mehrere PieCharts erstellen Allgemeine Java-Themen 2
M JFreeChart piechart - labelAnzeige Allgemeine Java-Themen 2
ARadauer JFreeChart: Beschriftung anzeigen Allgemeine Java-Themen 6
B JFreeChart - Achsenbeschriftung Allgemeine Java-Themen 4
ff Labels mit JFreeChart ausrichten Allgemeine Java-Themen 2
K JFreeChart Achsenbeschriftung ändern? Allgemeine Java-Themen 4
C jFreechart Diagram erstellen Allgemeine Java-Themen 2
G JFreeChart Allgemeine Java-Themen 5
G Jfreechart zwei charts Allgemeine Java-Themen 2
S JFreeChart LineChart Punkte über NULL Werte hinweg verbinden Allgemeine Java-Themen 5
E JFreeChart jars mit in meine Jar packen Allgemeine Java-Themen 6
G jfreechart probleme mit dem package? Allgemeine Java-Themen 2
D JFreeChart und Kuchendiagramm Allgemeine Java-Themen 3
P JFreeChart Fehlermeldung Allgemeine Java-Themen 2
P jFreeChart, binäre Signale Allgemeine Java-Themen 2
P jfreeChart y- Achsen hinzufügen Allgemeine Java-Themen 2
P jfreeChart Allgemeine Java-Themen 9
MQue JFreeChart Allgemeine Java-Themen 3
K JFreeChart Allgemeine Java-Themen 3
K JFreeChart und itext: Bildprobleme Allgemeine Java-Themen 4
G java.lang.NullPointerException JFreeChart Allgemeine Java-Themen 5
M JFreeChart: Zuviele Balken, Übersicht leidet dehr darunter Allgemeine Java-Themen 6
G JFreeChart - Labels Allgemeine Java-Themen 2
G Suche Beispiele jFreeChart Allgemeine Java-Themen 12
G Daten aus MySQL-Datenbank an JFreeChart übergeben Allgemeine Java-Themen 3
G JFreeChart drucken Allgemeine Java-Themen 2
W Requirements an ein Continuous Integration Tool Allgemeine Java-Themen 21

Ähnliche Java Themen

Neue Themen


Oben