Dynamic Time Series Stacked Area Chart in Java - java

My requirement is to create a dynamic time series stacked area chart in a java desktop app. Something like this example, but i want Stacked Area chart. I have found lot of examples of stacked area chart but they all are based on static data.

Here is the modified version of this example for dynamic time series stacked area chart.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickUnit;
import org.jfree.chart.axis.DateTickUnitType;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.SeriesRenderingOrder;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StackedXYAreaRenderer;
import org.jfree.data.time.Second;
import org.jfree.data.time.TimePeriod;
import org.jfree.data.time.TimeTableXYDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
public class DTSCTest extends ApplicationFrame {
private static final String TITLE = "Dynamic Series";
private static final String START = "Start";
private static final String STOP = "Stop";
private static final float MINMAX = 100;
private static final int COUNT = 15;
private static final int FAST = 1000;
private static final int SLOW = FAST * 5;
private static final Random random = new Random();
private Timer timer;
private static final String SERIES1 = "Positive";
private static final String SERIES2 = "Negative";
public DTSCTest(final String title) {
super(title);
final TimeTableXYDataset dataset = new TimeTableXYDataset();
JFreeChart chart = createAreaChart(dataset);
final JButton run = new JButton(STOP);
run.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (STOP.equals(cmd)) {
timer.stop();
run.setText(START);
} else {
timer.start();
run.setText(STOP);
}
}
});
final JComboBox combo = new JComboBox();
combo.addItem("Fast");
combo.addItem("Slow");
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if ("Fast".equals(combo.getSelectedItem())) {
timer.setDelay(FAST);
} else {
timer.setDelay(SLOW);
}
}
});
this.add(new ChartPanel(chart), BorderLayout.CENTER);
JPanel btnPanel = new JPanel(new FlowLayout());
btnPanel.add(run);
btnPanel.add(combo);
this.add(btnPanel, BorderLayout.SOUTH);
timer = new Timer(FAST, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
TimePeriod period = new Second();
dataset.add(period, randomValue(), SERIES1);
dataset.add(period, randomValue(), SERIES2);
if(dataset.getItemCount() > COUNT) {
TimePeriod firstItemTime = dataset.getTimePeriod(0);
dataset.remove(firstItemTime, SERIES1);
dataset.remove(firstItemTime, SERIES2);
}
}
});
}
private float randomValue() {
float randValue = (float) (random.nextGaussian() * MINMAX / 3);
return randValue < 0 ? -randValue : randValue;
}
private JFreeChart createAreaChart(final TimeTableXYDataset dataset) {
final JFreeChart chart = ChartFactory.createStackedXYAreaChart(
"Live Sentiment Chart", "Time", "Sentiments", dataset, PlotOrientation.VERTICAL, true, true, false);
final StackedXYAreaRenderer render = new StackedXYAreaRenderer();
render.setSeriesPaint(0, Color.RED);
render.setSeriesPaint(1, Color.GREEN);
DateAxis domainAxis = new DateAxis();
domainAxis.setAutoRange(true);
domainAxis.setDateFormatOverride(new SimpleDateFormat("HH:mm:ss"));
domainAxis.setTickUnit(new DateTickUnit(DateTickUnitType.SECOND, 1));
XYPlot plot = (XYPlot) chart.getPlot();
plot.setRenderer(render);
plot.setDomainAxis(domainAxis);
plot.setSeriesRenderingOrder(SeriesRenderingOrder.FORWARD);
plot.setForegroundAlpha(0.5f);
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setNumberFormatOverride(new DecimalFormat("#,###.#"));
rangeAxis.setAutoRange(true);
return chart;
}
public void start() {
timer.start();
}
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
DTSCTest demo = new DTSCTest(TITLE);
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
demo.start();
}
});
}
}

Related

Swing app freezes after a while when JFreeChart have a lot series

