| In this section we look at adding graphics to histograms. See Chapter 
              3: Tech : Histograms and Chapter 
              4 : Tech : More Histograms for earlier discussions of histogramming. 
             To simplify our histogram class hierarchy, we start with a new 
              base Histogram 
              class (code also shown below) that combines 
              the attributes and methods of the earlier BasicHist 
              and BetterHist 
              classes, which we created to illustrate class and inheritance concepts. 
              We added several new methods to our histogram to get or set various 
              values describing the histogram. We will extend Histogram 
              with various subclasses later. (See Chapter 
              8: Tech. Also, the Chapter 
              8: Tech : Refactoring section talks about reorganization of 
              classes as we did here.) For our display of histograms we create the HistPanel class. This class 
              extends PlotPanel 
              and overrides its PaintContents() 
              method to draw the histogram graph. (See the Starting 
              to Plot section for an explanation of how to use PlotPanel.) 
              The class takes a Histogram 
              object in the constructor. A new histogram can replace the current 
              one with the setHistgram(Histogram hist) method. 
             We will use this histogramming panel in several demonstration projects 
              in the course.   
              
                 
                 
                  |  
                      
                      
                      DrawHistApplet.java 
                        - create an instance of the Histogram class and fill it 
                        with values chosen from a Gaussian random number generator. 
                        Then create an instance of HistPanel and add it to the 
                        content pane.
 + New classes:
 
 HistPanel.java 
                        - PlotPanel subclass that displays instances of Histogram. 
                        It draws retangles to represent the bin values as columns. 
                        The PlotPanel methods provide the scale information, axes 
                        labeling. title, etc.
 
 Histogram.java 
                        - our new histogram base class combines the previous 
                        BasicHist 
                        and BetterHist 
                        classes. It includes the basics of histograms such as 
                        bin array, over/under flow variables, etc. In subsequent 
                        chapters we will create subclasses of this class with 
                        additional capabilities.
 
 + Previous classes:
 Chapter 
                        6: Tech: PlotPanel.java, 
                        PlotFormat.java
 
 |   
                  | Java Techniques 
                      & Other Programming Notes   
                      The Graphics 
                        class methods use integer values for the drawing positions 
                        and dimensions.When coordinates depend on floating point 
                        calculations there will be  round off errors. These 
                        errors can build up in a series of drawing commands that 
                        sum rounded off values. In the paintBars() method in HistPanel 
                        we reduce the effect by using floating point values to 
                        do the position computations before casting to the integer 
                        values. 
 
Java2D 
                        methods offer the option of using floating-point values 
                        to reduce the round off problem.
 
