KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > chart > axis > NumberAxis


1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
6  *
7  * Project Info: http://www.jfree.org/jfreechart/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this library; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
24  * in the United States and other countries.]
25  *
26  * ---------------
27  * NumberAxis.java
28  * ---------------
29  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
30  *
31  * Original Author: David Gilbert (for Object Refinery Limited);
32  * Contributor(s): Laurence Vanhelsuwe;
33  *
34  * $Id: NumberAxis.java,v 1.16 2005/05/19 13:58:11 mungady Exp $
35  *
36  * Changes (from 18-Sep-2001)
37  * --------------------------
38  * 18-Sep-2001 : Added standard header and fixed DOS encoding problem (DG);
39  * 22-Sep-2001 : Changed setMinimumAxisValue() and setMaximumAxisValue() so
40  * that they clear the autoRange flag (DG);
41  * 27-Nov-2001 : Removed old, redundant code (DG);
42  * 30-Nov-2001 : Added accessor methods for the standard tick units (DG);
43  * 08-Jan-2002 : Added setAxisRange() method (since renamed setRange()) (DG);
44  * 16-Jan-2002 : Added setTickUnit() method. Extended ValueAxis to support an
45  * optional cross-hair (DG);
46  * 08-Feb-2002 : Fixes bug to ensure the autorange is recalculated if the
47  * setAutoRangeIncludesZero flag is changed (DG);
48  * 25-Feb-2002 : Added a new flag autoRangeStickyZero to provide further
49  * control over margins in the auto-range mechanism. Updated
50  * constructors. Updated import statements. Moved the
51  * createStandardTickUnits() method to the TickUnits class (DG);
52  * 19-Apr-2002 : Updated Javadoc comments (DG);
53  * 01-May-2002 : Updated for changes to TickUnit class, removed valueToString()
54  * method (DG);
55  * 25-Jul-2002 : Moved the lower and upper margin attributes, and the
56  * auto-range minimum size, up one level to the ValueAxis
57  * class (DG);
58  * 05-Sep-2002 : Updated constructor to match changes in Axis class (DG);
59  * 01-Oct-2002 : Fixed errors reported by Checkstyle (DG);
60  * 04-Oct-2002 : Moved standardTickUnits from NumberAxis --> ValueAxis (DG);
61  * 24-Oct-2002 : Added a number format override (DG);
62  * 08-Nov-2002 : Moved to new package com.jrefinery.chart.axis (DG);
63  * 19-Nov-2002 : Removed grid settings (now controlled by the plot) (DG);
64  * 14-Jan-2003 : Changed autoRangeMinimumSize from Number --> double, and moved
65  * crosshair settings to the plot classes (DG);
66  * 20-Jan-2003 : Removed the monolithic constructor (DG);
67  * 26-Mar-2003 : Implemented Serializable (DG);
68  * 16-Jul-2003 : Reworked to allow for multiple secondary axes (DG);
69  * 13-Aug-2003 : Implemented Cloneable (DG);
70  * 07-Oct-2003 : Fixed bug (815028) in the auto range calculation (DG);
71  * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG);
72  * 07-Nov-2003 : Modified to use NumberTick class (DG);
73  * 21-Jan-2004 : Renamed translateJava2DToValue --> java2DToValue, and
74  * translateValueToJava2D --> valueToJava2D (DG);
75  * 03-Mar-2004 : Added plotState to draw() method (DG);
76  * 07-Apr-2004 : Changed string width calculation (DG);
77  * 11-Jan-2005 : Removed deprecated methods in preparation for 1.0.0
78  * release (DG);
79  * 28-Mar-2005 : Renamed autoRangeIncludesZero() --> getAutoRangeIncludesZero()
80  * and autoRangeStickyZero() --> getAutoRangeStickyZero() (DG);
81  * 21-Apr-2005 : Removed redundant argument from selectAutoTickUnit() (DG);
82  * 22-Apr-2005 : Renamed refreshHorizontalTicks --> refreshTicksHorizontal
83  * (and likewise the vertical version) for consistency with
84  * other axis classes (DG);
85  *
86  */

