Higeath
Higeath

Reputation: 561

Number axis setTickUnit to contain a specified number

I am displaying normal distribution using JFreeChart, and I change the tick number to standard deviation; but I would also want there to always be 'mean' value in the middle from which ticks emerge. Cross-posted here.

So standard deviation = 2 ; mean = 1

-3 -1  1 3 5

Standard deviation = 5 ; mean = 15

0 5 10 15 20 25 30

JFreeChart.java

public class JFreeChartPanel extends JPanel {
    private final XYPlot plot;
    double mean = 0.0, sd = 1.0;
    XYDataset dataset = initDataset();
    NumberAxis domain = new NumberAxis("Y") {
    @Override
    protected double calculateLowestVisibleTickValue() {
        double lowTickValue = super.calculateLowestVisibleTickValue();
        if (mean % 2 == 1) {
            return lowTickValue + 1;
        } else {
            return lowTickValue;
        }
    }
};
    public JFreeChartPanel(){
        JFreeChart chart = ChartFactory.createXYLineChart(
            "Normal Distribution",
            "X", 
            "PDF", 
            dataset,
            PlotOrientation.VERTICAL,
            false,
            false,
            false
        );
        plot=chart.getXYPlot();
        domain.setAutoRangeStickyZero(false);
        domain.setTickUnit(new NumberTickUnit(sd));
        plot.setDomainAxis(domain);
        final ChartPanel chartPanel = new ChartPanel(chart);
        setLayout(new BorderLayout());
        add(chartPanel);
    }

    private XYDataset initDataset() {
        double minX=mean-(4*sd),maxX=mean+(4*sd);
        Function2D normal = new NormalDistributionFunction2D(mean, sd);
        XYDataset dataset = DatasetUtilities.sampleFunction2D(normal, minX, maxX, 100, "Normal");
        return dataset;
    }

    public double getMean() {
        return mean;
    }

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

    public double getSd() {
        return sd;
    }

    public void setSd(double sd) {
        this.sd = sd;
        domain.setTickUnit(new NumberTickUnit(sd));
        plot.setDataset(initDataset());
    }
}

UI.java

public class UI extends javax.swing.JFrame {

    public UI() {
        initComponents();
    }

    @SuppressWarnings("unchecked")
    private void initComponents() {
      Auto-generated Netbeans GUI COde
    }                     

    public void updateMean()
    {
        try{
            double m = Double.parseDouble(mean.getText());
            jFreeChartPanel.setMean(m);
        }catch(Exception e){
        }
    }
    public void updateSd()
    {
        try{
            double sd = Double.parseDouble(standardDeviation.getText());
            jFreeChartPanel.setSd(sd);
        }catch(Exception e){
        }
    }

    public static void main(String args[]) {
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Windows".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {

        }
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new UI().setVisible(true);
            }
        });
    }

    private javax.swing.JPanel inputPanel;
    private main.JFreeChartPanel jFreeChartPanel;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JToggleButton jToggleButton1;
    private javax.swing.JTextField mean;
    private javax.swing.JLabel meanLabel;
    private javax.swing.JTextField standardDeviation;
    private javax.swing.JLabel standardDeviationLabel;
}

Upvotes: 2

Views: 1109

Answers (1)

trashgod
trashgod

Reputation: 205875

Starting from this example, I made the following changes, adapted from yours, to get the result illustrated below for µ=15 and σ=5:

import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
…
private double mean = 15.0, sigma = 5.0;
…
private XYDataset initDataset() {
    double minX = mean - (3 * sigma), maxX = mean + (3 * sigma);
    Function2D normal = new NormalDistributionFunction2D(mean, sigma);
    XYDataset dataset = DatasetUtilities.sampleFunction2D(normal, minX, maxX, 100, "Normal");
    return dataset;
}
…
public JFreeChartPanel() {
    …
    plot = chart.getXYPlot();
    NumberAxis domain = (NumberAxis) plot.getDomainAxis();
    domain.setTickUnit(new NumberTickUnit(sigma));
    …
}

µ=15; σ=5

Your other case, µ=1 and σ=2, requires overriding the NumberAxis method calculateLowestVisibleTickValue() to make ticks fall on odd values.

NumberAxis domain = new NumberAxis("Y") {
    @Override
    protected double calculateLowestVisibleTickValue() {
        double lowTickValue = super.calculateLowestVisibleTickValue();
        if (mean % 2 == 1) {
            return lowTickValue + 1;
        } else {
            return lowTickValue;
        }
    }
};
domain.setTickUnit(new NumberTickUnit(sigma));
plot = chart.getXYPlot();
plot.setDomainAxis(domain);

µ=1; σ=2

Why [is] the graph is slightly skewed for mean 3 and sd 1 also for mean 6 sd 2, mean 9 sd 3 and so on; here is a picture showing this.

As discussed here, there's "A flag that affects the size of the margins added to the axis range when the range is determined automatically."

domain.setAutoRangeStickyZero(false);

I've added…code.

Adding and instance of your revision 6 JFreeChartPanel to a JFrame with µ=1 and σ=2 produces the following result:

enter image description here

This happens with higher mean.

This

You can exclude zero from the auto-range.

exclude zero

domain.setAutoRangeIncludesZero(false);

Upvotes: 2

Related Questions