I'm writing a program which would display incoming data while day. It's getting data about every 600 milliseconds and adding it to the TimeSeries Chart. The problem is: after about 10 minutes of work, GUI starts freezing. But if display only few series of 33 it's become fine. So maybe I am doing something wrong?
How to solve that freezing? My SwingWorker may be weak, or chosen JFreeChart collection.
Any tips might be helpful, thank you!
My short code example:
import java.awt.event.ActionEvent;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.ChartFactory;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.data.xy.XYSeries;
import org.jfree.chart.JFreeChart;
import org.jfree.data.xy.XYDataset;
import java.awt.Dimension;
import java.awt.Component;
import javax.swing.JCheckBox;
import org.jfree.chart.ChartPanel;
import java.awt.LayoutManager;
import java.awt.BorderLayout;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import java.awt.event.ActionListener;
import java.awt.Window;
import org.jfree.chart.ui.UIUtils;
import javax.swing.JPanel;
import java.awt.Container;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Paint;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.SwingWorker;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.ui.ApplicationFrame;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
public class HideSeriesDemo1 extends ApplicationFrame {
public HideSeriesDemo1(final String title) {
super(title);
this.setContentPane(new MyDemoPanel());
}
public static JPanel createDemoPanel() {
return new MyDemoPanel();
}
public static void main(final String[] args) {
final HideSeriesDemo1 demo = new HideSeriesDemo1("JFreeChart: HideSeriesDemo1.java");
demo.pack();
UIUtils.centerFrameOnScreen(demo);
demo.setVisible(true);
}
static class MyDemoPanel extends JPanel implements ActionListener {
final JFreeChart chart;
private JPanel boxPanel;
TimeSeriesCollection seriesArray;
private XYItemRenderer renderer;
private void setLinesVisible() {
for (int i = 0; i < seriesArray.getSeriesCount(); i++) {
renderer.setSeriesVisible(i, true);
JCheckBox box = (JCheckBox) boxPanel.getComponent(i);
box.setSelected(true);
}
}
private void setLinesInvisible() {
for (int i = 0; i < seriesArray.getSeriesCount(); i++) {
renderer.setSeriesVisible(i, false);
JCheckBox box = (JCheckBox) boxPanel.getComponent(i);
box.setSelected(false);
}
}
private XYDataset createNumberedDataSet(int num) {
seriesArray = new TimeSeriesCollection();
for (int i = 0; i < num; i++) {
int num2 = i + 1;
TimeSeries s1 = new TimeSeries("Channel №" + num2);
seriesArray.addSeries(s1);
}
return seriesArray;
}
public MyDemoPanel() {
super(new BorderLayout());
final XYDataset dataset = this.createNumberedDataSet(33);
chart = this.createChart(dataset);
final ChartPanel chartPanel = new ChartPanel(chart);
boxPanel = new JPanel();
boxPanel.setLayout(new GridLayout(0, 11));
boxPanel.validate();
for (int i = 0; i < 33; i++) {
int numchik = i + 1;
JCheckBox box1 = new JCheckBox("Channel №" + numchik);
String com = "S" + numchik;
box1.setSelected(true);
box1.setActionCommand(com);
box1.addActionListener(this);
boxPanel.add(box1);
}
boxPanel.validate();
final JButton btn = new JButton("All not sellected");
btn.setVisible(true);
btn.setActionCommand("btn");
btn.addActionListener(this);
boxPanel.add(btn);
final JButton btn2 = new JButton("All sellected");
btn2.setVisible(true);
btn2.setActionCommand("btn2");
btn2.addActionListener(this);
boxPanel.add(btn2);
final JButton btn3 = new JButton("SwingWorker?");
btn3.setVisible(true);
btn3.setActionCommand("btn3");
btn3.addActionListener(this);
boxPanel.add(btn3);
this.add(chartPanel);
this.add(boxPanel, "South");
JPopupMenu pop = chartPanel.getPopupMenu();
pop.add(new JSeparator());
JMenuItem remBtn = new JMenuItem("All not selected");
remBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
setLinesInvisible();
}
});
pop.add(remBtn);
JMenuItem addBtn = new JMenuItem("All visible");
addBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
setLinesVisible();
}
});
pop.add(addBtn);
}
private JFreeChart createChart(final XYDataset dataset) {
final JFreeChart chart = ChartFactory.createTimeSeriesChart("xDisplay", "Time", "Data", dataset, true, true, false);
final XYPlot plot = (XYPlot) chart.getPlot();
this.renderer = plot.getRenderer();
return chart;
}
#Override
public void actionPerformed(final ActionEvent e) {
int series = -1;
if (e.getActionCommand().equals("btn")) {
this.setLinesInvisible();
System.out.println("set invisible btn pressed");
boxPanel.validate();
// System.out.println("btn pressed");
return;
}
if (e.getActionCommand().equals("btn2")) {
setLinesVisible();
boxPanel.validate();
System.out.println("setBtnVisible pressed");
return;
}
if (e.getActionCommand().equals("btn3")) {
System.out.println("swingworker");
MySwingWorker swi = new MySwingWorker();
swi.execute();
}
for (int i = 0; i<33;i++){
String s="S"+i;
if (e.getActionCommand().equals(s)) {
series = i-1;
}
}
if (series >= 0) {
final boolean visible = this.renderer.getItemVisible(series, 0);
this.renderer.setSeriesVisible(series, !visible);
}
}
private class MySwingWorker extends SwingWorker<Boolean, double[]> {
LinkedList<Double> fifo = new LinkedList<Double>();
public MySwingWorker() {
fifo.add(0.0);
}
#Override
protected Boolean doInBackground() {
while (!isCancelled()) {
try {
Thread.sleep(600);
} catch (InterruptedException ex) {
Logger.getLogger(HideSeriesDemo1.class.getName()).log(Level.SEVERE, null, ex);
}
fifo.add(fifo.get(fifo.size() - 1) + Math.random() - .5);
if (fifo.size() > 1000) {
fifo.removeFirst();
}
double[] array = new double[fifo.size()];
for (int i = 0; i < fifo.size(); i++) {
array[i] = fifo.get(i);
}
System.out.println(array.length + " : " + Arrays.toString(array) + "Array: ");
publish(array);
try {
Thread.sleep(5);
} catch (InterruptedException e) {
// eat it. caught when interrupt is called
System.out.println("MySwingWorker shut down." + " name:" + Thread.currentThread().getName());
}
}
return true;
}
#Override
protected void process(List<double[]> chunks) {
double[] mostRecentDataSet = chunks.get(chunks.size() - 1);
for (int i = 0; i < seriesArray.getSeriesCount(); i++) {
TimeSeries series = seriesArray.getSeries(i);
series.addOrUpdate(new Millisecond(), mostRecentDataSet[0] + i);
}
fifo.removeFirst();
System.out.println(" repaint zone " + " name:" + Thread.currentThread().getName());
}
}
}
}

