KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > chart > renderer > BoxAndWhiskerRenderer


1 /* ======================================
2  * JFreeChart : a free Java chart library
3  * ======================================
4  *
5  * Project Info: http://www.jfree.org/jfreechart/index.html
6  * Project Lead: David Gilbert (david.gilbert@object-refinery.com);
7  *
8  * (C) Copyright 2000-2003, by Object Refinery Limited and Contributors.
9  *
10  * This library is free software; you can redistribute it and/or modify it under the terms
11  * of the GNU Lesser General Public License as published by the Free Software Foundation;
12  * either version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
15  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License along with this
19  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20  * Boston, MA 02111-1307, USA.
21  *
22  * --------------------------
23  * BoxAndWhiskerRenderer.java
24  * --------------------------
25  * (C) Copyright 2003, by David Browning and Contributors.
26  *
27  * Original Author: David Browning (for the Australian Institute of Marine Science);
28  * Contributor(s): David Gilbert (for Object Refinery Limited);
29  * Tim Bardzil;
30  *
31  * $Id: BoxAndWhiskerRenderer.java,v 1.15 2003/11/13 08:42:31 mungady Exp $
32  *
33  * Changes
34  * -------
35  * 21-Aug-2003 : Version 1, contributed by David Browning (for the Australian Institute of
36  * Marine Science);
37  * 01-Sep-2003 : Incorporated outlier and farout symbols for low values also (DG);
38  * 08-Sep-2003 : Changed ValueAxis API (DG);
39  * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
40  * 07-Oct-2003 : Added renderer state (DG);
41  * 12-Nov-2003 : Fixed casting bug reported by Tim Bardzil (DG);
42  * 13-Nov-2003 : Added drawHorizontalItem(...) method contributed by Tim Bardzil (DG);
43  *
44  */

45
46 package org.jfree.chart.renderer;
47
48 import java.awt.Color JavaDoc;
49 import java.awt.Graphics2D JavaDoc;
50 import java.awt.Paint JavaDoc;
51 import java.awt.Shape JavaDoc;
52 import java.awt.Stroke JavaDoc;
53 import java.awt.geom.Ellipse2D JavaDoc;
54 import java.awt.geom.Line2D JavaDoc;
55 import java.awt.geom.Point2D JavaDoc;
56 import java.awt.geom.Rectangle2D JavaDoc;
57 import java.util.ArrayList JavaDoc;
58 import java.util.Collections JavaDoc;
59 import java.util.Iterator JavaDoc;
60 import java.util.List JavaDoc;
61
62 import org.jfree.chart.axis.CategoryAxis;
63 import org.jfree.chart.axis.ValueAxis;
64 import org.jfree.chart.plot.CategoryPlot;
65 import org.jfree.chart.plot.PlotOrientation;
66 import org.jfree.chart.plot.PlotRenderingInfo;
67 import org.jfree.data.CategoryDataset;
68 import org.jfree.data.statistics.BoxAndWhiskerCategoryDataset;
69 import org.jfree.ui.RectangleEdge;
70
71 /**
72  * A box-and-whisker renderer.
73  */

