3

This is only my second post, so please forgive me if I am not following the rules correctly yet. I am trying to automatically update a line graph, which was created using the JFreeChart lib. I have been attempting this for a few days now and have referred to the api and followed many examples here, here and here.

I have a method that gets the balance of an account and sends it to another class:

public double credit(double d) 
{
    int bonus = 10;
    if (d >= 500){
        logData = "CREDITED: + £" + df.format(d) + "\n ********** Whohoo a £10.00 bonus has been added to your balance for depositing at least £500 in a single month **********\n";
        currentBalance = currentBalance + d + bonus;
        draw.passBalance(currentBalance);
        draw.paint(currentBalance); //Send balance to Draw class for the graph (CPB)
    } else {
        logData = "CREDITED: + £" + df.format(d) + "\n";
        currentBalance = currentBalance + d;
    } 
    return currentBalance;
}

The class that receives this deals with the data for the graph:

public class Draw extends ApplicationFrame {

private double balance;
private ChartPanel chartPanel;
private JFreeChart chart;
private XYDataset dataset;
private Draw graph;

    public Draw(final String title) {

        super(title);

        dataset = createDataset();
        chart = createChart(dataset);
        chartPanel = new ChartPanel(chart);
        chartPanel.setPreferredSize(new Dimension(750, 350));
        setContentPane(chartPanel);
    }

    private XYDataset createDataset() {

        final XYSeries series1 = new XYSeries("Balance");
        series1.add(1.0, balance);
        series1.add(2.0, balance);
        series1.add(3.0, 100.00);
        series1.add(4.0, 100.00);
        series1.add(5.0, 100.00);
        series1.add(6.0, 100.00);
        series1.add(7.0, 100.00);
        series1.add(8.0, 100.00);
        series1.add(9.0, 100.00);
        series1.add(10.0, 100.00);
        series1.add(11.0, 100.00);
        series1.add(12.0, 100.00);

        System.out.println(balance);

        final XYSeriesCollection dataset = new XYSeriesCollection();
        dataset.addSeries(series1);

        return dataset;
    }

    private JFreeChart createChart(final XYDataset dataset) {

      // create the chart...
      final JFreeChart chart = ChartFactory.createXYLineChart(
            "Account Balance", // chart title
            "Month", // x axis label
            "Balance", // y axis label
            dataset, // data
            PlotOrientation.VERTICAL,
            false, // include legend
            true, // tooltips
            false // urls
    );


      chart.setBackgroundPaint(Color.white);

      final XYPlot plot = chart.getXYPlot();
      plot.setBackgroundPaint(Color.white);
      plot.setDomainGridlinePaint(Color.lightGray);
      plot.setRangeGridlinePaint(Color.lightGray);

      final XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
      renderer.setSeriesLinesVisible(1, true);
      plot.setRenderer(renderer);

      return chart;

  }

    public double passBalance(double d)
    {
     return balance = d;
    }

    public void paint(double d)
    {   
        //System.out.println(balance);
        createDataset();

    }
}

It is my understanding that the chart will be redrawn since all the methods throw a SeriesChangeEvent, but this doesn't appear to be the case.

I'm relatively new to Java and would greatly appreciate any help at all!!!

Thanks

Community
  • 1
  • 1
Cristophs0n
  • 1,246
  • 3
  • 19
  • 27

1 Answers1

1

To help isolate the problem, I've reduced your code to a self-contained example that updates a single XYDataItem in an XYSeries in an XYSeriesCollection. Note that each XYDataItem encapsulates two instances of Number; each are Comparable, as required by the XYSeries; add(double x, double y) converts each to Double. Click the Update button to see the effect. Item INDEX should increase by five with each click.

enter image description here

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;

/** @see https://stackoverflow.com/a/33898324/230513 */
public class Draw extends ApplicationFrame {

    private static final int INDEX = 5;
    private final XYSeries series = new XYSeries("Balance");
    private double balance;

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            new Draw("Test");
        });
    }

    public Draw(final String title) {
        super(title);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        ChartPanel chartPanel = new ChartPanel(createChart(createDataset())) {

            @Override
            public Dimension getPreferredSize() {
                return new Dimension(640, 360);
            }
        };
        add(chartPanel);
        add(new JButton(new AbstractAction("Update") {

            @Override
            public void actionPerformed(ActionEvent e) {
                balance += 5;
                series.addOrUpdate(INDEX, balance);
            }
        }), BorderLayout.SOUTH);
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private XYDataset createDataset() {
        for (int i = 0; i < 11; i++) {
            series.add(i, 100.00);
        }
        series.remove(INDEX);
        series.add(INDEX, balance);
        final XYSeriesCollection dataset = new XYSeriesCollection();
        dataset.addSeries(series);
        return dataset;
    }

    private JFreeChart createChart(final XYDataset dataset) {
        final JFreeChart chart = ChartFactory.createXYLineChart(
            "Account Balance", // chart title
            "Month", // x axis label
            "Balance", // y axis label
            dataset, // data
            PlotOrientation.VERTICAL,
            false, // include legend
            true, // tooltips
            false // urls
        );
        return chart;
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Thank you for the timely response @trashgod. Apologies for not providing my code as a self-contained example as well - I will follow this on my next post, but I was unaware of this resource until you pointed it out. I took your example and incorporated it into my code. Now my graph is updating, albeit with somewhat erratic behaviour. I need to minimize its window for the update to occur. If I recall someone else had posted about this problem in the past [here](http://stackoverflow.com/questions/7149436/how-to-update-a-chart-in-jfreechart) – Cristophs0n Nov 24 '15 at 20:46
  • Ok so I needed to add getContentPane().removeAll(); and chartPanel.revalidate(); to get the window to update properly. Thanks for your help. I'm going to accept this answer. – Cristophs0n Nov 24 '15 at 20:48
  • 1
    Yes, that will work; but updating _in situ_ should work, too. Regarding _erratic_, don't neglect to invoke [`EventQueue.invokeLater()`](https://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html). – trashgod Nov 24 '15 at 21:22