How to draw a spiderchart above a existing JfreeChart

I have one a jfree chart which I can generate everytime I run the code.
Now i want to override few more spider graphs on the same chart. please help me how to do that
Above this i need to add one more spider chart using jfree.
Here is my code for doing this chart.
package com.rectrix.exide.pdfbox;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Paint;
import java.awt.PaintContext;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.ColorModel;
import javax.swing.JPanel;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.StandardCategoryToolTipGenerator;
import org.jfree.chart.plot.SpiderWebPlot;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.*;
public class DemoChart extends ApplicationFrame {
public DemoChart(String s)
{
super(s);
JPanel jpanel = createDemoPanel();
jpanel.setPreferredSize(new Dimension(500, 270));
setContentPane(jpanel);
}
private static CategoryDataset createDataset()
{
String s1 = "First";
String s2 = "Second";
String s3 = "Third";
String s4 = "Forth";
String s5 = "Fivth";
String s6 = "Sixth";
String s7 = "Seventh";
String s8 = "Eighth";
String s9 = "Ninth";
String s10 = "Tenth";
DefaultCategoryDataset defaultcategorydataset = new DefaultCategoryDataset();
int count = 5;
int value = 0;
//String keyRow="s";
for (int i=1;i<=10;i++){
value = i*4;
Comparable colKey = 0;
String keyRow = "s"+i;
for(int j=1;j<=count;j++){
colKey = j;
defaultcategorydataset.addValue(value, keyRow, colKey);
}
}
return defaultcategorydataset;
}
public static JFreeChart createChart1(CategoryDataset categorydataset,double d) {
SpiderWebPlot plot = new SpiderWebPlot(categorydataset);
Color bckColor1 = Color.decode("#4282CE"); //Light blue
Paint p = new GradientPaint(0, 1, bckColor1, 0, 1, bckColor1);
plot.setSeriesPaint(p);
JFreeChart chart = new JFreeChart("", plot);
return chart;
}
public static JPanel createDemoPanel()
{
JFreeChart jfreechart = createChart1(createDataset(), 10D);
return new ChartPanel(jfreechart);
}
public static void main(String args[])
{
DemoChart spiderwebchartdemo1 = new DemoChart("JFreeChart: SpiderWebChartDemo1.java");
spiderwebchartdemo1.pack();
RefineryUtilities.centerFrameOnScreen(spiderwebchartdemo1);
spiderwebchartdemo1.setVisible(true);
}
}
Please help me as soon as possible i need to send this build by tomorrow
Thank u in advance for helping and taking efforts to see this.
I want to override few more spider graphs on the same chart.
It may help to examine how a spider web plot is used to display multivariate data. The simplified example below compares just two OBSERVATIONS, each having five VARIABLES named A .. E, with random values in the range 1 .. 3. By chance, the values for variable B coincide; the rest differ. You can adjust the value of OBSERVATIONS to see the effect, but the result becomes progressively more muddled as the number of observations grows. You may want to alter series visibility, as suggested here, or consider these alternatives.
import java.awt.EventQueue;
import java.util.Random;
import javax.swing.JPanel;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.SpiderWebPlot;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.ApplicationFrame;
/** #see https://stackoverflow.com/a/32885067/230513 */
public class SpiderChart extends ApplicationFrame {
private static final int OBSERVATIONS = 2;
private static final int VARIABLES = 5;
private static final Random r = new Random();
public SpiderChart(String s) {
super(s);
add(createDemoPanel());
}
private static CategoryDataset createDataset() {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
for (int i = 1; i <= OBSERVATIONS; i++) {
String rowKey = "Observation " + i;
for (int j = 1; j <= VARIABLES; j++) {
Comparable colKey = Character.valueOf((char)(j+64));
dataset.addValue(r.nextInt(3) + 1, rowKey, colKey);
}
}
return dataset;
}
public static JFreeChart createChart(CategoryDataset dataset) {
SpiderWebPlot plot = new SpiderWebPlot(dataset);
JFreeChart chart = new JFreeChart("Test", plot);
return chart;
}
public static JPanel createDemoPanel() {
JFreeChart jfreechart = createChart(createDataset());
return new ChartPanel(jfreechart);
}
public static void main(String args[]) {
EventQueue.invokeLater(() -> {
SpiderChart demo = new SpiderChart("SpiderWebChart");
demo.pack();
demo.setDefaultCloseOperation(EXIT_ON_CLOSE);
demo.setVisible(true);
});
}
}