87
88 package org.jfree.chart.axis;
89
90 import java.awt.Font JavaDoc;
91 import java.awt.FontMetrics JavaDoc;
92 import java.awt.Graphics2D JavaDoc;
93 import java.awt.font.FontRenderContext JavaDoc;
94 import java.awt.font.LineMetrics JavaDoc;
95 import java.awt.geom.Rectangle2D JavaDoc;
96 import java.io.Serializable JavaDoc;
97 import java.text.DecimalFormat JavaDoc;
98 import java.text.NumberFormat JavaDoc;
99 import java.util.List JavaDoc;
100 import java.util.Locale JavaDoc;
101
102 import org.jfree.chart.event.AxisChangeEvent;
103 import org.jfree.chart.plot.Plot;
104 import org.jfree.chart.plot.PlotRenderingInfo;
105 import org.jfree.chart.plot.ValueAxisPlot;
106 import org.jfree.data.Range;
107 import org.jfree.data.RangeType;
108 import org.jfree.ui.RectangleEdge;
109 import org.jfree.ui.RectangleInsets;
110 import org.jfree.ui.TextAnchor;
111 import org.jfree.util.ObjectUtilities;
112
113 /**
114  * An axis for displaying numerical data.
115  * <P>
116  * If the axis is set up to automatically determine its range to fit the data,
117  * you can ensure that the range includes zero (statisticians usually prefer
118  * this) by setting the <code>autoRangeIncludesZero</code> flag to
119  * <code>true</code>.
120  * <P>
121  * The <code>NumberAxis</code> class has a mechanism for automatically
122  * selecting a tick unit that is appropriate for the current axis range. This
123  * mechanism is an adaptation of code suggested by Laurence Vanhelsuwe.
124  */