74 public class BoxAndWhiskerRenderer extends AbstractCategoryItemRenderer {
75
76     /** The color used to paint the median line and average marker. */
77     private Paint JavaDoc artifactPaint;
78
79     /** The box width. */
80     private double boxWidth;
81
82     /** The margin between items (boxes) within a category. */
83     private double itemMargin;
84
85     /**
86      * Default constructor.
87      */

88     public BoxAndWhiskerRenderer () {
89         this.artifactPaint = Color.black;
90         this.boxWidth = 0.0;
91         this.itemMargin = 0.20;
92     }
93
94     /**
95      * Returns the paint used to color the median and average markers.
96      *
97      * @return A paint.
98      */

99     public Paint JavaDoc getArtifactPaint() {
100         return artifactPaint;
101     }
102
103     /**
104      * Sets the paint used to color the median and average markers.
105      *
106      * @param paint the paint.
107      */

108     public void setArtifactPaint(Paint JavaDoc paint) {
109         this.artifactPaint = paint;
110     }
111
112     /**
113      * Returns the box width.
114      *
115      * @return The box width.
116      */

117     public double getBoxWidth() {
118         return boxWidth;
119     }
120
121     /**
122      * Sets the box width.
123      *
124      * @param width the width.
125      */

126     public void setBoxWidth(double width) {
127         this.boxWidth = width;
128     }
129
130     /**
131      * Returns the item margin. This is a percentage of the available space that is allocated
132      * to the space between items in the chart.
133      *
134      * @return The margin.
135      */

136     public double getItemMargin() {
137         return itemMargin;
138     }
139
140     /**
141      * Sets the item margin.
142      *
143      * @param margin the margin.
144      */

145     public void setItemMargin(double margin) {
146         this.itemMargin = margin;
147     }
148
149     /**
150      * Initialises the renderer.
151      * <p>
152      * This method gets called once at the start of the process of drawing a chart.
153      *
154      * @param g2 the graphics device.
155      * @param dataArea the area in which the data is to be plotted.
156      * @param plot the plot.
157      * @param index the renderer index (<code>null</code> for primary index).
158      * @param info collects chart rendering information for return to caller.
159      *
160      * @return The renderer state.
161      */

162     public CategoryItemRendererState initialise(Graphics2D JavaDoc g2,
163                                                 Rectangle2D JavaDoc dataArea,
164                                                 CategoryPlot plot,
165                                                 Integer JavaDoc index,
166                                                 PlotRenderingInfo info) {
167
168         CategoryItemRendererState state = super.initialise(g2, dataArea, plot, index, info);
169
170         // calculate the box width
171
CategoryAxis domainAxis = getDomainAxis(plot, index);
172         
173         CategoryDataset dataset = getDataset(plot, index);
174         if (dataset != null) {
175             int columns = dataset.getColumnCount();
176             int rows = dataset.getRowCount();
177             double space = 0.0;
178             PlotOrientation orientation = plot.getOrientation();
179             if (orientation == PlotOrientation.HORIZONTAL) {
180                 space = dataArea.getHeight();
181             }
182             else if (orientation == PlotOrientation.VERTICAL) {
183                 space = dataArea.getWidth();
184             }
185             double categoryMargin = 0.0;
186             double currentItemMargin = 0.0;
187             if (columns > 1) {
188                 categoryMargin = domainAxis.getCategoryMargin();
189             }
190             if (rows > 1) {
191                 currentItemMargin = getItemMargin();
192             }
193             double used = space * (1 - domainAxis.getLowerMargin() - domainAxis.getUpperMargin()
194                                      - categoryMargin - currentItemMargin);
195             if ((rows * columns) > 0) {
196                 setBoxWidth(used / (dataset.getColumnCount() * dataset.getRowCount()));
197             }
198             else {
199                 setBoxWidth(used);
200             }
201         }
202         
203         return state;
204
205     }
206
207     /**
208      * Draw a single data item.
209      *
210      * @param g2 the graphics device.
211      * @param state the renderer state.
212      * @param dataArea the area in which the data is drawn.
213      * @param plot the plot.
214      * @param domainAxis the domain axis.
215      * @param rangeAxis the range axis.
216      * @param dataset the data.
217      * @param row the row index (zero-based).
218      * @param column the column index (zero-based).
219      */

220     public void drawItem(Graphics2D JavaDoc g2,
221                          CategoryItemRendererState state,
222                          Rectangle2D JavaDoc dataArea,
223                          CategoryPlot plot,
224                          CategoryAxis domainAxis,
225                          ValueAxis rangeAxis,
226                          CategoryDataset dataset,
227                          int row,
228                          int column) {
229                              
230         if (!(dataset instanceof BoxAndWhiskerCategoryDataset)) {
231             throw new IllegalArgumentException JavaDoc("BoxAndWhiskerRenderer.drawItem()"
232                 + " : the data should be of type BoxAndWhiskerCategoryDataset only.");
233         }
234
235         PlotOrientation orientation = plot.getOrientation();
236
237         if (orientation == PlotOrientation.HORIZONTAL) {
238             drawHorizontalItem(g2, dataArea, plot, domainAxis, rangeAxis, dataset, row, column);
239         }
240         else if (orientation == PlotOrientation.VERTICAL) {
241             drawVerticalItem(g2, dataArea, plot, domainAxis, rangeAxis, dataset, row, column);
242         }
243         
244     }
245
246     /**
247      * Draws the visual representation of a single data item when the plot has a horizontal
248      * orientation.
249      *
250      * @param g2 the graphics device.
251      * @param dataArea the area within which the plot is being drawn.
252      * @param plot the plot (can be used to obtain standard color information etc).
253      * @param domainAxis the domain axis.
254      * @param rangeAxis the range axis.
255      * @param dataset the dataset.
256      * @param row the row index (zero-based).
257      * @param column the column index (zero-based).
258      */

259     public void drawHorizontalItem(Graphics2D JavaDoc g2,
260                                      Rectangle2D JavaDoc dataArea,
261                                      CategoryPlot plot,
262                                      CategoryAxis domainAxis,
263                                      ValueAxis rangeAxis,
264                                      CategoryDataset dataset,
265                                      int row,
266                                      int column) {
267
268         BoxAndWhiskerCategoryDataset bawDataset = (BoxAndWhiskerCategoryDataset) dataset;
269
270         double categoryEnd = domainAxis.getCategoryEnd(
271             column, getColumnCount(), dataArea, plot.getDomainAxisEdge());
272         double categoryStart = domainAxis.getCategoryStart(
273             column, getColumnCount(), dataArea, plot.getDomainAxisEdge());
274         double categoryWidth = Math.abs(categoryEnd - categoryStart);
275
276         double yy = categoryStart;
277         int seriesCount = getRowCount();
278         int categoryCount = getColumnCount();
279
280         if (seriesCount > 1) {
281             double seriesGap = dataArea.getWidth() * getItemMargin()
282                                / (categoryCount * (seriesCount - 1));
283             double usedWidth = (getBoxWidth() * seriesCount) + (seriesGap * (seriesCount - 1));
284             // offset the start of the boxes if the total width used is smaller than the category width
285
double offset = (categoryWidth - usedWidth) / 2;
286             yy = yy + offset + (row * (getBoxWidth() + seriesGap));
287         }
288         else {
289             // offset the start of the box if the box width is smaller than the category width
290
double offset = (categoryWidth - boxWidth) / 2;
291             yy = yy + offset;
292         }
293
294         Paint JavaDoc p = this.getItemPaint(row, column);
295         if (p != null) {
296             g2.setPaint(p);
297         }
298         Stroke JavaDoc s = getItemStroke(row, column);
299         g2.setStroke(s);
300
301         RectangleEdge location = plot.getRangeAxisEdge();
302
303         Number JavaDoc xQ1 = bawDataset.getQ1Value(row, column);
304         Number JavaDoc xQ3 = bawDataset.getQ3Value(row, column);
305         Number JavaDoc xMax = bawDataset.getMaxRegularValue(row, column);
306         Number JavaDoc xMin = bawDataset.getMinRegularValue(row, column);
307
308         if (xQ1 != null && xQ3 != null && xMax != null && xMin != null) {
309
310             double xxQ1 = rangeAxis.translateValueToJava2D(xQ1.doubleValue(), dataArea, location);
311             double xxQ3 = rangeAxis.translateValueToJava2D(xQ3.doubleValue(), dataArea, location);
312             double xxMax = rangeAxis.translateValueToJava2D(xMax.doubleValue(), dataArea, location);
313             double xxMin = rangeAxis.translateValueToJava2D(xMin.doubleValue(), dataArea, location);
314             // draw the upper shadow...
315
if ((xxMax > xxQ1) && (xxMax > xxQ3)) { // 0,0 = top left...
316
g2.draw(new Line2D.Double JavaDoc(xxMax, yy + this.boxWidth / 2,
317                                           Math.max(xxQ1, xxQ3), yy + this.boxWidth / 2));
318                 g2.draw(new Line2D.Double JavaDoc(xxMax, yy,
319                                           xxMax, yy + this.boxWidth));
320             }
321
322             // draw the lower shadow...
323
if ((xxMin < xxQ1) && (xxMin < xxQ3)) {
324                 g2.draw(new Line2D.Double JavaDoc(xxMin, yy + this.boxWidth / 2,
325                                           Math.min(xxQ1, xxQ3), yy + this.boxWidth / 2));
326                 g2.draw(new Line2D.Double JavaDoc(xxMin, yy,
327                                           xxMin, yy + this.boxWidth));
328             }
329
330             // draw the body...
331
Shape JavaDoc body = new Rectangle2D.Double JavaDoc(Math.min(xxQ1, xxQ3), yy,
332                                                 Math.abs(xxQ1 - xxQ3), this.boxWidth);
333             g2.fill(body);
334             g2.draw(body);
335
336         }
337
338         g2.setPaint(artifactPaint);
339         double aRadius = 0; // average radius
340

341         // draw mean - SPECIAL AIMS REQUIREMENT...
342
Number JavaDoc xMean = bawDataset.getMeanValue(row, column);
343         if (xMean != null) {
344             double xxMean = rangeAxis.translateValueToJava2D(xMean.doubleValue(), dataArea, location);
345             aRadius = this.boxWidth / 4;
346             Ellipse2D.Double JavaDoc avgEllipse = new Ellipse2D.Double JavaDoc(xxMean - aRadius, yy + aRadius,
347                                                                aRadius * 2, aRadius * 2);
348             g2.fill(avgEllipse);
349             g2.draw(avgEllipse);
350         }
351
352         // draw median...
353
Number JavaDoc xMedian = bawDataset.getMedianValue(row, column);
354         if (xMedian != null) {
355             double xxMedian = rangeAxis.translateValueToJava2D(
356                 xMedian.doubleValue(),
357                 dataArea,
358                 location);
359             g2.draw(new Line2D.Double JavaDoc(xxMedian, yy, xxMedian, yy + this.boxWidth));
360         }
361
362     }
363         
364     /**
365      * Draws the visual representation of a single data item when the plot has a vertical
366      * orientation.
367      *
368      * @param g2 the graphics device.
369      * @param dataArea the area within which the plot is being drawn.
370      * @param plot the plot (can be used to obtain standard color information etc).
371      * @param domainAxis the domain axis.
372      * @param rangeAxis the range axis.
373      * @param dataset the dataset.
374      * @param row the row index (zero-based).
375      * @param column the column index (zero-based).
376      */

377     public void drawVerticalItem(Graphics2D JavaDoc g2,
378                                  Rectangle2D JavaDoc dataArea,
379                                  CategoryPlot plot,
380                                  CategoryAxis domainAxis,
381                                  ValueAxis rangeAxis,
382                                  CategoryDataset dataset,
383                                  int row,
384                                  int column) {
385
386         // setup for collecting optional entity info...
387
// EntityCollection entities = null;
388
// if (info != null) {
389
// entities = info.getEntityCollection();
390
// }
391

392         BoxAndWhiskerCategoryDataset bawDataset = (BoxAndWhiskerCategoryDataset) dataset;
393         
394         double categoryEnd = domainAxis.getCategoryEnd(
395                 column, getColumnCount(), dataArea, plot.getDomainAxisEdge());
396         double categoryStart = domainAxis.getCategoryStart(
397                 column, getColumnCount(), dataArea, plot.getDomainAxisEdge());
398         double categoryWidth = categoryEnd - categoryStart;
399
400         double xx = categoryStart;
401         int seriesCount = getRowCount();
402         int categoryCount = getColumnCount();
403
404         if (seriesCount > 1) {
405             double seriesGap = dataArea.getWidth() * getItemMargin()
406                                / (categoryCount * (seriesCount - 1));
407             double usedWidth = (getBoxWidth() * seriesCount) + (seriesGap * (seriesCount - 1));
408             // offset the start of the boxes if the total width used is smaller than the category width
409
double offset = (categoryWidth - usedWidth) / 2;
410             xx = xx + offset + (row * (getBoxWidth() + seriesGap));
411         }
412         else {
413             // offset the start of the box if the box width is smaller than the category width
414
double offset = (categoryWidth - boxWidth) / 2;
415             xx = xx + offset;
416         }
417         
418         double yyAverage = 0.0;
419         double yyOutlier;
420
421         Paint JavaDoc p = this.getItemPaint(row, column);
422         if (p != null) {
423             g2.setPaint(p);
424         }
425         Stroke JavaDoc s = getItemStroke(row, column);
426         g2.setStroke(s);
427
428         double aRadius = 0; // average radius
429

430         RectangleEdge location = plot.getRangeAxisEdge();
431
432         Number JavaDoc yQ1 = bawDataset.getQ1Value(row, column);
433         Number JavaDoc yQ3 = bawDataset.getQ3Value(row, column);
434         Number JavaDoc yMax = bawDataset.getMaxRegularValue(row, column);
435         Number JavaDoc yMin = bawDataset.getMinRegularValue(row, column);
436         if (yQ1 != null && yQ3 != null && yMax != null && yMin != null) {
437
438             // draw the upper shadow...
439
double yyQ1 = rangeAxis.translateValueToJava2D(yQ1.doubleValue(), dataArea, location);
440             double yyQ3 = rangeAxis.translateValueToJava2D(yQ3.doubleValue(), dataArea, location);
441             double yyMax = rangeAxis.translateValueToJava2D(yMax.doubleValue(), dataArea, location);
442             double yyMin = rangeAxis.translateValueToJava2D(yMin.doubleValue(), dataArea, location);
443             if ((yyMax < yyQ1) && (yyMax < yyQ3)) { // 0,0 = top left...
444
g2.draw(new Line2D.Double JavaDoc(xx + this.boxWidth / 2, yyMax,
445                                           xx + this.boxWidth / 2, Math.max(yyQ1, yyQ3)));
446                 g2.draw(new Line2D.Double JavaDoc(xx, yyMax,
447                                           xx + this.boxWidth, yyMax));
448             }
449
450             // draw the lower shadow...
451
if ((yyMin > yyQ1) && (yyMin > yyQ3)) {
452                 g2.draw(new Line2D.Double JavaDoc(xx + this.boxWidth / 2, yyMin,
453                                           xx + this.boxWidth / 2, Math.min(yyQ1, yyQ3)));
454                 g2.draw(new Line2D.Double JavaDoc(xx, yyMin,
455                                           xx + this.boxWidth, yyMin));
456             }
457
458             // draw the body...
459
Shape JavaDoc body = new Rectangle2D.Double JavaDoc(xx, Math.min(yyQ1, yyQ3),
460                                                 this.boxWidth, Math.abs(yyQ1 - yyQ3));
461             g2.fill(body);
462             g2.draw(body);
463   
464         }
465         
466         g2.setPaint(artifactPaint);
467
468         // draw mean - SPECIAL AIMS REQUIREMENT...
469
Number JavaDoc yMean = bawDataset.getMeanValue(row, column);
470         if (yMean != null) {
471             yyAverage = rangeAxis.translateValueToJava2D(yMean.doubleValue(), dataArea, location);
472             aRadius = this.boxWidth / 4;
473             Ellipse2D.Double JavaDoc avgEllipse = new Ellipse2D.Double JavaDoc(xx + aRadius, yyAverage - aRadius,
474                                                                aRadius * 2, aRadius * 2);
475             g2.fill(avgEllipse);
476             g2.draw(avgEllipse);
477         }
478
479         // draw median...
480
Number JavaDoc yMedian = bawDataset.getMedianValue(row, column);
481         if (yMedian != null) {
482             double yyMedian = rangeAxis.translateValueToJava2D(yMedian.doubleValue(),
483                                                                dataArea, location);
484             g2.draw(new Line2D.Double JavaDoc(xx, yyMedian, xx + this.boxWidth, yyMedian));
485         }
486         
487         // draw yOutliers...
488
double maxAxisValue = rangeAxis.translateValueToJava2D(rangeAxis.getUpperBound(),
489                                                                dataArea, location) + aRadius;
490         double minAxisValue = rangeAxis.translateValueToJava2D(rangeAxis.getLowerBound(),
491                                                                dataArea, location) - aRadius;
492
493         g2.setPaint(p);
494
495         // draw outliers
496
double oRadius = this.boxWidth / 3; // outlier radius
497
List JavaDoc outliers = new ArrayList JavaDoc();
498         OutlierListCollection outlierListCollection = new OutlierListCollection();
499
500         // From outlier array sort out which are outliers and put these into a list
501
// If there are any farouts, set the flag on the OutlierListCollection
502
List JavaDoc yOutliers = bawDataset.getOutliers(row, column);
503         for (int i = 0; i < yOutliers.size(); i++) {
504             double outlier = ((Number JavaDoc) yOutliers.get(i)).doubleValue();
505             if (outlier > bawDataset.getMaxOutlier(row, column).doubleValue()) {
506                 outlierListCollection.setHighFarOut(true);
507             }
508             else if (outlier < bawDataset.getMinOutlier(row, column).doubleValue()) {
509                 outlierListCollection.setLowFarOut(true);
510             }
511             else if (outlier > bawDataset.getMaxRegularValue(row, column).doubleValue()) {
512                 yyOutlier = rangeAxis.translateValueToJava2D(outlier, dataArea, location);
513                 outliers.add(new Outlier(xx + this.boxWidth / 2.0, yyOutlier, oRadius));
514             }
515             else if (outlier < bawDataset.getMinRegularValue(row, column).doubleValue()) {
516                 yyOutlier = rangeAxis.translateValueToJava2D(outlier, dataArea, location);
517                 outliers.add(new Outlier(xx + this.boxWidth / 2.0, yyOutlier, oRadius));
518             }
519             Collections.sort(outliers);
520         }
521
522         // Process outliers. Each outlier is either added to the appropriate outlier list
523
// or a new outlier list is made
524
for (Iterator JavaDoc iterator = outliers.iterator(); iterator.hasNext();) {
525             Outlier outlier = (Outlier) iterator.next();
526             outlierListCollection.add(outlier);
527         }
528
529         for (Iterator JavaDoc iterator = outlierListCollection.iterator(); iterator.hasNext();) {
530             OutlierList list = (OutlierList) iterator.next();
531             Outlier outlier = list.getAveragedOutlier();
532             Point2D JavaDoc point = outlier.getPoint();
533
534             if (list.isMultiple()) {
535                 drawMultipleEllipse(point, this.boxWidth, oRadius, g2);
536             }
537             else {
538                 drawEllipse(point, oRadius, g2);
539             }
540         }
541
542         // draw farout indicators
543
if (outlierListCollection.isHighFarOut()) {
544             drawHighFarOut(aRadius / 2.0, g2, xx + this.boxWidth / 2.0, maxAxisValue);
545         }
546         
547         if (outlierListCollection.isLowFarOut()) {
548             drawLowFarOut(aRadius / 2.0, g2, xx + this.boxWidth / 2.0, minAxisValue);
549         }
550
551         // add an entity for the item...
552
// if (entities != null) {
553
// String tip = null;
554
// if (getToolTipGenerator() != null) {
555
// tip = getToolTipGenerator().generateToolTip(dataset, series, item);
556
// }
557
// String url = null;
558
// if (getURLGenerator() != null) {
559
// url = getURLGenerator().generateURL(dataset, series, item);
560
// }
561
// XYItemEntity entity = new XYItemEntity(body, dataset, series, item, tip, url);
562
// entities.addEntity(entity);
563
// }
564

565     }
566
567     /**
568      * Draws a dot to represent an outlier.
569      *
570      * @param point the location.
571      * @param oRadius the radius.
572      * @param g2 the graphics device.
573      */

574     private void drawEllipse(Point2D JavaDoc point, double oRadius, Graphics2D JavaDoc g2) {
575         Ellipse2D JavaDoc dot = new Ellipse2D.Double JavaDoc(point.getX() + oRadius / 2, point.getY(),
576                                              oRadius, oRadius);
577         g2.draw(dot);
578     }
579
580     /**
581      * Draws two dots to represent the average value of more than one outlier.
582      *
583      * @param point the location
584      * @param boxWidth the box width.
585      * @param oRadius the radius.
586      * @param g2 the graphics device.
587      */

588     private void drawMultipleEllipse(Point2D JavaDoc point, double boxWidth, double oRadius,
589                                      Graphics2D JavaDoc g2) {
590                                          
591         Ellipse2D JavaDoc dot1 = new Ellipse2D.Double JavaDoc(point.getX() - (boxWidth / 2) + oRadius, point.getY(),
592                                               oRadius, oRadius);
593         Ellipse2D JavaDoc dot2 = new Ellipse2D.Double JavaDoc(point.getX() + (boxWidth / 2), point.getY(),
594                                               oRadius, oRadius);
595         g2.draw(dot1);
596         g2.draw(dot2);
597     }
598
599     /**
600      * Draws a triangle to indicate the presence of far-out values.
601      *
602      * @param aRadius the radius.
603      * @param g2 the graphics device.
604      * @param xx the x coordinate.
605      * @param m the y coordinate.
606      */

607     private void drawHighFarOut(double aRadius, Graphics2D JavaDoc g2, double xx, double m) {
608         double side = aRadius * 2;
609         g2.draw(new Line2D.Double JavaDoc(xx - side, m + side, xx + side, m + side));
610         g2.draw(new Line2D.Double JavaDoc(xx - side, m + side, xx, m));
611         g2.draw(new Line2D.Double JavaDoc(xx + side, m + side, xx, m));
612     }
613
614     /**
615      * Draws a triangle to indicate the presence of far-out values.
616      *
617      * @param aRadius the radius.
618      * @param g2 the graphics device.
619      * @param xx the x coordinate.
620      * @param m the y coordinate.
621      */

622     private void drawLowFarOut(double aRadius, Graphics2D JavaDoc g2, double xx, double m) {
623         double side = aRadius * 2;
624         g2.draw(new Line2D.Double JavaDoc(xx - side, m - side, xx + side, m - side));
625         g2.draw(new Line2D.Double JavaDoc(xx - side, m - side, xx, m));
626         g2.draw(new Line2D.Double JavaDoc(xx + side, m - side, xx, m));
627     }
628 }
629
Popular Tags