Dynamic JFreeChart at 30 second intervals

I am new in JFreeChart and new to Java also.
I have this data from our claims table:
SEQ IP_CLAIMS_RECEIVED HB_CLAIMS_RECEIVED IP_AVERAGE_RESPONSE HB_AVERAGE_RESPONSE
30 Seconds 29 19 4 4
This data every 30 seconds will change giving the amount of claims processed and with the avarage seconds it took to process this.
So my graph I want it on the Y-Axis to display the round seconds like (0,,5,10,15,20,25,30,35,40) and then on the X-Axis to display the time - the 30 seconds intervals showing the refresh times. And then the spike-lines would show the average-response times... And if it will be possible have two combined graphs one for IP Claims and another for HB Claims. I have a perfect example of the graph but its confusing me a bit here is the code of it below:
package timeseriesdemo;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.DynamicTimeSeriesCollection;
import org.jfree.data.time.Second;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
/** #see https://stackoverflow.com/questions/5048852 */
public class TimeSeriesDemo extends ApplicationFrame {
private static final String TITLE = "Dynamic Series";
private static final String START = "Start";
private static final String STOP = "Stop";
private static final float MINMAX = 100;
private static final int COUNT = 2 * 60;
private static final int FAST = 100;
private static final int SLOW = FAST * 5;
private static final Random random = new Random();
private Timer timer;
public TimeSeriesDemo(final String title) {
super(title);
final DynamicTimeSeriesCollection dataset =
new DynamicTimeSeriesCollection(1, COUNT, new Second());
dataset.setTimeBase(new Second(0, 0, 0, 1, 1, 2011));
dataset.addSeries(gaussianData(), 0, "Gaussian data");
JFreeChart chart = createChart(dataset);
final JButton run = new JButton(STOP);
run.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (STOP.equals(cmd)) {
timer.stop();
run.setText(START);
} else {
timer.start();
run.setText(STOP);
}
}
});
final JComboBox combo = new JComboBox();
combo.addItem("Fast");
combo.addItem("Slow");
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if ("Fast".equals(combo.getSelectedItem())) {
timer.setDelay(FAST);
} else {
timer.setDelay(SLOW);
}
}
});
this.add(new ChartPanel(chart), BorderLayout.CENTER);
JPanel btnPanel = new JPanel(new FlowLayout());
btnPanel.add(run);
btnPanel.add(combo);
this.add(btnPanel, BorderLayout.SOUTH);
timer = new Timer(FAST, new ActionListener() {
float[] newData = new float[1];
#Override
public void actionPerformed(ActionEvent e) {
newData[0] = randomValue();
System.out.println("dataset1 : " + dataset.advanceTime());
dataset.advanceTime();
dataset.appendData(newData);
}
});
}
private float randomValue() {
System.out.println("randomvalue : " + (float) (random.nextGaussian() * MINMAX / 3));
return (float) (random.nextGaussian() * MINMAX / 3);
}
private float[] gaussianData() {
float[] a = new float[COUNT];
for (int i = 0; i < a.length; i++) {
a[i] = randomValue();
}
return a;
}
private JFreeChart createChart(final XYDataset dataset) {
final JFreeChart result = ChartFactory.createTimeSeriesChart(
TITLE, "hh:mm:ss", "Claims Received", dataset, true, true, false);
final XYPlot plot = result.getXYPlot();
ValueAxis domain = plot.getDomainAxis();
domain.setAutoRange(true);
ValueAxis range = plot.getRangeAxis();
range.setRange(-MINMAX, MINMAX);
return result;
}
public void start() {
timer.start();
}
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
TimeSeriesDemo demo = new TimeSeriesDemo(TITLE);
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
demo.start();
}
});
}
}

