2

I have a class that extends JPanel for JFreeChart. Inside of setMean(), I tried updating values of dataset or just the Function2D, but nothing changes on the graph even with repaint().

    public class JFreeChartPanel extends JPanel {
        Function2D normal = new NormalDistributionFunction2D(0.0, 3.0);
        XYDataset dataset = DatasetUtilities.sampleFunction2D(normal, -5.0, 5.0, 100, "Normal");

        double mean = 0.0, std = 1.0;

        public double getMean() {
            return mean;
        }

        public void setMean(double mean) {
            this.mean = mean;
            normal = new NormalDistributionFunction2D(mean,std);
            dataset = DatasetUtilities.sampleFunction2D(normal, -5.0, 5.0, 100, "Normal");
            repaint();
        }

        public double getStd() {
            return std;
        }

        public void setStd(double std) {
            this.std = std;
        }

        public JFreeChartPanel(){        

            JFreeChart chart = ChartFactory.createXYLineChart(
                "Normal Distribution",
                "X", 
                "Y", 
                dataset,
                PlotOrientation.VERTICAL,
                true,
                true,
                false
            );


            final ChartPanel chartPanel = new ChartPanel(chart);
            setLayout(new BorderLayout());
            add(chartPanel);
        }
}

And this is executed everytime I change the value in my JTextField.

public void updateMean()
    {
        String meanS = mean.getText();
        double mean = 0.0;
        try{
            mean = Double.parseDouble(meanS);
            System.out.println("Mean: "+mean);
            jFreeChartPanel.setMean(mean);
        }catch(Exception e){
            System.out.println("Mean: incorrect input");
        }
    }
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
Higeath
  • 541
  • 5
  • 20
  • You change the values held by dataset but you never change the JFreeChart chart, and it's not going to magically change by itself. I don't use JFreeChart, but you're going to have to check the API to see if you either can call a method on the displayed chart or if you have to create a new one with the new data. – Hovercraft Full Of Eels Oct 20 '16 at 20:18
  • @HovercraftFullOfEels As far as I've read JFreeChart has a ton of listeners so any changes should automatically be reflected on the graph. – Higeath Oct 20 '16 at 20:22
  • You don't understand how listeners work -- you have to set them up, wire them for them to function. Yes, you create a JFreeChart object using the dataset object, but again, simply changing dataset later will have no effect on the JFreeChart object. JFreeChart objects have a *model*, and if this model has listeners, and you make changes to the model using appropriate setter methods, methods that trip the listener, I could understand your expectations, but you don't. You're creating a completely new dataset object, and so there's no way that that could conceivably work as you assume it should. – Hovercraft Full Of Eels Oct 20 '16 at 20:26
  • 1
    For example, assume that the XYDataset object is wired into the JFreeChart object as its model (again, I don't use JFreeChart, and so this probably isn't so, but just assume that it is), then perhaps calling a method that changes its state might work, but again **you're creating a completely new XYDataset object**, so even if it were wired in as a listener, your new object can not cause any change in the JFreeChart object. – Hovercraft Full Of Eels Oct 20 '16 at 20:29
  • Found a duplicate on changing the chart series after data has been changed. Check out [TrashGod's answer](http://stackoverflow.com/a/6206616/522444) in particular. – Hovercraft Full Of Eels Oct 20 '16 at 20:38
  • Also, please have a look at [these similar questions](https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=site:stackoverflow.com+java+jfreechart+change+dataset) that can be found on this site. – Hovercraft Full Of Eels Oct 20 '16 at 20:40
  • @HovercraftFullOfEels I have went through all of those questions before asking here, I only create new objects because I went through documentation and there are no methods to implicitly change the data. – Higeath Oct 20 '16 at 20:55
  • Perhaps you want to use a DefaultIntervalXYDataset as your dataset as it allows for changing of the data with listeners. – Hovercraft Full Of Eels Oct 20 '16 at 21:08
  • 1
    @HovercraftFullOfEels is correct about _replacing_ the dataset, as suggested [below](http://stackoverflow.com/a/40167139/230513). – trashgod Oct 21 '16 at 02:02

1 Answers1

4

Ordinarily, you could simply update the XYDataset used to create the JFreeChart, and the listening chart would update itself in response. As @Hovercraft notes, repaint() alone is not sufficient to tell the chart's plot that you have replaced the dataset. In the example below, I've refactored the dataset's initialization and passed it to setDataset() as a parameter.

public void setMean(double mean) {
    this.mean = mean;
    plot.setDataset(initDataset());
}

See the relevant source to examine the event wiring. A ChangeListener added to a JSpinner may be easier to operate than a JTextField.

image

import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.event.ChangeEvent;
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.data.function.Function2D;
import org.jfree.data.function.NormalDistributionFunction2D;
import org.jfree.data.general.DatasetUtilities;
import org.jfree.data.xy.XYDataset;

/**
 * @see https://stackoverflow.com/a/40167139/230513
 */
public class TestDistribution {

    private static class JFreeChartPanel extends JPanel {

        private XYPlot plot;
        private double mean = 0.0, sigma = 1.0;
        XYDataset dataset = initDataset();

        private XYDataset initDataset() {
            Function2D normal = new NormalDistributionFunction2D(mean, sigma);
            XYDataset dataset = DatasetUtilities.sampleFunction2D(normal, -5.0, 5.0, 100, "Normal");
            return dataset;
        }

        ;
        public double getMean() {
            return mean;
        }

        public void setMean(double mean) {
            this.mean = mean;
            plot.setDataset(initDataset());
        }

        public double getStd() {
            return sigma;
        }

        public void setStd(double sigma) {
            this.sigma = sigma;
        }

        public JFreeChartPanel() {
            JFreeChart chart = ChartFactory.createXYLineChart(
                "Normal Distribution", "X", "Y", dataset,
                PlotOrientation.VERTICAL, true, true, false
            );
            plot = chart.getXYPlot();
            final ChartPanel chartPanel = new ChartPanel(chart);
            add(chartPanel);
        }
    }

    private void display() {
        JFrame f = new JFrame("TestDistribution");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JFreeChartPanel chartPanel = new JFreeChartPanel();
        f.add(chartPanel);
        JSpinner spinner = new JSpinner();
        spinner.setValue(chartPanel.mean);
        spinner.addChangeListener((ChangeEvent e) -> {
            JSpinner s = (JSpinner) e.getSource();
            Number n = (Number) s.getValue();
            chartPanel.setMean(n.doubleValue());
        });
        f.add(spinner, BorderLayout.PAGE_END);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new TestDistribution()::display);
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • A related event chain is examined [here](http://stackoverflow.com/a/6206616/230513). – trashgod Oct 21 '16 at 09:53
  • If you don't mind I have one question is there an easy way to change tickUnits for my x-axis? Since it is using ValueAxis instead of NumberAxis I cannot access setTickUnit – Higeath Oct 21 '16 at 12:28
  • `ChartFactory.createXYLineChart()` uses `NumberAxis` internally, so you can cast; the new question is examined [here](http://stackoverflow.com/q/40184461/230513). – trashgod Oct 23 '16 at 11:19