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

Java tutorial

Introduction

Here is the source code for sim.util.media.chart.HistogramSeriesAttributes.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 javax.swing.*;
import javax.swing.border.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import sim.util.gui.*;

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

/** A SeriesAttributes used for user control of histogram series created with HistogramGenerator.
Unfortunately JFreeChart doesn't have nearly
as well-designed a histogram chart facility as its time series charts.  There is no HistogramSeries object to
encapsulate a series, and no facilities for deleting or moving series relative to one another.  
*/

public class HistogramSeriesAttributes extends SeriesAttributes {
    double[] values;

    public double[] getValues() {
        return values;
    }

    public void setValues(double[] vals) {
        if (vals != null)
            vals = (double[]) (vals.clone());
        values = vals;
    }

    /** Border thickness */
    float thickness;
    NumberTextField thicknessField;
    /** The color of the histogram bar. */
    Color fillColor;
    ColorWell fillColorWell;
    /** The color of the histogram bar border. */
    Color strokeColor;
    ColorWell strokeColorWell;
    /** The opacity of the histogram bar.  Sadly this must be separate than the color because
    Sun doesn't have a proper color selector.  */
    double fillOpacity;
    NumberTextField fillOpacityField;

    /** The opacity of the histogram bar border.  Sadly this must be separate than the color because
    Sun doesn't have a proper color selector.  */
    double lineOpacity;
    NumberTextField lineOpacityField;
    NumberTextField numBinsField;

    public void setFillOpacity(double value) {
        fillOpacityField.setValue(fillOpacityField.newValue(value));
    }

    public double getFillOpacity() {
        return fillOpacityField.getValue();
    }

    public void setStrokeOpacity(double value) {
        lineOpacityField.setValue(lineOpacityField.newValue(value));
    }

    public double getStrokeOpacity() {
        return lineOpacityField.getValue();
    }

    public void setThickness(double value) {
        thicknessField.setValue(thicknessField.newValue(value));
    }

    public double getThickness() {
        return (double) (thicknessField.getValue());
    }

    // we need to store numBins here so update() gets it properly, see later
    int numBins;

    public void setNumBins(int value) {
        numBinsField.setValue(numBinsField.newValue(value));
        numBins = (int) (numBinsField.getValue());
    }

    public int getNumBins() {
        return numBins;
    }

    public void setFillColor(Color value) {
        fillColorWell.setColor(fillColor = value);
    }

    public Color getFillColor() {
        return fillColor;
    }

    public void setStrokeColor(Color value) {
        strokeColorWell.setColor(strokeColor = value);
    }

    public Color getStrokeColor() {
        return strokeColor;
    }

    /** Produces a HistogramSeriesAttributes object with the given generator, series name, series index,
    and desire to display margin options. */
    public HistogramSeriesAttributes(ChartGenerator generator, String name, int index, double[] values, int bins,
            SeriesChangeListener stoppable) // , boolean includeMargin)
    {
        super(generator, name, index, stoppable);
        setValues(values);
        super.setSeriesName(name); // just set the name, don't update
        numBins = bins;
        numBinsField.setValue(bins); // otherwise it'd call newValue(), which would in turn try to update the series, which hasn't been made yet
        numBinsField.setInitialValue(bins); // make this the default
    }

    /** It's very expensive to call this function (O(n)) because JFreeChart has no way of changing the
    name of a histogram dataset series, and so we must rebuild all of it from scratch. */
    public void setSeriesName(String val) {
        super.setSeriesName(val); // call this first to set it
        ((HistogramGenerator) generator).update();
    }