JFreeChart scaling of Boxplots with several Categories

i am currently working on a java-based project using JFreeChart to display boxplots.
My Problem is how to display a chart containing boxplots for a CategoryDataset with about 20 Categories and 5+ Series.
Currently if the preferred size of the ChartPanel is not set, the Legend, Labels and Annotations are readable but the Boxplots are too small. Or the size of the ChartPanel is set so that the Boxplots have an acceptable size but then the legend, labels and annotations are horizontally stretched.
My question is, how to correctly scale the boxplots without scaling the legend, axis Labels and annotations of the Chart? Is it possible to scale the Plot without scaling all the elements of the Chart?
Code Example
import java.awt.Color;
import java.awt.Dimension;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.renderer.category.BoxAndWhiskerRenderer;
import org.jfree.data.statistics.DefaultBoxAndWhiskerCategoryDataset;
public class StretchedBoxAndWhiskerExample{
DefaultBoxAndWhiskerCategoryDataset dataset;
JFreeChart chart;
ChartPanel chartPanel;
JFrame frame;
JScrollPane scrollPane;
public StretchedBoxAndWhiskerExample() {
createCategoryBoxplot();
frame = new JFrame();
scrollPane = new JScrollPane(chartPanel);
scrollPane.setPreferredSize(new Dimension(800,700));
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
frame.add(scrollPane);
frame.pack();
frame.setVisible(true);
}
private void createCategoryBoxplot(){
dataset = createCategoryDataset();
CategoryAxis xAxis = new CategoryAxis("");
NumberAxis yAxis = new NumberAxis("Score");
BoxAndWhiskerRenderer renderer = new BoxAndWhiskerRenderer();
CategoryPlot plot = new CategoryPlot(dataset, xAxis, yAxis, renderer);
createJFreeChart(plot,"Test");
// Design
renderer.setFillBox(false);
renderer.setMeanVisible(false);
chart.setBackgroundPaint(Color.white);
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinePaint(Color.white);
plot.setDomainGridlinesVisible(true);
plot.setRangeGridlinePaint(Color.white);
plot.getRangeAxis().setRange(-10.5, 10.5);
chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(3250,600));
}
private DefaultBoxAndWhiskerCategoryDataset createCategoryDataset() {
dataset = new DefaultBoxAndWhiskerCategoryDataset();
ArrayList<Double> values = createSampleData();
ArrayList<String> categories = createSampleCategories();
for (int i=0;i<=5;i++){
for (String category : categories){
dataset.add(values,i,category);
}
}
return dataset;
}
private ArrayList<String> createSampleCategories() {
ArrayList<String> tmp = new ArrayList<String>();
for (int i=0;i<=20;i++){
tmp.add("Category"+i);
}
return tmp;
}
private ArrayList<Double> createSampleData() {
ArrayList<Double> tmp = new ArrayList<Double>();
for (int i=0;i<10;i++){
tmp.add(5.0);
tmp.add(7.0);
tmp.add(2.0);
tmp.add(4.0);
}
return tmp;
}
private void createJFreeChart(CategoryPlot plot, String title){
chart = new JFreeChart(title, plot);
}
public static void main(String[] args) throws IOException {
StretchedBoxAndWhiskerExample demo = new StretchedBoxAndWhiskerExample();
}
}
Set the preferred size of the containing ChartPanel, not the chart, as shown here and here.
Addendum: I don't think you can usefully add a chart to a scroll pane. Instead, create a class similar to SlidingCategoryDataset that implements BoxAndWhiskerCategoryDataset. Add a scroll bar to the frame that controls the first displayed index.
Addendum: A somewhat less ambitious approach is simply to page a portion of the data set using some suitable control, as shown in the example below.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.renderer.category.BoxAndWhiskerRenderer;
import org.jfree.data.statistics.DefaultBoxAndWhiskerCategoryDataset;
/** #see https://stackoverflow.com/questions/6844759 */
public class BoxAndWhiskerDemo {
private static final int COLS = 20;
private static final int VISIBLE = 4;
private static final int ROWS = 5;
private static final int VALUES = 10;
private static final Random rnd = new Random();
private List<String> columns;
private List<List<List<Double>>> data;
private DefaultBoxAndWhiskerCategoryDataset dataset;
private CategoryPlot plot;
private ChartPanel chartPanel;
private JPanel controlPanel;
private int start = 0;
public BoxAndWhiskerDemo() {
createData();
createDataset(start);
createChartPanel();
createControlPanel();
}
private void createData() {
columns = new ArrayList<String>(COLS);
data = new ArrayList<List<List<Double>>>();
for (int i = 0; i < COLS; i++) {
String name = "Category" + String.valueOf(i + 1);
columns.add(name);
List<List<Double>> list = new ArrayList<List<Double>>();
for (int j = 0; j < ROWS; j++) {
list.add(createValues());
}
data.add(list);
}
}
private List<Double> createValues() {
List<Double> list = new ArrayList<Double>();
for (int i = 0; i < VALUES; i++) {
list.add(rnd.nextGaussian());
}
return list;
}
private void createDataset(int start) {
dataset = new DefaultBoxAndWhiskerCategoryDataset();
for (int i = start; i < start + VISIBLE; i++) {
List<List<Double>> list = data.get(i);
int row = 0;
for (List<Double> values : list) {
String category = columns.get(i);
dataset.add(values, "s" + row++, category);
}
}
}
private void createChartPanel() {
CategoryAxis xAxis = new CategoryAxis("Category");
NumberAxis yAxis = new NumberAxis("Value");
BoxAndWhiskerRenderer renderer = new BoxAndWhiskerRenderer();
plot = new CategoryPlot(dataset, xAxis, yAxis, renderer);
JFreeChart chart = new JFreeChart("BoxAndWhiskerDemo", plot);
chartPanel = new ChartPanel(chart);
}
private void createControlPanel() {
controlPanel = new JPanel();
controlPanel.add(new JButton(new AbstractAction("\u22b2Prev") {
#Override
public void actionPerformed(ActionEvent e) {
start -= VISIBLE;
if (start < 0) {
start = 0;
return;
}
createDataset(start);
plot.setDataset(dataset);
}
}));
controlPanel.add(new JButton(new AbstractAction("Next\u22b3") {
#Override
public void actionPerformed(ActionEvent e) {
start += VISIBLE;
if (start > COLS - VISIBLE) {
start = COLS - VISIBLE;
return;
}
createDataset(start);
plot.setDataset(dataset);
}
}));
}
public ChartPanel getChartPanel() {
return chartPanel;
}
public JPanel getControlPanel() {
return controlPanel;
}
public static void main(String[] args) throws IOException {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BoxAndWhiskerDemo demo = new BoxAndWhiskerDemo();
frame.add(demo.getChartPanel(), BorderLayout.CENTER);
frame.add(demo.getControlPanel(), BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}

Using JFreeChart to display recent changes in a time series

How can I use JFreeChart to display just the most recent data in a continually updated time series?
Addenda: A complete, working example that incorporates the accepted answer is shown here. See also this variation having two series. See also this Q&A regarding setTimeBase().
The JFreeChart class DynamicTimeSeriesCollection is a good choice.
Addendum: As noted by #Bahadır, the last point of the series was persistently zero. #Don helpfully suggests advancing the time and then appending the data.
dataset.advanceTime();
dataset.appendData(newData);
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.DynamicTimeSeriesCollection;
import org.jfree.data.time.Second;
import org.jfree.data.xy.XYDataset;
import org.jfree.chart.ui.ApplicationFrame;
import org.jfree.chart.ui.UIUtils;
/**
* #see http://stackoverflow.com/a/15521956/230513
* #see http://stackoverflow.com/questions/5048852
*/
public class DTSCTest extends ApplicationFrame {
private static final String TITLE = "Dynamic Series";
private static final String START = "Start";
private static final String STOP = "Stop";
private static final float MINMAX = 100;
private static final int COUNT = 2 * 60;
private static final int FAST = 100;
private static final int SLOW = FAST * 5;
private static final Random random = new Random();
private Timer timer;
public DTSCTest(final String title) {
super(title);
final DynamicTimeSeriesCollection dataset =
new DynamicTimeSeriesCollection(1, COUNT, new Second());
dataset.setTimeBase(new Second(0, 0, 0, 1, 1, 2011));
dataset.addSeries(gaussianData(), 0, "Gaussian data");
JFreeChart chart = createChart(dataset);
final JButton run = new JButton(STOP);
run.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (STOP.equals(cmd)) {
timer.stop();
run.setText(START);
} else {
timer.start();
run.setText(STOP);
}
}
});
final JComboBox combo = new JComboBox();
combo.addItem("Fast");
combo.addItem("Slow");
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if ("Fast".equals(combo.getSelectedItem())) {
timer.setDelay(FAST);
} else {
timer.setDelay(SLOW);
}
}
});
this.add(new ChartPanel(chart) {
#Override
public Dimension getPreferredSize() {
return new Dimension(640, 480);
}
}, BorderLayout.CENTER);
JPanel btnPanel = new JPanel(new FlowLayout());
btnPanel.add(run);
btnPanel.add(combo);
this.add(btnPanel, BorderLayout.SOUTH);
timer = new Timer(FAST, new ActionListener() {
float[] newData = new float[1];
#Override
public void actionPerformed(ActionEvent e) {
newData[0] = randomValue();
dataset.advanceTime();
dataset.appendData(newData);
}
});
}
private float randomValue() {
return (float) (random.nextGaussian() * MINMAX / 3);
}
private float[] gaussianData() {
float[] a = new float[COUNT];
for (int i = 0; i < a.length; i++) {
a[i] = randomValue();
}
return a;
}
private JFreeChart createChart(final XYDataset dataset) {
final JFreeChart result = ChartFactory.createTimeSeriesChart(
TITLE, "hh:mm:ss", "milliVolts", dataset, true, true, false);
final XYPlot plot = result.getXYPlot();
ValueAxis domain = plot.getDomainAxis();
domain.setAutoRange(true);
ValueAxis range = plot.getRangeAxis();
range.setRange(-MINMAX, MINMAX);
return result;
}
public void start() {
timer.start();
}
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
DTSCTest demo = new DTSCTest(TITLE);
demo.pack();
UIUtils.centerFrameOnScreen(demo);
demo.setVisible(true);
demo.start();
}
});
}
}
You can also eliminate the zero by first advanceTime(), then appendData. (swap the way they are doing it in the example).
One alternative approach to #thrashgod's answer would be to use TimeSeriesCollection and setting item age on the TimeSeries. Below code can setup a graph to show last 1 hour of data with 1 minute intervals.
private TimeSeriesCollection dataset;
private TimeSeries sensorSeries;
sensorSeries = new TimeSeries("name", Minute.class);
sensorSeries.setMaximumItemAge(60);
dataset = new TimeSeriesCollection();
dataset.addSeries(sensorSeries);
..and you will add the data as it comes with:
sensorSeries.add(new Minute(new Date()), newData);

Categories