I have a problem with the TimeSeriesCollection ultimately consuming 100% processor time and effectively slowing down the computer and distorting the plot. It takes about 10 minutes for the CPU usage to reach 100%, and it never comes down.
I have included a modified demo class to illustrate this problem. There are 2 comment sections in the class that explain how to duplicate and demonstrate it the problem. ( It's not a problem, it's a feature, right

My suspicion is that there is a problem (garbage collecting issue) adding a new Millisecond class to the TimeSeries every time it is called from the accessor methods. Is there another way to do this? I basically dissected the code in the example classes and made this OScope work for me.
PS - I hope this posts well.
//*************** Begin OScope class ***************
import java.text.DecimalFormat;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import com.jrefinery.data.*;
import com.jrefinery.chart.*;
import com.jrefinery.chart.entity.*;
import com.jrefinery.chart.event.*;
import com.jrefinery.chart.tooltips.*;
import com.jrefinery.chart.ui.*;
/**
* A simple class demonstrating run-away CPU usage with the BasicTimeSeries or
* TimeSeriesCollection classes (or other class related to a Dynamic XYPlot).
*
* This application was built and tested using Java 1.4.0 although it may work
* using Java 1.3.x. Additionally, this demo requires the classes in the
* JCommon and JFreeChart distributions.
*
* See the comment section below above the Accessor methods for further
* explaination of the run-away CPU usage problem and a way to demonstrate
* the problem.
*
* If anyone has any questions, comments or needs further explaination, please
* call or email.
*
* thank you,
* Tony Bianchini
* Tony.Bianchini@aei.com
* 970-407-6136
*/
public class OScope extends JLayeredPane {
private static final Font BUTTON_FONT = new Font("SansSerif", Font.PLAIN, 12);
private ChartPanel chartPnl;
private JFreeChart chart;
private XYSeriesCollection dataset;
private XYDataset data;
private XYPlot xyplot;
private VerticalNumberAxis range;
private HorizontalDateAxis domain;
private BasicTimeSeries cyanTimeSeries, greenTimeSeries;
private TimeSeriesCollection timeDataset;
private DecimalFormat df = new DecimalFormat("#.00");
private BasicStroke gridStroke, seriesStroke;
private JLabel cyanLabel, greenLabel;
public OScope() {
super();
NumberTickUnit verticalTicks = new NumberTickUnit(25.0, new DecimalFormat());
//DateTickUnit horizontalTicks = new DateTickUnit();
cyanTimeSeries = new BasicTimeSeries("Random Data", Millisecond.class);
greenTimeSeries = new BasicTimeSeries("Random Data", Millisecond.class);
timeDataset = new TimeSeriesCollection();
timeDataset.addSeries(cyanTimeSeries);
timeDataset.addSeries(greenTimeSeries);
gridStroke = new BasicStroke(0.50f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
seriesStroke = new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
domain = new HorizontalDateAxis();
range = new VerticalNumberAxis();
xyplot = new XYPlot(timeDataset, domain, range);
xyplot.setBackgroundPaint(Color.black);
xyplot.setSeriesPaint(new Paint[] {Color.cyan, Color.green});
xyplot.setSeriesStroke(0, seriesStroke);
domain.setAutoRange(true); //if true, display is blank
domain.setFixedAutoRange(30000.0); //30 second dispaly
domain.setGridPaint(Color.green);
domain.setGridStroke(gridStroke);
domain.setTickLabelsVisible(false);
domain.setGridLinesVisible(false); //vertical grid lines off
domain.setCrosshairVisible(false);
range.setStandardTickUnits(TickUnits.createIntegerTickUnits());
range.setTickUnit(verticalTicks);
range.setRange(0.0, 200.0);
range.setGridPaint(Color.green);
range.setGridStroke(gridStroke);
range.setTickLabelsVisible(false);
range.setGridLinesVisible(true); //horizontal grind lines on
range.setCrosshairVisible(false);
//get the chart and add it to the ChartPnl
chart = new JFreeChart(xyplot);
chartPnl = new ChartPanel(chart);
chartPnl.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLoweredBevelBorder(),
BorderFactory.createEmptyBorder(0,-5,-12,-8) ));
cyanLabel = new JLabel();
cyanLabel.setText("0");
cyanLabel.setFont(BUTTON_FONT);
cyanLabel.setForeground(Color.cyan);
greenLabel = new JLabel("0");
greenLabel.setFont(BUTTON_FONT);
greenLabel.setForeground(Color.green);
cyanLabel.setBackground(Color.black);
cyanLabel.setOpaque(true);
greenLabel.setBackground(Color.black);
greenLabel.setOpaque(true);
add(chartPnl, JLayeredPane.DEFAULT_LAYER);
//add(gridPnl, new Integer(50));
add(cyanLabel, JLayeredPane.PALETTE_LAYER);
add(greenLabel, JLayeredPane.PALETTE_LAYER);
chartPnl.setBounds(7,5,250,130);
cyanLabel.setBounds(13,17,43,14);
greenLabel.setBounds(13,34,43,14);
}//constructor
/** Accessor Methods to update the Green and Cyan plots ************
* and App Notes relating to how to duplicate the CPU usage problem
*
* The following 2 Accessor methods the update the value of the
* green and cyan plots and labels on the OScope Demo.
* setCyanPlot(double y) and setGreenPlot(double y)
*
* Scenario 1:
* First, run this application as is and monitor the CPU usage on
* the Windows Task Manager.In a short period of time, about 10 minutes,
* you will see the CPU usage creep up to 100% --- and stay there!!!
*
* Scenario 2:
* Now, comment the 2 statements that update the
* timeSeries and leave the statements that update the labels
* uncommented and run this application and watch the CPU usage
* you find that the CPU usage is at or near 0% and will never climb
* above it.
*
* The statements to comment are:
* cyanTimeSeries.add(new Millisecond(), y); and
* greenTimeSeries.add(new Millisecond(), y);
*
* Commenting these statements here, keeps the DataGenerator running and
* Scope labels updating and only shuts down the
* JFreeChart TimeSeries classes.
*
* You can change the update rate in the DataGenerator to a slower
* update rate and this run-away CPU usage problem will still occur.
* My design spec is to have a maximum update interval of 100mS.
*
* (I am using a 1GHz P4 processor w/512MByte of RAM)
*
* So, is there another way to do this without encountering the
* excessive CPU usage problem?
*
*/
void setCyanPlot(double y){
cyanTimeSeries.add(new Millisecond(), y); //comment this line
cyanLabel.setText(df.format(y));
}
void setGreenPlot(double y) {
greenTimeSeries.add(new Millisecond(), y); //comment this line
greenLabel.setText(df.format(y));
}
private static int hangCount;
boolean state;
/**
* An inner class to generate random data for the Cyan plot
* and a square wave for the Green plot.
*
* The accessor methods to update the 2 plots are called from
* within the DataGenerator.
*/
class DataGenerator extends Timer implements ActionListener {
private double lastValue;
private double factor;
DataGenerator(){
super(250,null); //DataGenerator update interval
lastValue = 100.0;
this.addActionListener(this);
}
public void actionPerformed(ActionEvent ae){
factor = 0.9 + 0.2*Math.random();
lastValue = lastValue*factor;
//reset the amplitude of the plot
//if it gets too low or too high
if (lastValue<5) {lastValue = lastValue+100;}
if (lastValue>155) {lastValue = lastValue-100;}
setCyanPlot(lastValue);
//setGreenPlot(lastValue-25);
//Square Wave Generator
if (state){
setGreenPlot(110);
} else {
setGreenPlot(10);
}
hangCount++;
if (hangCount == 10) {
state = !state;
hangCount = 0;
}
}//actionPerformed
}//class DataGenerator
public static void main(String[] args) {
JFrame frame = new JFrame("OScope Demo");
OScope scope = new OScope();
frame.getContentPane().add(scope, BorderLayout.CENTER);
frame.setBounds(200,20,300,200);
frame.setVisible(true);
scope.new DataGenerator().start();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}//main
}//class