125 public class NumberAxis extends ValueAxis implements Cloneable JavaDoc, Serializable JavaDoc {
126
127     /** For serialization. */
128     private static final long serialVersionUID = 2805933088476185789L;
129     
130     /** The default value for the autoRangeIncludesZero flag. */
131     public static final boolean DEFAULT_AUTO_RANGE_INCLUDES_ZERO = true;
132
133     /** The default value for the autoRangeStickyZero flag. */
134     public static final boolean DEFAULT_AUTO_RANGE_STICKY_ZERO = true;
135
136     /** The default tick unit. */
137     public static final NumberTickUnit
138         DEFAULT_TICK_UNIT = new NumberTickUnit(1.0, new DecimalFormat JavaDoc("0"));
139
140     /** The default setting for the vertical tick labels flag. */
141     public static final boolean DEFAULT_VERTICAL_TICK_LABELS = false;
142
143     /**
144      * The range type (can be used to force the axis to display only positive
145      * values or only negative values.
146      */

147     private RangeType rangeType;
148     
149     /**
150      * A flag that affects the axis range when the range is determined
151      * automatically. If the auto range does NOT include zero and this flag
152      * is TRUE, then the range is changed to include zero.
153      */

154     private boolean autoRangeIncludesZero;
155
156     /**
157      * A flag that affects the size of the margins added to the axis range when
158      * the range is determined automatically. If the value 0 falls within the
159      * margin and this flag is TRUE, then the margin is truncated at zero.
160      */

161     private boolean autoRangeStickyZero;
162
163     /** The tick unit for the axis. */
164     private NumberTickUnit tickUnit;
165
166     /** The override number format. */
167     private NumberFormat JavaDoc numberFormatOverride;
168
169     /** An optional band for marking regions on the axis. */
170     private MarkerAxisBand markerBand;
171
172     /**
173      * Default constructor.
174      */

175     public NumberAxis() {
176         this(null);
177     }
178     
179     /**
180      * Constructs a number axis, using default values where necessary.
181      *
182      * @param label the axis label (<code>null</code> permitted).
183      */

184     public NumberAxis(String JavaDoc label) {
185         super(label, NumberAxis.createStandardTickUnits());
186         this.rangeType = RangeType.FULL;
187         this.autoRangeIncludesZero = DEFAULT_AUTO_RANGE_INCLUDES_ZERO;
188         this.autoRangeStickyZero = DEFAULT_AUTO_RANGE_STICKY_ZERO;
189         this.tickUnit = DEFAULT_TICK_UNIT;
190         this.numberFormatOverride = null;
191         this.markerBand = null;
192     }
193     
194     /**
195      * Returns the axis range type.
196      *
197      * @return The axis range type (never <code>null</code>).
198      */

199     public RangeType getRangeType() {
200         return this.rangeType;
201     }
202     
203     /**
204      * Sets the axis range type.
205      *
206      * @param rangeType the range type (<code>null</code> not permitted).
207      */

208     public void setRangeType(RangeType rangeType) {
209         if (rangeType == null) {
210             throw new IllegalArgumentException JavaDoc("Null 'rangeType' argument.");
211         }
212         this.rangeType = rangeType;
213         notifyListeners(new AxisChangeEvent(this));
214     }
215     
216     /**
217      * Returns the flag that indicates whether or not the automatic axis range
218      * (if indeed it is determined automatically) is forced to include zero.
219      *
220      * @return The flag.
221      */

222     public boolean getAutoRangeIncludesZero() {
223         return this.autoRangeIncludesZero;
224     }
225
226     /**
227      * Sets the flag that indicates whether or not the axis range, if
228      * automatically calculated, is forced to include zero.
229      * <p>
230      * If the flag is changed to <code>true</code>, the axis range is
231      * recalculated.
232      * <p>
233      * Any change to the flag will trigger an {@link AxisChangeEvent}.
234      *
235      * @param flag the new value of the flag.
236      */

237     public void setAutoRangeIncludesZero(boolean flag) {
238         if (this.autoRangeIncludesZero != flag) {
239             this.autoRangeIncludesZero = flag;
240             if (isAutoRange()) {
241                 autoAdjustRange();
242             }
243             notifyListeners(new AxisChangeEvent(this));
244         }
245     }
246
247     /**
248      * Returns a flag that affects the auto-range when zero falls outside the
249      * data range but inside the margins defined for the axis.
250      *
251      * @return The flag.
252      */

253     public boolean getAutoRangeStickyZero() {
254         return this.autoRangeStickyZero;
255     }
256
257     /**
258      * Sets a flag that affects the auto-range when zero falls outside the data
259      * range but inside the margins defined for the axis.
260      *
261      * @param flag the new flag.
262      */

263     public void setAutoRangeStickyZero(boolean flag) {
264         if (this.autoRangeStickyZero != flag) {
265             this.autoRangeStickyZero = flag;
266             if (isAutoRange()) {
267                 autoAdjustRange();
268             }
269             notifyListeners(new AxisChangeEvent(this));
270         }
271     }
272
273     /**
274      * Returns the tick unit for the axis.
275      *
276      * @return The tick unit for the axis.
277      */

278     public NumberTickUnit getTickUnit() {
279         return this.tickUnit;
280     }
281
282     /**
283      * Sets the tick unit for the axis and sends an {@link AxisChangeEvent} to
284      * all registered listeners. A side effect of calling this method is that
285      * the "auto-select" feature for tick units is switched off (you can
286      * restore it using the {@link ValueAxis#setAutoTickUnitSelection(boolean)}
287      * method).
288      *
289      * @param unit the new tick unit (<code>null</code> not permitted).
290      */

291     public void setTickUnit(NumberTickUnit unit) {
292         // defer argument checking...
293
setTickUnit(unit, true, true);
294     }
295
296     /**
297      * Sets the tick unit for the axis and, if requested, sends an
298      * {@link AxisChangeEvent} to all registered listeners. In addition, an
299      * option is provided to turn off the "auto-select" feature for tick units
300      * (you can restore it using the
301      * {@link ValueAxis#setAutoTickUnitSelection(boolean)} method).
302      *
303      * @param unit the new tick unit (<code>null</code> not permitted).
304      * @param notify notify listeners?
305      * @param turnOffAutoSelect turn off the auto-tick selection?
306      */

307     public void setTickUnit(NumberTickUnit unit, boolean notify,
308                             boolean turnOffAutoSelect) {
309
310         if (unit == null) {
311             throw new IllegalArgumentException JavaDoc("Null 'unit' argument.");
312         }
313         this.tickUnit = unit;
314         if (turnOffAutoSelect) {
315             setAutoTickUnitSelection(false, false);
316         }
317         if (notify) {
318             notifyListeners(new AxisChangeEvent(this));
319         }
320
321     }
322
323     /**
324      * Returns the number format override. If this is non-null, then it will
325      * be used to format the numbers on the axis.
326      *
327      * @return The number formatter (possibly <code>null</code>).
328      */

329     public NumberFormat JavaDoc getNumberFormatOverride() {
330         return this.numberFormatOverride;
331     }
332
333     /**
334      * Sets the number format override. If this is non-null, then it will be
335      * used to format the numbers on the axis.
336      *
337      * @param formatter the number formatter (<code>null</code> permitted).
338      */

339     public void setNumberFormatOverride(NumberFormat JavaDoc formatter) {
340         this.numberFormatOverride = formatter;
341         notifyListeners(new AxisChangeEvent(this));
342     }
343
344     /**
345      * Returns the (optional) marker band for the axis.
346      *
347      * @return The marker band (possibly <code>null</code>).
348      */

349     public MarkerAxisBand getMarkerBand() {
350         return this.markerBand;
351     }
352
353     /**
354      * Sets the marker band for the axis.
355      * <P>
356      * The marker band is optional, leave it set to <code>null</code> if you
357      * don't require it.
358      *
359      * @param band the new band (<code>null<code> permitted).
360      */

361     public void setMarkerBand(MarkerAxisBand band) {
362         this.markerBand = band;
363         notifyListeners(new AxisChangeEvent(this));
364     }
365
366     /**
367      * Configures the axis to work with the specified plot. If the axis has
368      * auto-scaling, then sets the maximum and minimum values.
369      */

370     public void configure() {
371         if (isAutoRange()) {
372             autoAdjustRange();
373         }
374     }
375
376     /**
377      * Rescales the axis to ensure that all data is visible.
378      */

379     protected void autoAdjustRange() {
380
381         Plot plot = getPlot();
382         if (plot == null) {
383             return; // no plot, no data
384
}
385
386         if (plot instanceof ValueAxisPlot) {
387             ValueAxisPlot vap = (ValueAxisPlot) plot;
388
389             Range r = vap.getDataRange(this);
390             if (r == null) {
391                 r = new Range(DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND);
392             }
393             
394             double upper = r.getUpperBound();
395             double lower = r.getLowerBound();
396             if (this.rangeType == RangeType.POSITIVE) {
397                 lower = Math.max(0.0, lower);
398                 upper = Math.max(0.0, upper);
399             }
400             else if (this.rangeType == RangeType.NEGATIVE) {
401                 lower = Math.min(0.0, lower);
402                 upper = Math.min(0.0, upper);
403             }
404             
405             if (getAutoRangeIncludesZero()) {
406                 lower = Math.min(lower, 0.0);
407                 upper = Math.max(upper, 0.0);
408             }
409             double range = upper - lower;
410
411             // if fixed auto range, then derive lower bound...
412
double fixedAutoRange = getFixedAutoRange();
413             if (fixedAutoRange > 0.0) {
414                 lower = upper - fixedAutoRange;
415             }
416             else {
417                 // ensure the autorange is at least <minRange> in size...
418
double minRange = getAutoRangeMinimumSize();
419                 if (range < minRange) {
420                     double expand = (minRange - range) / 2;
421                     upper = upper + expand;
422                     lower = lower - expand;
423                     if (this.rangeType == RangeType.POSITIVE) {
424                         if (lower < 0.0) {
425                             upper = upper - lower;
426                             lower = 0.0;
427                         }
428                     }
429                     else if (this.rangeType == RangeType.NEGATIVE) {
430                         if (upper > 0.0) {
431                             lower = lower - upper;
432                             upper = 0.0;
433                         }
434                     }
435                 }
436
437                 if (getAutoRangeStickyZero()) {
438                     if (upper <= 0.0) {
439                         upper = Math.min(0.0, upper + getUpperMargin() * range);
440                     }
441                     else {
442                         upper = upper + getUpperMargin() * range;
443                     }
444                     if (lower >= 0.0) {
445                         lower = Math.max(0.0, lower - getLowerMargin() * range);
446                     }
447                     else {
448                         lower = lower - getLowerMargin() * range;
449                     }
450                 }
451                 else {
452                     upper = upper + getUpperMargin() * range;
453                     lower = lower - getLowerMargin() * range;
454                 }
455             }
456
457             setRange(new Range(lower, upper), false, false);
458         }
459
460     }
461
462     /**
463      * Converts a data value to a coordinate in Java2D space, assuming that the
464      * axis runs along one edge of the specified dataArea.
465      * <p>
466      * Note that it is possible for the coordinate to fall outside the plotArea.
467      *
468      * @param value the data value.
469      * @param area the area for plotting the data.
470      * @param edge the axis location.
471      *
472      * @return The Java2D coordinate.
473      */

474     public double valueToJava2D(double value, Rectangle2D JavaDoc area,
475                                 RectangleEdge edge) {
476         
477         Range range = getRange();
478         double axisMin = range.getLowerBound();
479         double axisMax = range.getUpperBound();
480
481         double min = 0.0;
482         double max = 0.0;
483         if (RectangleEdge.isTopOrBottom(edge)) {
484             min = area.getX();
485             max = area.getMaxX();
486         }
487         else if (RectangleEdge.isLeftOrRight(edge)) {
488             max = area.getMinY();
489             min = area.getMaxY();
490         }
491         if (isInverted()) {
492             return max
493                    - ((value - axisMin) / (axisMax - axisMin)) * (max - min);
494         }
495         else {
496             return min
497                    + ((value - axisMin) / (axisMax - axisMin)) * (max - min);
498         }
499
500     }
501
502     /**
503      * Converts a coordinate in Java2D space to the corresponding data value,
504      * assuming that the axis runs along one edge of the specified dataArea.
505      *
506      * @param java2DValue the coordinate in Java2D space.
507      * @param area the area in which the data is plotted.
508      * @param edge the location.
509      *
510      * @return The data value.
511      */

512     public double java2DToValue(double java2DValue, Rectangle2D JavaDoc area,
513                                 RectangleEdge edge) {
514         
515         Range range = getRange();
516         double axisMin = range.getLowerBound();
517         double axisMax = range.getUpperBound();
518
519         double min = 0.0;
520         double max = 0.0;
521         if (RectangleEdge.isTopOrBottom(edge)) {
522             min = area.getX();
523             max = area.getMaxX();
524         }
525         else if (RectangleEdge.isLeftOrRight(edge)) {
526             min = area.getMaxY();
527             max = area.getY();
528         }
529         if (isInverted()) {
530             return axisMax
531                    - (java2DValue - min) / (max - min) * (axisMax - axisMin);
532         }
533         else {
534             return axisMin
535                    + (java2DValue - min) / (max - min) * (axisMax - axisMin);
536         }
537
538     }
539
540     /**
541      * Calculates the value of the lowest visible tick on the axis.
542      *
543      * @return The value of the lowest visible tick on the axis.
544      */

545     protected double calculateLowestVisibleTickValue() {
546
547         double unit = getTickUnit().getSize();
548         double index = Math.ceil(getRange().getLowerBound() / unit);
549         return index * unit;
550
551     }
552
553     /**
554      * Calculates the value of the highest visible tick on the axis.
555      *
556      * @return The value of the highest visible tick on the axis.
557      */

558     protected double calculateHighestVisibleTickValue() {
559
560         double unit = getTickUnit().getSize();
561         double index = Math.floor(getRange().getUpperBound() / unit);
562         return index * unit;
563
564     }
565
566     /**
567      * Calculates the number of visible ticks.
568      *
569      * @return The number of visible ticks on the axis.
570      */

571     protected int calculateVisibleTickCount() {
572
573         double unit = getTickUnit().getSize();
574         Range range = getRange();
575         return (int) (Math.floor(range.getUpperBound() / unit)
576                       - Math.ceil(range.getLowerBound() / unit) + 1);
577
578     }
579
580     /**
581      * Draws the axis on a Java 2D graphics device (such as the screen or a
582      * printer).
583      *
584      * @param g2 the graphics device (<code>null</code> not permitted).
585      * @param cursor the cursor location.
586      * @param plotArea the area within which the axes and data should be drawn
587      * (<code>null</code> not permitted).
588      * @param dataArea the area within which the data should be drawn
589      * (<code>null</code> not permitted).
590      * @param edge the location of the axis (<code>null</code> not permitted).
591      * @param plotState collects information about the plot
592      * (<code>null</code> permitted).
593      *
594      * @return The axis state (never <code>null</code>).
595      */

596     public AxisState draw(Graphics2D JavaDoc g2,
597                           double cursor,
598                           Rectangle2D JavaDoc plotArea,
599                           Rectangle2D JavaDoc dataArea,
600                           RectangleEdge edge,
601                           PlotRenderingInfo plotState) {
602
603         AxisState state = null;
604         // if the axis is not visible, don't draw it...
605
if (!isVisible()) {
606             state = new AxisState(cursor);
607             // even though the axis is not visible, we need ticks for the
608
// gridlines...
609
List JavaDoc ticks = refreshTicks(g2, state, dataArea, edge);
610             state.setTicks(ticks);
611             return state;
612         }
613
614         // draw the tick marks and labels...
615
state = drawTickMarksAndLabels(g2, cursor, plotArea, dataArea, edge);
616
617 // // draw the marker band (if there is one)...
618
// if (getMarkerBand() != null) {
619
// if (edge == RectangleEdge.BOTTOM) {
620
// cursor = cursor - getMarkerBand().getHeight(g2);
621
// }
622
// getMarkerBand().draw(g2, plotArea, dataArea, 0, cursor);
623
// }
624

625         // draw the axis label...
626
state = drawLabel(getLabel(), g2, plotArea, dataArea, edge, state);
627
628         return state;
629         
630     }
631
632     /**
633      * Creates the standard tick units.
634      * <P>
635      * If you don't like these defaults, create your own instance of TickUnits
636      * and then pass it to the setStandardTickUnits() method in the
637      * NumberAxis class.
638      *
639      * @return The standard tick units.
640      */

641     public static TickUnitSource createStandardTickUnits() {
642
643         TickUnits units = new TickUnits();
644         DecimalFormat JavaDoc df0 = new DecimalFormat JavaDoc("0.00000000");
645         DecimalFormat JavaDoc df1 = new DecimalFormat JavaDoc("0.0000000");
646         DecimalFormat JavaDoc df2 = new DecimalFormat JavaDoc("0.000000");
647         DecimalFormat JavaDoc df3 = new DecimalFormat JavaDoc("0.00000");
648         DecimalFormat JavaDoc df4 = new DecimalFormat JavaDoc("0.0000");
649         DecimalFormat JavaDoc df5 = new DecimalFormat JavaDoc("0.000");
650         DecimalFormat JavaDoc df6 = new DecimalFormat JavaDoc("0.00");
651         DecimalFormat JavaDoc df7 = new DecimalFormat JavaDoc("0.0");
652         DecimalFormat JavaDoc df8 = new DecimalFormat JavaDoc("#,##0");
653         DecimalFormat JavaDoc df9 = new DecimalFormat JavaDoc("#,###,##0");
654         DecimalFormat JavaDoc df10 = new DecimalFormat JavaDoc("#,###,###,##0");
655         
656         // we can add the units in any order, the TickUnits collection will
657
// sort them...
658
units.add(new NumberTickUnit(0.0000001, df1));
659         units.add(new NumberTickUnit(0.000001, df2));
660         units.add(new NumberTickUnit(0.00001, df3));
661         units.add(new NumberTickUnit(0.0001, df4));
662         units.add(new NumberTickUnit(0.001, df5));
663         units.add(new NumberTickUnit(0.01, df6));
664         units.add(new NumberTickUnit(0.1, df7));
665         units.add(new NumberTickUnit(1, df8));
666         units.add(new NumberTickUnit(10, df8));
667         units.add(new NumberTickUnit(100, df8));
668         units.add(new NumberTickUnit(1000, df8));
669         units.add(new NumberTickUnit(10000, df8));
670         units.add(new NumberTickUnit(100000, df8));
671         units.add(new NumberTickUnit(1000000, df9));
672         units.add(new NumberTickUnit(10000000, df9));
673         units.add(new NumberTickUnit(100000000, df9));
674         units.add(new NumberTickUnit(1000000000, df10));
675         units.add(new NumberTickUnit(10000000000.0, df10));
676         units.add(new NumberTickUnit(100000000000.0, df10));
677         
678         units.add(new NumberTickUnit(0.00000025, df0));
679         units.add(new NumberTickUnit(0.0000025, df1));
680         units.add(new NumberTickUnit(0.000025, df2));
681         units.add(new NumberTickUnit(0.00025, df3));
682         units.add(new NumberTickUnit(0.0025, df4));
683         units.add(new NumberTickUnit(0.025, df5));
684         units.add(new NumberTickUnit(0.25, df6));
685         units.add(new NumberTickUnit(2.5, df7));
686         units.add(new NumberTickUnit(25, df8));
687         units.add(new NumberTickUnit(250, df8));
688         units.add(new NumberTickUnit(2500, df8));
689         units.add(new NumberTickUnit(25000, df8));
690         units.add(new NumberTickUnit(250000, df8));
691         units.add(new NumberTickUnit(2500000, df9));
692         units.add(new NumberTickUnit(25000000, df9));
693         units.add(new NumberTickUnit(250000000, df9));
694         units.add(new NumberTickUnit(2500000000.0, df10));
695         units.add(new NumberTickUnit(25000000000.0, df10));
696         units.add(new NumberTickUnit(250000000000.0, df10));
697
698         units.add(new NumberTickUnit(0.0000005, df1));
699         units.add(new NumberTickUnit(0.000005, df2));
700         units.add(new NumberTickUnit(0.00005, df3));
701         units.add(new NumberTickUnit(0.0005, df4));
702         units.add(new NumberTickUnit(0.005, df5));
703         units.add(new NumberTickUnit(0.05, df6));
704         units.add(new NumberTickUnit(0.5, df7));
705         units.add(new NumberTickUnit(5L, df8));
706         units.add(new NumberTickUnit(50L, df8));
707         units.add(new NumberTickUnit(500L, df8));
708         units.add(new NumberTickUnit(5000L, df8));
709         units.add(new NumberTickUnit(50000L, df8));
710         units.add(new NumberTickUnit(500000L, df8));
711         units.add(new NumberTickUnit(5000000L, df9));
712         units.add(new NumberTickUnit(50000000L, df9));
713         units.add(new NumberTickUnit(500000000L, df9));
714         units.add(new NumberTickUnit(5000000000L, df10));
715         units.add(new NumberTickUnit(50000000000L, df10));
716         units.add(new NumberTickUnit(500000000000L, df10));
717
718         return units;
719
720     }
721
722     /**
723      * Returns a collection of tick units for integer values.
724      *
725      * @return A collection of tick units for integer values.
726      */

727     public static TickUnitSource createIntegerTickUnits() {
728
729         TickUnits units = new TickUnits();
730         DecimalFormat JavaDoc df0 = new DecimalFormat JavaDoc("0");
731         DecimalFormat JavaDoc df1 = new DecimalFormat JavaDoc("#,##0");
732         units.add(new NumberTickUnit(1, df0));
733         units.add(new NumberTickUnit(2, df0));
734         units.add(new NumberTickUnit(5, df0));
735         units.add(new NumberTickUnit(10, df0));
736         units.add(new NumberTickUnit(20, df0));
737         units.add(new NumberTickUnit(50, df0));
738         units.add(new NumberTickUnit(100, df0));
739         units.add(new NumberTickUnit(200, df0));
740         units.add(new NumberTickUnit(500, df0));
741         units.add(new NumberTickUnit(1000, df1));
742         units.add(new NumberTickUnit(2000, df1));
743         units.add(new NumberTickUnit(5000, df1));
744         units.add(new NumberTickUnit(10000, df1));
745         units.add(new NumberTickUnit(20000, df1));
746         units.add(new NumberTickUnit(50000, df1));
747         units.add(new NumberTickUnit(100000, df1));
748         units.add(new NumberTickUnit(200000, df1));
749         units.add(new NumberTickUnit(500000, df1));
750         units.add(new NumberTickUnit(1000000, df1));
751         units.add(new NumberTickUnit(2000000, df1));
752         units.add(new NumberTickUnit(5000000, df1));
753         units.add(new NumberTickUnit(10000000, df1));
754         units.add(new NumberTickUnit(20000000, df1));
755         units.add(new NumberTickUnit(50000000, df1));
756         units.add(new NumberTickUnit(100000000, df1));
757         units.add(new NumberTickUnit(200000000, df1));
758         units.add(new NumberTickUnit(500000000, df1));
759         units.add(new NumberTickUnit(1000000000, df1));
760         units.add(new NumberTickUnit(2000000000, df1));
761         units.add(new NumberTickUnit(5000000000.0, df1));
762         units.add(new NumberTickUnit(10000000000.0, df1));
763
764         return units;
765
766     }
767
768     /**
769      * Creates a collection of standard tick units. The supplied locale is
770      * used to create the number formatter (a localised instance of
771      * <code>NumberFormat</code>).
772      * <P>
773      * If you don't like these defaults, create your own instance of
774      * {@link TickUnits} and then pass it to the
775      * <code>setStandardTickUnits()</code> method.
776      *
777      * @param locale the locale.
778      *
779      * @return A tick unit collection.
780      */

781     public static TickUnitSource createStandardTickUnits(Locale JavaDoc locale) {
782
783         TickUnits units = new TickUnits();
784
785         NumberFormat JavaDoc numberFormat = NumberFormat.getNumberInstance(locale);
786
787         // we can add the units in any order, the TickUnits collection will
788
// sort them...
789
units.add(new NumberTickUnit(0.0000001, numberFormat));
790         units.add(new NumberTickUnit(0.000001, numberFormat));
791         units.add(new NumberTickUnit(0.00001, numberFormat));
792         units.add(new NumberTickUnit(0.0001, numberFormat));
793         units.add(new NumberTickUnit(0.001, numberFormat));
794         units.add(new NumberTickUnit(0.01, numberFormat));
795         units.add(new NumberTickUnit(0.1, numberFormat));
796         units.add(new NumberTickUnit(1, numberFormat));
797         units.add(new NumberTickUnit(10, numberFormat));
798         units.add(new NumberTickUnit(100, numberFormat));
799         units.add(new NumberTickUnit(1000, numberFormat));
800         units.add(new NumberTickUnit(10000, numberFormat));
801         units.add(new NumberTickUnit(100000, numberFormat));
802