The HistPanel 
                        class properties include a number of variables for the 
                        display settings such as the colors of the frame and so 
                        forth. Additional getter/setter methods could be added 
                        to allow for access and modifications to these variables.   |   
                  |  import 
                      javax.swing.*;import java.awt.*;
 import java.awt.event.*;
 import java.util.*;
 
 /**
 *  Create an instance of Histogram, 
                      add a Gaussian generated
 *  distribution of data to it and 
                      display it.
 **/
 public class DrawHistApplet extends JApplet
 {
 Histogram fHistogram = null;
 
 public void init ()  {
 
 Container content_pane = getContentPane 
                      ();
 
 // Create a histogram with Gaussian 
                      distribution.
 makeHist ();
 
 // Create an instance of a JPanel 
                      sub-class
 HistPanel hist_panel = new HistPanel 
                      (fHistogram);
 
 // And add one or more panels to 
                      the JApplet panel.
 content_pane.add (hist_panel);
 
 } // init
 
 /**
 *  Create the histogram 
                      and a set of data drawn
 *  from a Gaussian random 
                      number generator.
 **/
 void makeHist () {
 // Create an instance of the Random 
                      class for
 // producing our random values.
 java.util.Random r = new java.util.Random 
                      ();
 
 // Them method nextGaussian in the 
                      class Random produces
 // a value centered at 0.0 and a 
                      standard deviation
 // of 1.0.
 
 // Create an instance of our basic 
                      gHistogram class.
 // Make it wide enough enough to 
                      include most of the
 // gaussian values.
 fHistogram = new Histogram ("Gaussian 
                      Distribution", "random values",
 10,-2.0,2.0);
 
 // Fill histogram with Gaussian 
                      distribution
 for (int i=0; i<100000; i++) {
 double 
                      val = r.nextGaussian ();
 fHistogram.add 
                      (val);
 }
 } // makeHist
 
 } // class DrawHistApplet
 |   
                  |  import 
                      java.awt.*;import javax.swing.*;
 
 /**  Display histogram data on a PlotPanel subclass. 
                      **/
 public class HistPanel extends PlotPanel {
 
 // Histogram reference
 protected Histogram fHistogram;
 
 // Histogram bar parameters.
 protected Color fBarLineColor = Color.DARK_GRAY;
 protected Color fBarFillColor = Color.PINK;
 int fGap = 2;  // 2 pixels between 
                      bars
 
 // Fractional margin between highest bar and 
                      top frame
 double fTopMargin  = 0.05;
 
 // Fractional margnin between side bars and 
                      frame
 double fSideMargin = 0.01;
 
 // Arrays to hold numbers for axes scale values
 double [] fXScaleValue;
 double [] fYScaleValue;
 
 // Number of values on each axis
 int fNumYScaleValues = 2;
 int fNumXScaleValues = 5;
 
 /** Create the panel with the histogram. **/
 public HistPanel (Histogram histogram) {
 fHistogram = histogram;
 getScaling ();
 }
 
 /** Switch to a new histogram. **/
 public void setHistogram (Histogram histogram){
 fHistogram = histogram;
 getScaling ();
 repaint ();
 }
 
 /**
 * Get the values for the scale values 
                      on
 * the plot axes.
 **/
 void getScaling () {
 
 fYScaleValue = new double[fNumYScaleValues];
 // Use lowest value of 0;
 fYScaleValue[0] = 0.0;
 
 fXScaleValue = new double[fNumXScaleValues];
 // First get the low and high values;
 fXScaleValue[0] = fHistogram.getLo 
                      ();
 fXScaleValue[fNumXScaleValues-1] 
                      = fHistogram.getHi ();
 
 // Then calculate the difference 
                      between the values
 //  (assumes linear scale)
 double range = fXScaleValue[fNumXScaleValues-1] 
                      -
 fXScaleValue[0];
 double dx = range/(fNumXScaleValues-1);
 
 // Now set the intermediate scale 
                      values.
 for (int i=1; i < (fNumXScaleValues-1); 
                      i++) {
 fXScaleValue[i] 
                      = i*dx + fXScaleValue[0];
 }
 
 } // getScaling
 
 /** Optional bar color settings. **/
 public void setBarColors (Color line, Color 
                      fill) {
 if ( line != null) fBarLineColor 
                      = line;
 if ( fill != null) fBarFillColor 
                      = fill;
 }
 
 
 /**
 * Overrides the abstract method 
                      in PlotPanel superclass.
 * Draw the vertical bars that represent 
                      the bin contents.
 * Draw also the numbers for the 
                      scales on the axes.
 **/
 void paintContents (Graphics g) {
 
 // Get the histogram max value and 
                      bin data
 int max_data_value = fHistogram.getMax 
                      ();
 int [] bins = fHistogram.getBins 
                      ();
 
 if (max_data_value == 0) return;
 
 Color old_color=g.getColor ();  // 
                      remember color for later
 
 // Dimensions of the drawing area 
                      for the bars
 int side_space =  (int) 
                      (fFrameWidth*fSideMargin);
 int draw_width= fFrameWidth - 2 
                      * side_space- (bins.length-1)*fGap;
 
 int draw_height=  (int)(fFrameHeight* 
                      (1.0 - fTopMargin));
 
 // To avoid build up of round off 
                      errors, the bar
 // positions will be calculated 
                      from a FP value.
 float step_width= (float)draw_width/(float)bins.length;
 int bar_width = Math.round (step_width);
 step_width += fGap;
 
 // Scale the bars to the maximum 
                      bin value.
 float scale_factor= (float)draw_height/max_data_value;
 
 int start_x = fFrameX + side_space;
 int start_y = fFrameY + fFrameHeight;
 
 for (int i=0; i < bins.length; i++) 
                      {
 int bar_height 
                      =  (int)(bins[i] * scale_factor);
 
 int bar_x 
                      =  (int)(i * step_width) + start_x;
 
 // Bar drawn 
                      from top left corner
 int bar_y= 
                      start_y-bar_height;
 
 g.setColor 
                      (fBarLineColor);
 g.drawRect 
                      (bar_x,bar_y, bar_width ,bar_height);
 
 g.setColor 
                      (fBarFillColor);
 g.fillRect 
                      (bar_x+1, bar_y+1, bar_width-2, bar_height-1);
 }
 
 // Find the scale value of the full 
                      frame height.
 fYScaleValue[1] =  (double) 
                      (fFrameHeight/scale_factor);
 
 // Draw the numbers along the axes.
 drawAxesNumbers (g, fXScaleValue, 
                      fYScaleValue);
 
 g.setColor (old_color); //reset 
                      original color
 
 } // paintContents
 
 // Methods overriding those in PlotPanel
 String getTitle () {
 return fHistogram.getTitle ();
 }
 
 String getXLabel () {
 return fHistogram.getXLabel ();
 }
 
 } // class HistPanel
 
 |   
                  | /** 
                    This class provides the bare essentials for a histogram.**/ public class Histogram
 {
 protected String fTitle = "Histogram";
 protected String fXLabel = "Data";
 
 protected int [] fBins;
 protected int fNumBins;
 protected int fUnderflows;
 protected int fOverflows;
 
 protected double fLo;
 protected double fHi;
 protected double fRange;
 
 /** The constructor will create an array of a 
                    given
 * number of bins. The range of the 
                    histogram given
 * by the upper and lower limit values.
 **/
 public Histogram (int numBins, double lo, double 
                    hi) {
 // Check for bad range values.
 // Could throw an exception but will 
                    just
 // use default values;
 if (hi < lo) {
 lo = 0.0;
 hi = 1.0;
 }
 if (numBins <= 0) numBins = 1;
 fNumBins = numBins;
 fBins = new int[fNumBins];
 fLo = lo;
 fHi = hi;
 fRange = fHi - fLo;
 } // ctor
 
 // This constructor includes the title and horizontal
 // axis label.
 public Histogram (String title, String xLabel,
 int fNumBins, double lo, double hi) {
 this (fNumBins, lo, hi);// Invoke 
                    overloaded constructor
 fTitle= title;
 fXLabel = xLabel;
 } // ctor
 
 //--- Histogram description --------------------------------
 /** Get to title string. **/
 public String getTitle ()
 { return fTitle; }
 
 /** Set the title. **/
 public void setTitle (String title)
 { fTitle = title; }
 
 /** Get to the horizontal axis label. **/
 public String getXLabel ()
 { return fXLabel; }
 
 /** Set the horizontal axis label. **/
 public void setXLabel (String xLabel)
 { fXLabel = xLabel; }
 
 //--- Bin info access --------------------------------------
 /** Get the low end of the range. **/
 public double getLo ()
 { return fLo; }
 
 /** Get the high end of the range.**/
 public double getHi ()
 { return fHi; }
 
 /** Get the number of entries in the largest bin. 
                    **/
 public int getMax () {
 int max = 0;
 for (int i=0; i < fNumBins;i++)
 if (max < 
                    fBins[i]) max = fBins[i];
 return max;
 }
 
 /**
 * This method returns a reference 
                    to the fBins.
 * Note that this means the values 
                    of the histogram
 * could be altered by the caller object.
 **/
 public int [] getBins () {
 return fBins;
 }
 
 /** Get the number of entries in the smallest 
                    bin.**/
 public int getMin () {
 int min = getMax ();
 for (int i=0; i < fNumBins; i++)
 if (min > 
                    fBins[i]) min = fBins[i];
 return min;
 }
 
 /** Get the total number of entries not counting
 * overflows and underflows.
 **/
 public int getTotal () {
 int total = 0;
 for (int i=0; i < fNumBins; i++)
 total += 
                    fBins[i];
 return total;
 }
 
 /**
 * Add an entry to a bin.
 * @param x double value added if it 
                    is in the range:
 *   lo <= x < hi
 **/
 public void add (double x) {
 if (x >= fHi) fOverflows++;
 else if (x < fLo) fUnderflows++;
 else {
 double val = x - fLo;
 
 // Casting to int will 
                    round off to lower
 // integer value.
 int bin =  (int) 
                    (fNumBins *  (val/fRange) );
 
 // Increment the corresponding 
                    bin.
 fBins[bin]++;
 }
 }
 
 /** Clear the histogram bins and the over and 
                    under flows.**/
 public void clear () {
 for (int i=0; i < fNumBins; i++) {
 fBins[i] = 0;
 fOverflows = 0;
 fUnderflows= 0;
 }
 }
 
 /**
 * Provide access to the value in the 
                    bin element
 * specified by bin_num.
 
 * Return the underflows if bin value 
                    negative,
 * Return the overflows if bin value 
                    more than
 * the number of bins.
 **/
 public int getValue (int bin_num) {
 if (bin_num < 0)
 return fUnderflows;
 else if (bin_num >= fNumBins)
 return fOverflows;
 else
 return fBins[bin_num];
 }
 
 /**
 * Get the average and standard deviation 
                    of the
 * distribution of entries.
 * @return double array
 **/
 public double [] getStats () {
 int total = 0;
 
 double wt_total = 0;
 double wt_total2 = 0;
 double [] stat = new double[2];
 double bin_width = fRange/fNumBins;
 
 for (int i=0; i < fNumBins;i++) {
 total += fBins[i];
 
 double bin_mid =  (i 
                    - 0.5) * bin_width + fLo;
 wt_total  += 
                    fBins[i] * bin_mid;
 wt_total2 += fBins[i] 
                    * bin_mid * bin_mid;
 }
 
 if (total > 0) {
 stat[0] = wt_total / total;
 double av2 = wt_total2 
                    / total;
 stat[1] = Math.sqrt (av2 
                    - stat[0] * stat[0]);
 } else {
 stat[0] = 0.0;
 stat[1] = -1.0;
 }
 
 return stat;
 }// getStats()
 
 /**
 * Create the histogram from a user derived array 
                    along with the
 * under and overflow values.
 * The low and high range values that the histogram
 * corresponds to must be in passed as well.
 
 *
 * @param userBins array of int values.
 * @param under number of underflows.
 * @param over number of overflows.
 * @param lo value of the lower range limit.
 * @param hi value of the upper range limit.
 **/
 public void pack (int [] user_bins,
 int under, int over,
 double lo, double hi) {
 fNumBins = user_bins.length;
 fBins = new int[fNumBins];
 for (int i = 0; i < fNumBins; i++) 
                    {
 fBins[i] = user_bins[i];
 }
 
 fLo = lo;
 fHi = hi;
 fRange = fHi-fLo;
 fUnderflows = under;
 fOverflows = over;
 }// pack()
 
 }// class Histogram
 
 |    References & Web Resources 
 Latest update: Oct. 30, 2004 |