Java tutorial
/* 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 edu.gmu.cs.sim.util.media.chart; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import edu.gmu.cs.sim.util.gui.DisclosurePanel; import edu.gmu.cs.sim.util.gui.LabelledList; import org.jfree.chart.ChartFactory; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.renderer.xy.StandardXYBarPainter; import org.jfree.chart.renderer.xy.XYBarRenderer; import org.jfree.data.general.SeriesChangeListener; import org.jfree.data.statistics.HistogramDataset; import org.jfree.data.statistics.HistogramType; // From JFreeChart // from iText (www.lowagie.com/iText/) /* // 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; } }