    public void rebuildGraphicsDefinitions() {
        XYBarRenderer renderer = (XYBarRenderer) (((XYPlot) getPlot()).getRenderer());

        if (thickness == 0.0)
            renderer.setDrawBarOutline(false);
        else {
            renderer.setSeriesOutlineStroke(getSeriesIndex(), new BasicStroke(thickness));
            renderer.setDrawBarOutline(true);
        }

        renderer.setSeriesPaint(getSeriesIndex(), reviseColor(fillColor, fillOpacity));
        renderer.setSeriesOutlinePaint(getSeriesIndex(), reviseColor(strokeColor, lineOpacity));
        repaint();
    }

    static final int DEFAULT_BINS = 8; // to have enough space  -- it'll get changed soon

    public void buildAttributes() {
        // The following three variables aren't defined until AFTER construction if
        // you just define them above.  So we define them below here instead.
        thickness = 2.0f;
        fillOpacity = 1.0;
        lineOpacity = 1.0;

        numBinsField = new NumberTextField("", DEFAULT_BINS, true) {
            public double newValue(double newValue) {
                newValue = (int) newValue;
                if (newValue < 1)
                    newValue = currentValue;

                // we now set the number of bins directly so update() gets it when it calls getNumBins()
                numBins = (int) newValue;
                ((HistogramGenerator) generator).update();
                return newValue;
            }
        };
        addLabelled("Bins", numBinsField);

        // NOTES:
        // fillColor = (Color)((((XYPlot)getPlot()).getRenderer()).getSeriesPaint(getSeriesIndex()));
        // this returns null, cause getSeriesPaint returns whatever was set through setSeriesPaint;
        // for the default colors, you need "lookupSeriesPaint()".
        // fillColor = (Color) ((((XYPlot)getPlot()).getRenderer()).lookupSeriesPaint(getSeriesIndex()));
        // getRenderer returns an object implementing the XYItemRenderer interface.
        // either you cast that object to AbstractRenderer, and call lookupSeriesPaint()
        // or you call getItemPaint() on it directly; all getItemPaint does is call lookupSeriesPaint(),
        // but that looks bad, cause getItemPaint() seems to be meant for category data).
        // On the other hand, lookupSeriesPaint() does not show up before 1.0.6, so 
        // in the interest of backward compatibility:
        fillColor = (Color) ((((XYPlot) getPlot()).getRenderer()).getItemPaint(getSeriesIndex(), -1));
        // second argument does not matter

        fillColor = (Color) ((((XYPlot) getPlot()).getRenderer()).getSeriesPaint(getSeriesIndex()));
        fillColorWell = new ColorWell(fillColor) {
            public Color changeColor(Color c) {
                fillColor = c;
                rebuildGraphicsDefinitions();
                return c;
            }
        };

        addLabelled("Fill", fillColorWell);

        fillOpacityField = new NumberTextField("Opacity ", fillOpacity, 1.0, 0.125) {
            public double newValue(double newValue) {
                if (newValue < 0.0 || newValue > 1.0)
                    newValue = currentValue;
                fillOpacity = (float) newValue;
                rebuildGraphicsDefinitions();
                return newValue;
            }
        };
        addLabelled("", fillOpacityField);

        strokeColor = Color.black;
        strokeColorWell = new ColorWell(strokeColor) {
            public Color changeColor(Color c) {
                strokeColor = c;
                rebuildGraphicsDefinitions();
                return c;
            }
        };

        addLabelled("Line", strokeColorWell);

        lineOpacityField = new NumberTextField("Opacity ", lineOpacity, 1.0, 0.125) {
            public double newValue(double newValue) {
                if (newValue < 0.0 || newValue > 1.0)
                    newValue = currentValue;
                lineOpacity = (float) newValue;
                rebuildGraphicsDefinitions();
                return newValue;
            }
        };
        addLabelled("", lineOpacityField);

        thicknessField = new NumberTextField("Width ", thickness, false) {
            public double newValue(double newValue) {
                if (newValue < 0.0)
                    newValue = currentValue;
                thickness = (float) newValue;
                rebuildGraphicsDefinitions();
                return newValue;
            }
        };
        addLabelled("", thicknessField);
    }
}