sim.util.media.chart.HistogramGenerator.java Source code

Java tutorial

Introduction

Here is the source code for sim.util.media.chart.HistogramGenerator.java

Source

/*
  Copyright 2006 by Sean Luke and George Mason University
  Licensed under the Academic Free License version 3.0
  See the file "LICENSE" for more information
*/

package sim.util.media.chart;

import java.awt.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.*;

import sim.util.gui.*;

// From JFreeChart
import org.jfree.chart.*;
import org.jfree.chart.plot.*;
import org.jfree.data.general.*;
import org.jfree.data.statistics.*;
import org.jfree.chart.renderer.xy.*;

// from iText (www.lowagie.com/iText/)
import com.lowagie.text.*;
import com.lowagie.text.pdf.*;

/*  // looks like we'll have to move to these soon
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
*/

/**
   HistogramGenerator is a ChartGenerator which displays a histogram using the JFreeChart library.
   The generator uses the HistoramDataset as its dataset, which holds histogram elements consisting of
   a name, an array of doubles (the samples), and an integer (the number of bins).  
   representing a time series displayed on the chart.  You add series to the generator with the <tt>addSeries</tt>
   method.
       
   <p>HistogramGenerator creates attributes components in the form of HistogramSeriesAttributes, which work with
   the generator to properly update the chart to reflect changes the user has made to its display.
*/

public class HistogramGenerator extends XYChartGenerator {
    HistogramType histogramType = HistogramType.FREQUENCY;

    public void removeSeries(int index) {
        super.removeSeries(index);
        update();
    }

    public void moveSeries(int index, boolean up) {
        super.moveSeries(index, up);
        update();
    }

    protected void buildChart() {
        HistogramDataset dataset = new HistogramDataset();
        dataset.setType(HistogramType.FREQUENCY); // when buildChart() is called, histogramType hasn't been set yet.

        chart = ChartFactory.createHistogram("Untitled Chart", "Untitled X Axis", "Untitled Y Axis", dataset,
                PlotOrientation.VERTICAL, false, true, false);
        chart.setAntiAlias(true);
        //chartPanel = new ScrollableChartPanel(chart, true);         
        chartPanel = buildChartPanel(chart);
        setChartPanel(chartPanel);
        //chartHolder.getViewport().setView(chartPanel);
        ((XYBarRenderer) (chart.getXYPlot().getRenderer())).setShadowVisible(false);
        ((XYBarRenderer) (chart.getXYPlot().getRenderer())).setBarPainter(new StandardXYBarPainter());

        // this must come last because the chart must exist for us to set its dataset
        setSeriesDataset(dataset);
    }

    protected void update() {
        // We have to rebuild the dataset from scratch (deleting and replacing it) because JFreeChart's
        // histogram facility doesn't have a way to remove or move elements.  Stupid stupid stupid.

        SeriesAttributes[] sa = getSeriesAttributes();
        HistogramDataset dataset = new HistogramDataset();
        dataset.setType(histogramType);

        for (int i = 0; i < sa.length; i++) {
            HistogramSeriesAttributes attributes = (HistogramSeriesAttributes) (sa[i]);
            dataset.addSeries(new UniqueString(attributes.getSeriesName()), attributes.getValues(),
                    attributes.getNumBins());
        }

        setSeriesDataset(dataset);
    }

    public HistogramGenerator() {
        // buildChart is called by super() first

        LabelledList list = new LabelledList("Show Histogram...");
        DisclosurePanel pan1 = new DisclosurePanel("Show Histogram...", list);

        final HistogramType[] styles = new HistogramType[] { HistogramType.FREQUENCY,
                HistogramType.RELATIVE_FREQUENCY, HistogramType.SCALE_AREA_TO_1 };
        final JComboBox style = new JComboBox(
                new String[] { "By Frequency", "By Relative Frequency", "With Area = 1.0" });
        style.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                histogramType = styles[style.getSelectedIndex()];
                HistogramDataset dataset = (HistogramDataset) (getSeriesDataset());
                dataset.setType(histogramType);
            }
        });
        list.add(style);
        addGlobalAttribute(pan1);
    }

    /** Adds a series, plus a (possibly null) SeriesChangeListener which will receive a <i>single</i>
    event if/when the series is deleted from the chart by the user. Returns the series attributes. */
    public SeriesAttributes addSeries(double[] vals, int bins, String name, SeriesChangeListener stopper) {
        if (vals == null || vals.length == 0)
            vals = new double[] { 0 }; // ya gotta have at least one val
        HistogramDataset dataset = (HistogramDataset) (getSeriesDataset());
        int i = dataset.getSeriesCount();
        dataset.setType(histogramType); // It looks like the histograms reset
        dataset.addSeries(new UniqueString(name), vals, bins);

        // need to have added the dataset BEFORE calling this since it'll try to change the name of the series
        HistogramSeriesAttributes csa = new HistogramSeriesAttributes(this, name, i, vals, bins, stopper);
        seriesAttributes.add(csa);

        revalidate(); // display the new series panel
        update();

        // won't update properly unless I force it here by letting all the existing scheduled events to go through.  Dumb design.  :-(
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                update();
            }
        });

        return csa;
    }

    public void updateSeries(int index, double[] vals) {
        if (index < 0) // this happens when we're a dead chart but the inspector doesn't know
            return;

        if (index >= getNumSeriesAttributes()) // this can happen when we close a window if we use the Histogram in a display
            return;

        if (vals == null || vals.length == 0)
            vals = new double[] { 0 }; // ya gotta have at least one val
        HistogramSeriesAttributes hsa = (HistogramSeriesAttributes) (getSeriesAttribute(index));
        hsa.setValues(vals);
    }

    public void setHistogramType(HistogramType type) {
        histogramType = type;
    }

    public HistogramType getHistogramType() {
        return histogramType;
    }
}