Nikos Nikos - 27 days ago 11
Java Question

jfreechart xylinechart sorting times isn't updated

I'm making a simple sorting benchmark in Java Swing and I want it to display a graph that changes with time. But the graph is not updating when the algorithm runs. I'm really confused. Can someone please explain what I'm doing wrong?

The array is filled with random data when the GUI is running

int A[]=null;int [] copyOfA=null;


chart

final XYSeriesCollection dataset = new XYSeriesCollection();
private ChartPanel createDemoPanel() {
JFreeChart jfreechart = ChartFactory.createXYLineChart(title, "array", "time",dataset ,
PlotOrientation.VERTICAL, true, true, false);
jfreechart.setBackgroundPaint(Color.white);
XYPlot plot = (XYPlot) jfreechart.getPlot();
plot.getDomainAxis().setRange(0, 1000); //array
plot.getRangeAxis().setRange(-1,1);//time

//plot.getDomainAxis().setFixedAutoRange(20);
//plot.getRangeAxis().setFixedAutoRange(100);
// render shapes and lines
XYLineAndShapeRenderer renderer =
new XYLineAndShapeRenderer(true, true);
plot.setRenderer(renderer);
renderer.setBaseShapesVisible(true);
renderer.setBaseShapesFilled(true);

return new ChartPanel(jfreechart);
}


inside ActionPerformed

private void insSortActionPerformed(java.awt.event.ActionEvent evt) {
XYSeries series = new XYSeries("ins sort");

if( insSort.isEnabled()) {

long startTime = System.currentTimeMillis();
insSort(A);
long endTime = System.currentTimeMillis();
totalRuntime += (endTime - startTime);
}

series.add(totalRuntime,A.length);
dataset.addSeries(series);
}

Answer

At this line the Y axis range is set to (-1,1) interval:

plot.getDomainAxis().setRange(0, 1000); //array
plot.getRangeAxis().setRange(-1,1);//time

But Y axis is intended to take the value from totalRuntime which is a time difference given in millis:

if( insSort.isEnabled()) {
   long startTime = System.currentTimeMillis();
   insSort(A);
   long endTime = System.currentTimeMillis();
   totalRuntime += (endTime - startTime); // this is certainly > 1
}
series.add(totalRuntime,A.length);
dataset.addSeries(series); 

This value will be certainly > 1 (unless you have the most powerful computer ever :). So you can see which value is getting totalRuntime and adjust the Y axis range accordingly.

You might also check:

  • Domain axis range: if the array has more than 1000 elements then you won't see the graphic either.
  • Is insSort.isEnabled() actually true? If not so then you'll be adding garbage to dataset.

Addendum

I want to graph sorting time versus the number of elements

Well you can take a look to the example below. As I haven't the sort methods implementation the example emulates the times using Swing timer. The key is adding the values to the series properly and having the right ranges set.

Note: as times are random generated then the shown info is garbage. The example tries to illustrate the process you should follow to make the graphic work. Pay special attention to fillChart() method: it makes the trick.

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class Demo {

    private final XYSeries _timeSeries = new XYSeries("Time Series");
    boolean _shouldPaint;

    private void createAndShowGUI() {

        JToggleButton fillChart = new JToggleButton("Fill chart") ;
        fillChart.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JToggleButton toggleButton = (JToggleButton)e.getSource();
                if(toggleButton.isSelected()) {
                    _timeSeries.clear();
                    _shouldPaint = true;
                    fillChart();
                } else {
                    _shouldPaint = false;
                }
            }
        });

        JPanel content = new JPanel(new BorderLayout());
        content.add(getFreeChartPanel(), BorderLayout.CENTER);
        content.add(fillChart, BorderLayout.SOUTH);

        JFrame frame = new JFrame("Demo");      
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.getContentPane().add(content);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private JPanel getFreeChartPanel() {
        String title = "Time series example";

        XYSeriesCollection dataset = new XYSeriesCollection();
        dataset.addSeries(_timeSeries); // series is added only once!

        JFreeChart chart = ChartFactory.createXYLineChart(title, "Array elements", "Time (in millis)", dataset, 
                                                         PlotOrientation.VERTICAL, true, true, false);       
        XYPlot plot = chart.getXYPlot();
        plot.setRenderer(new XYLineAndShapeRenderer(true, true));
        plot.setDomainCrosshairVisible(true);
        plot.setRangeCrosshairVisible(true);
        plot.getDomainAxis().setRange(0, 1000); // Number of elements - top visible: 1000
        plot.getRangeAxis().setRange(0, 4000); // Time employed to do the sort - top visible: 4 seconds (4k millis)        

        return new ChartPanel(chart);
    }

    /**
     * You should do your own implementation of this method.
     */
    private void fillChart() {
        Timer timer = new Timer(500, new ActionListener() {

            long lastTimeMillis = System.currentTimeMillis();
            int domainAxis = 0;

            @Override
            public void actionPerformed(ActionEvent e) {
                if(_shouldPaint) {
                    long currentTimeMillis = System.currentTimeMillis();
                    long rangeAxisValue = (long)((currentTimeMillis - lastTimeMillis) * Math.random());
                    int domainAxisValue = domainAxis + 100;

                    _timeSeries.add(domainAxisValue, rangeAxisValue);
                    // Note this is the unique line that has an effect on the graphic

                    lastTimeMillis = currentTimeMillis;
                    domainAxis = domainAxisValue;

                } else {
                    Timer timer = (Timer)e.getSource();
                    timer.stop();
                }
            }
        });

        timer.setDelay(1500);
        timer.start();
    }

    public static void main(String[] args) {   
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Demo().createAndShowGUI();
            }
        });
    }    
}

Picture

enter image description here