KickJava   Java API By Example, From Geeks To Geeks.

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


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  * XYBoxAndWhiskerRenderer.java
24  * ----------------------------
25  * (C) Copyright 2003, by David Browning and Contributors.
26  *
27  * Original Author: David Browning (for Australian Institute of Marine Science);
28  * Contributor(s): David Gilbert (for Object Refinery Limited);
29  *
30  * $Id: XYBoxAndWhiskerRenderer.java,v 1.8 2003/11/03 14:21:28 mungady Exp $
31  *
32  * Changes
33  * -------
34  * 05-Aug-2003 : Version 1, contributed by David Browning. Based on code in the
35  * CandlestickRenderer class. Additional modifications by David Gilbert to
36  * make the code work with 0.9.10 changes (DG);
37  * 08-Aug-2003 : Updated some of the Javadoc
38  * Allowed BoxAndwhiskerDataset Average value to be null - the average value is an
39  * AIMS requirement
40  * Allow the outlier and farout coefficients to be set -
41  * though at the moment this only affects the calculation of farouts.
42  * Added artifactPaint variable and setter/getter
43  * 12-Aug-2003 Rewrote code to sort out and process outliers to take advantage of changes in
44  * DefaultBoxAndWhiskerDataset
45  * Added a limit of 10% for width of box should no width be specified...
46  * Maybe this should be setable???
47  * 20-Aug-2003 : Implemented Cloneable and PublicCloneable (DG);
48  * 08-Sep-2003 : Changed ValueAxis API (DG);
49  * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
50  *
51  *
52  * DO NOT USE drawHorizontalItem() - IT IS INCOMPLETE
53  * TO EXPERIMENT, USE drawVerticalItem()
54  *
55  */

56
57 package org.jfree.chart.renderer;
58
59 import java.awt.Color JavaDoc;
60 import java.awt.Graphics2D JavaDoc;
61 import java.awt.Paint JavaDoc;
62 import java.awt.Shape JavaDoc;
63 import java.awt.Stroke JavaDoc;
64 import java.awt.geom.Ellipse2D JavaDoc;
65 import java.awt.geom.Line2D JavaDoc;
66 import java.awt.geom.Point2D JavaDoc;
67 import java.awt.geom.Rectangle2D JavaDoc;
68 import java.io.IOException JavaDoc;
69 import java.io.ObjectInputStream JavaDoc;
70 import java.io.ObjectOutputStream JavaDoc;
71 import java.io.Serializable JavaDoc;
72 import java.util.ArrayList JavaDoc;
73 import java.util.Collections JavaDoc;
74 import java.util.Iterator JavaDoc;
75 import java.util.List JavaDoc;
76
77 import org.jfree.chart.CrosshairInfo;
78 import org.jfree.chart.axis.ValueAxis;
79 import org.jfree.chart.entity.EntityCollection;
80 import org.jfree.chart.entity.XYItemEntity;
81 import org.jfree.chart.labels.BoxAndWhiskerToolTipGenerator;
82 import org.jfree.chart.plot.PlotOrientation;
83 import org.jfree.chart.plot.PlotRenderingInfo;
84 import org.jfree.chart.plot.XYPlot;
85 import org.jfree.data.XYDataset;
86 import org.jfree.data.statistics.BoxAndWhiskerXYDataset;
87 import org.jfree.io.SerialUtilities;
88 import org.jfree.ui.RectangleEdge;
89 import org.jfree.util.PublicCloneable;
90
91 /**
92  * A renderer that draws box-and-whisker items on an {@link XYPlot}. This renderer requires a
93  * {@link BoxAndWhiskerXYDataset}).
94  *
95  * @author David Browning
96  */

97 public class XYBoxAndWhiskerRenderer extends AbstractXYItemRenderer
98                                      implements XYItemRenderer,
99                                                 Cloneable JavaDoc,
100                                                 PublicCloneable,
101                                                 Serializable JavaDoc {
102
103     /** The box width. */
104     private double boxWidth;
105
106     /** The paint used to fill the box. */
107     private transient Paint JavaDoc paint;
108
109     /**
110      * The paint used to draw various artifacts such as outliers, farout symbol, average
111      * ellipse and median line.
112      */

113     private Paint JavaDoc artifactPaint = Color.black;
114
115     /**
116      * Creates a new renderer for box and whisker charts.
117      */

118     public XYBoxAndWhiskerRenderer() {
119         this(-1.0);
120     }
121
122     /**
123      * Creates a new renderer for box and whisker charts.
124      * <P>
125      * Use -1 for the box width if you prefer the width to be calculated automatically.
126      *
127      * @param boxWidth The box width.
128      */

129     public XYBoxAndWhiskerRenderer(double boxWidth) {
130         super();
131         this.boxWidth = boxWidth;
132         this.paint = Color.green;
133         setToolTipGenerator(new BoxAndWhiskerToolTipGenerator());
134     }
135
136     /**
137      * Returns the width of each box.
138      *
139      * @return The box width.
140      */

141     public double getBoxWidth() {
142         return this.boxWidth;
143     }
144
145     /**
146      * Sets the box width.
147      * <P>
148      * If you set the width to a negative value, the renderer will calculate
149      * the box width automatically based on the space available on the chart.
150      *
151      * @param width The width.
152      */

153     public void setBoxWidth(double width) {
154
155         if (width != this.boxWidth) {
156             Double JavaDoc old = new Double JavaDoc(this.boxWidth);
157             this.boxWidth = width;
158             this.firePropertyChanged("BoxAndWhiskerRenderer.boxWidth", old, new Double JavaDoc(width));
159         }
160
161     }
162
163     /**
164      * Returns the paint used to fill boxes.
165      *
166      * @return The paint.
167      */

168     public Paint JavaDoc getPaint() {
169         return this.paint;
170     }
171
172     /**
173      * Sets the paint used to fill boxes.
174      * <P>
175      * Registered property change listeners are notified that the
176      * "BoxAndWhiskerRenderer.paint" property has changed.
177      *
178      * @param paint The paint.
179      */

180     public void setPaint(Paint JavaDoc paint) {
181
182         Paint JavaDoc old = this.paint;
183         this.paint = paint;
184         this.firePropertyChanged("BoxAndWhiskerRenderer.paint", old, paint);
185
186     }
187
188     /**
189      * Returns the paint used to paint the various artifacts such as outliers, farout symbol,
190      * median line and the averages ellipse.
191      *
192      * @return The paint.
193      */

194     public Paint JavaDoc getArtifactPaint() {
195         return artifactPaint;
196     }
197
198     /**
199      * Sets the paint used to paint the various artifacts such as outliers, farout symbol,
200      * median line and the averages ellipse.
201      *
202      * @param artifactPaint the paint.
203      */

204     public void setArtifactPaint(Paint JavaDoc artifactPaint) {
205         this.artifactPaint = artifactPaint;
206     }
207
208
209     /**
210      * Draws the visual representation of a single data item.
211      *
212      * @param g2 the graphics device.
213      * @param state the renderer state.
214      * @param dataArea the area within which the plot is being drawn.
215      * @param info collects info about the drawing.
216      * @param plot the plot (can be used to obtain standard color information etc).
217      * @param domainAxis the domain axis.
218      * @param rangeAxis the range axis.
219      * @param dataset the dataset.
220      * @param series the series index (zero-based).
221      * @param item the item index (zero-based).
222      * @param crosshairInfo information about crosshairs on a plot.
223      * @param pass the pass index.
224      */

225     public void drawItem(Graphics2D JavaDoc g2,
226                          XYItemRendererState state,
227                          Rectangle2D JavaDoc dataArea,
228                          PlotRenderingInfo info,
229                          XYPlot plot,
230                          ValueAxis domainAxis,
231                          ValueAxis rangeAxis,
232                          XYDataset dataset,
233                          int series,
234                          int item,
235                          CrosshairInfo crosshairInfo,
236                          int pass) {
237
238         PlotOrientation orientation = plot.getOrientation();
239         this.setPaint(getItemPaint(series, item));
240
241         if (orientation == PlotOrientation.HORIZONTAL) {
242             drawHorizontalItem(g2, dataArea, info, plot, domainAxis, rangeAxis,
243                                dataset, series, item,
244                                crosshairInfo, pass);
245         }
246         else if (orientation == PlotOrientation.VERTICAL) {
247             drawVerticalItem(g2, dataArea, info, plot, domainAxis, rangeAxis,
248                              dataset, series, item,
249                              crosshairInfo, pass);
250         }
251
252     }
253
254     /**
255      * Draws the visual representation of a single data item.
256      *
257      * @param g2 the graphics device.
258      * @param dataArea the area within which the plot is being drawn.
259      * @param info collects info about the drawing.
260      * @param plot the plot (can be used to obtain standard color information etc).
261      * @param domainAxis the domain axis.
262      * @param rangeAxis the range axis.
263      * @param dataset the dataset.
264      * @param series the series index (zero-based).
265      * @param item the item index (zero-based).
266      * @param crosshairInfo information about crosshairs on a plot.
267      * @param pass the pass index.
268      */

269     public void drawHorizontalItem(Graphics2D JavaDoc g2,
270                                    Rectangle2D JavaDoc dataArea,
271                                    PlotRenderingInfo info,
272                                    XYPlot plot,
273                                    ValueAxis domainAxis,
274                                    ValueAxis rangeAxis,
275                                    XYDataset dataset,
276                                    int series,
277                                    int item,
278                                    CrosshairInfo crosshairInfo,
279                                    int pass) {
280
281         // setup for collecting optional entity info...
282
EntityCollection entities = null;
283         if (info != null) {
284             entities = info.getOwner().getEntityCollection();
285         }
286
287
288         BoxAndWhiskerXYDataset boxAndWhiskerData = (BoxAndWhiskerXYDataset) dataset;
289
290         Number JavaDoc x = boxAndWhiskerData.getXValue(series, item);
291         Number JavaDoc yMax = boxAndWhiskerData.getMaxRegularValue(series, item);
292         Number JavaDoc yMin = boxAndWhiskerData.getMinRegularValue(series, item);
293         Number JavaDoc yQ1Median = boxAndWhiskerData.getQ1Value(series, item);
294         Number JavaDoc yQ3Median = boxAndWhiskerData.getQ3Value(series, item);
295
296         double xx = domainAxis.translateValueToJava2D(x.doubleValue(), dataArea,
297                                                       plot.getDomainAxisEdge());
298
299         RectangleEdge location = plot.getRangeAxisEdge();
300         double yyMax = rangeAxis.translateValueToJava2D(yMax.doubleValue(), dataArea, location);
301         double yyMin = rangeAxis.translateValueToJava2D(yMin.doubleValue(), dataArea, location);
302
303         double yyQ1Median = rangeAxis.translateValueToJava2D(yQ1Median.doubleValue(),
304                                                              dataArea, location);
305         double yyQ3Median = rangeAxis.translateValueToJava2D(yQ3Median.doubleValue(),
306                                                              dataArea, location);
307
308         double exactCandleWidth = boxWidth;
309         double thisCandleWidth = boxWidth;
310         if (boxWidth <= 0.0) {
311             int itemCount = boxAndWhiskerData.getItemCount(series);
312             exactCandleWidth = (dataArea.getHeight()) / itemCount * 4.5 / 7;
313             if (exactCandleWidth < 1) {
314                 exactCandleWidth = 1;
315             }
316             thisCandleWidth = exactCandleWidth;
317             if (thisCandleWidth < 3) {
318                 thisCandleWidth = 3;
319             }
320         }
321
322         Stroke JavaDoc s = getItemStroke(series, item);
323
324         g2.setStroke(s);
325
326         // draw the upper shadow
327
if ((yyMax > yyQ1Median) && (yyMax > yyQ3Median)) {
328             g2.draw(new Line2D.Double JavaDoc(yyMax, xx, Math.max(yyQ1Median, yyQ3Median), xx));
329         }
330
331         // draw the lower shadow
332
if ((yyMin < yyQ1Median) && (yyMin < yyQ3Median)) {
333             g2.draw(new Line2D.Double JavaDoc(yyMin, xx, Math.min(yyQ1Median, yyQ3Median), xx));
334         }
335
336
337         // draw the body
338
Shape JavaDoc body = null;
339         if (yyQ1Median < yyQ3Median) {
340             body = new Rectangle2D.Double JavaDoc(yyQ1Median, xx - thisCandleWidth / 2,
341                                           yyQ3Median - yyQ1Median, thisCandleWidth);
342         }
343         else {
344             body = new Rectangle2D.Double JavaDoc(yyQ3Median, xx - thisCandleWidth / 2,
345                                           yyQ1Median - yyQ3Median, thisCandleWidth);
346             if (paint != null) {
347                 g2.setPaint(paint);
348                 g2.fill(body);
349             }
350             g2.draw(body);
351         }
352
353         // add an entity for the item...
354
if (entities != null) {
355             String JavaDoc tip = null;
356             if (getToolTipGenerator() != null) {
357                 tip = getToolTipGenerator().generateToolTip(dataset, series, item);
358             }
359             String JavaDoc url = null;
360             if (getURLGenerator() != null) {
361                 url = getURLGenerator().generateURL(dataset, series, item);
362             }
363             XYItemEntity entity = new XYItemEntity(body, dataset, series, item, tip, url);
364             entities.addEntity(entity);
365         }
366
367     }
368
369     /**
370      * Draws the visual representation of a single data item.
371      *
372      * @param g2 the graphics device.
373      * @param dataArea the area within which the plot is being drawn.
374      * @param info collects info about the drawing.
375      * @param plot the plot (can be used to obtain standard color information etc).
376      * @param domainAxis the domain axis.
377      * @param rangeAxis the range axis.
378      * @param dataset the dataset.
379      * @param series the series index (zero-based).
380      * @param item the item index (zero-based).
381      * @param crosshairInfo information about crosshairs on a plot.
382      * @param pass the pass index.
383      */

384     public void drawVerticalItem(Graphics2D JavaDoc g2,
385                                  Rectangle2D JavaDoc dataArea,
386                                  PlotRenderingInfo info,
387                                  XYPlot plot,
388                                  ValueAxis domainAxis,
389                                  ValueAxis rangeAxis,
390                                  XYDataset dataset,
391                                  int series,
392                                  int item,
393                                  CrosshairInfo crosshairInfo,
394                                  int pass) {
395
396         // setup for collecting optional entity info...
397
EntityCollection entities = null;
398         if (info != null) {
399             entities = info.getOwner().getEntityCollection();
400         }
401
402         BoxAndWhiskerXYDataset boxAndWhiskerData = (BoxAndWhiskerXYDataset) dataset;
403
404         Number JavaDoc x = boxAndWhiskerData.getXValue(series, item);
405         Number JavaDoc yMax = boxAndWhiskerData.getMaxRegularValue(series, item);
406         Number JavaDoc yMin = boxAndWhiskerData.getMinRegularValue(series, item);
407         Number JavaDoc yMedian = boxAndWhiskerData.getMedianValue(series, item);
408         Number JavaDoc yAverage = boxAndWhiskerData.getMeanValue(series, item);
409         Number JavaDoc yQ1Median = boxAndWhiskerData.getQ1Value(series, item);
410         Number JavaDoc yQ3Median = boxAndWhiskerData.getQ3Value(series, item);
411         List JavaDoc yOutliers = boxAndWhiskerData.getOutliers(series, item);
412
413         double xx = domainAxis.translateValueToJava2D(x.doubleValue(), dataArea,
414                                                       plot.getDomainAxisEdge());
415
416         RectangleEdge location = plot.getRangeAxisEdge();
417         double yyMax = rangeAxis.translateValueToJava2D(yMax.doubleValue(), dataArea, location);
418         double yyMin = rangeAxis.translateValueToJava2D(yMin.doubleValue(), dataArea, location);
419         double yyMedian = rangeAxis.translateValueToJava2D(yMedian.doubleValue(),
420                                                            dataArea, location);
421         double yyAverage = 0.0;
422         if (yAverage != null) {
423             yyAverage = rangeAxis.translateValueToJava2D(yAverage.doubleValue(),
424                                                          dataArea, location);
425         }
426         double yyQ1Median = rangeAxis.translateValueToJava2D(yQ1Median.doubleValue(),
427                                           dataArea, location); // should be low range
428
double yyQ3Median = rangeAxis.translateValueToJava2D(yQ3Median.doubleValue(),
429                                           dataArea, location); // should be high range
430
double yyOutlier;
431
432
433         double exactBoxWidth = boxWidth;
434         double width = this.boxWidth;
435         double dataAreaX = dataArea.getMaxX() - dataArea.getMinX();
436         double maxBoxPercent = 0.1;
437         double maxBoxWidth = dataAreaX * maxBoxPercent;
438         if (boxWidth <= 0.0) {
439             int itemCount = boxAndWhiskerData.getItemCount(series);
440             exactBoxWidth = dataAreaX / itemCount * 4.5 / 7;
441             if (exactBoxWidth < 3) {
442                 width = 3;
443             }
444             else if (exactBoxWidth > maxBoxWidth) {
445                 width = maxBoxWidth;
446             }
447             else {
448                 width = exactBoxWidth;
449             }
450         }
451
452         Paint JavaDoc p = this.getPaint();
453         if (p != null) {
454             g2.setPaint(p);
455         }
456         Stroke JavaDoc s = getItemStroke(series, item);
457
458         g2.setStroke(s);
459
460         // draw the upper shadow
461
if ((yyMax < yyQ1Median) && (yyMax < yyQ3Median)) { // 0,0 = top left...
462
g2.draw(new Line2D.Double JavaDoc(xx, yyMax, xx, Math.max(yyQ1Median, yyQ3Median)));
463             g2.draw(new Line2D.Double JavaDoc(xx - width / 2, yyMax, xx + width / 2, yyMax));
464         }
465
466         // draw the lower shadow
467
if ((yyMin > yyQ1Median) && (yyMin > yyQ3Median)) {
468             g2.draw(new Line2D.Double JavaDoc(xx, yyMin, xx,
469                 Math.min(yyQ1Median, yyQ3Median)));
470             g2.draw(new Line2D.Double JavaDoc(xx - width / 2, yyMin, xx + width / 2, yyMin));
471         }
472
473
474         // draw the body
475
Shape JavaDoc body = null;
476         if (yyQ1Median > yyQ3Median) {
477             body = new Rectangle2D.Double JavaDoc(xx - width / 2, yyQ3Median,
478                                           width, yyQ1Median - yyQ3Median);
479         }
480         else {
481             body = new Rectangle2D.Double JavaDoc(xx - width / 2, yyQ1Median,
482                                           width, yyQ3Median - yyQ1Median);
483         }
484         g2.fill(body);
485         g2.draw(body);
486
487         // draw median
488
g2.setPaint(this.artifactPaint);
489         g2.draw(new Line2D.Double JavaDoc(xx - width / 2, yyMedian, xx + width / 2, yyMedian));
490
491         double aRadius = 0; // average radius
492
double oRadius = width / 3; // outlier radius
493

494         // draw average - SPECIAL AIMS REQUIREMENT
495
if (yAverage != null) {
496             aRadius = width / 4;
497             Ellipse2D.Double JavaDoc avgEllipse = new Ellipse2D.Double JavaDoc(xx - aRadius, yyAverage - aRadius,
498                                                                aRadius * 2, aRadius * 2);
499             g2.fill(avgEllipse);
500             g2.draw(avgEllipse);
501         }
502
503         List JavaDoc outliers = new ArrayList JavaDoc();
504         OutlierListCollection outlierListCollection = new OutlierListCollection();
505
506
507         /* From outlier array sort out which are outliers and put these into an arraylist
508          * If there are any farouts, set the flag on the OutlierListCollection
509          */

510
511         for (int i = 0; i < yOutliers.size(); i++) {
512             double outlier = ((Number JavaDoc) yOutliers.get(i)).doubleValue();
513             if (outlier > boxAndWhiskerData.getMaxOutlier(series, item).doubleValue()) {
514                 outlierListCollection.setHighFarOut(true);
515             }
516             else if (outlier < boxAndWhiskerData.getMinOutlier(series, item).doubleValue()) {
517                 outlierListCollection.setLowFarOut(true);
518             }
519             else if (outlier > boxAndWhiskerData.getMaxRegularValue(series, item).doubleValue()) {
520                 yyOutlier = rangeAxis.translateValueToJava2D(outlier, dataArea, location);
521                 outliers.add(new Outlier(xx, yyOutlier, oRadius));
522             }
523             else if (outlier < boxAndWhiskerData.getMinRegularValue(series, item).doubleValue()) {
524                 yyOutlier = rangeAxis.translateValueToJava2D(outlier, dataArea, location);
525                 outliers.add(new Outlier(xx, yyOutlier, oRadius));
526             }
527             Collections.sort(outliers);
528         }
529
530         // Process outliers. Each outlier is either added to the appropriate outlier list
531
// or a new outlier list is made
532
for (Iterator JavaDoc iterator = outliers.iterator(); iterator.hasNext();) {
533             Outlier outlier = (Outlier) iterator.next();
534             outlierListCollection.add(outlier);
535         }
536
537         // draw yOutliers
538
double maxAxisValue = rangeAxis.translateValueToJava2D(rangeAxis.getUpperBound(),
539                                   dataArea, location) + aRadius;
540         double minAxisValue = rangeAxis.translateValueToJava2D(rangeAxis.getLowerBound(),
541                                   dataArea, location) - aRadius;
542
543         //g2.setPaint(p);
544

545         // draw outliers
546
for (Iterator JavaDoc iterator = outlierListCollection.iterator(); iterator.hasNext();) {
547             OutlierList list = (OutlierList) iterator.next();
548             Outlier outlier = list.getAveragedOutlier();
549             Point2D JavaDoc point = outlier.getPoint();
550
551             if (list.isMultiple()) {
552                 drawMultipleEllipse(point, width, oRadius, g2);
553             }
554             else {
555                 drawEllipse(point, oRadius, g2);
556             }
557         }
558
559         // draw farout
560
if (outlierListCollection.isHighFarOut()) {
561             drawHighFarOut(aRadius, g2, xx, maxAxisValue);
562         }
563
564         if (outlierListCollection.isLowFarOut()) {
565             drawLowFarOut(aRadius, g2, xx, minAxisValue);
566         }
567         
568         // add an entity for the item...
569
if (entities != null) {
570             String JavaDoc tip = null;
571             if (getToolTipGenerator() != null) {
572                 tip = getToolTipGenerator().generateToolTip(dataset, series, item);
573             }
574             String JavaDoc url = null;
575             if (getURLGenerator() != null) {
576                 url = getURLGenerator().generateURL(dataset, series, item);
577             }
578             XYItemEntity entity = new XYItemEntity(body, dataset, series, item, tip, url);
579             entities.addEntity(entity);
580         }
581
582     }
583
584     /**
585      * Draws an ellipse to represent an outlier.
586      *
587      * @param point the location.
588      * @param oRadius the radius.
589      * @param g2 the graphics device.
590      */

591     private void drawEllipse(Point2D JavaDoc point, double oRadius, Graphics2D JavaDoc g2) {
592         Ellipse2D.Double JavaDoc dot = new Ellipse2D.Double JavaDoc(point.getX() + oRadius / 2, point.getY(),
593                                                     oRadius, oRadius);
594         g2.draw(dot);
595     }
596
597     /**
598      * Draws two ellipses to represent overlapping outliers.
599      *
600      * @param point the location.
601      * @param boxWidth the box width.
602      * @param oRadius the radius.
603      * @param g2 the graphics device.
604      */

605     private void drawMultipleEllipse(Point2D JavaDoc point, double boxWidth, double oRadius,
606                                      Graphics2D JavaDoc g2) {
607                                          
608         Ellipse2D.Double JavaDoc dot1 = new Ellipse2D.Double JavaDoc(point.getX() - (boxWidth / 2) + oRadius,
609                                                      point.getY(), oRadius, oRadius);
610         Ellipse2D.Double JavaDoc dot2 = new Ellipse2D.Double JavaDoc(point.getX() + (boxWidth / 2),
611                                                      point.getY(), oRadius, oRadius);
612         g2.draw(dot1);
613         g2.draw(dot2);
614         
615     }
616
617     /**
618      * Draws a triangle to indicate the presence of far out values.
619      *
620      * @param aRadius the radius.
621      * @param g2 the graphics device.
622      * @param xx the x value.
623      * @param m the max y value.
624      */

625     private void drawHighFarOut(double aRadius, Graphics2D JavaDoc g2, double xx, double m) {
626         double side = aRadius * 2;
627         g2.draw(new Line2D.Double JavaDoc(xx - side, m + side, xx + side, m + side));
628         g2.draw(new Line2D.Double JavaDoc(xx - side, m + side, xx, m));
629         g2.draw(new Line2D.Double JavaDoc(xx + side, m + side, xx, m));
630     }
631
632     /**
633      * Draws a triangle to indicate the presence of far out values.
634      *
635      * @param aRadius the radius.
636      * @param g2 the graphics device.
637      * @param xx the x value.
638      * @param m the min y value.
639      */

640     private void drawLowFarOut(double aRadius, Graphics2D JavaDoc g2, double xx, double m) {
641         double side = aRadius * 2;
642         g2.draw(new Line2D.Double JavaDoc(xx - side, m - side, xx + side, m - side));
643         g2.draw(new Line2D.Double JavaDoc(xx - side, m - side, xx, m));
644         g2.draw(new Line2D.Double JavaDoc(xx + side, m - side, xx, m));
645     }
646
647     /**
648      * Tests this renderer for equality with another object.
649      *
650      * @param obj the object.
651      *
652      * @return <code>true</code> or <code>false</code>.
653      */

654     public boolean equals(Object JavaDoc obj) {
655
656         if (obj == null) {
657             return false;
658         }
659
660         if (obj == this) {
661             return true;
662         }
663
664         if (obj instanceof XYBoxAndWhiskerRenderer) {
665             XYBoxAndWhiskerRenderer renderer = (XYBoxAndWhiskerRenderer) obj;
666             boolean result = super.equals(obj);
667             result = result && (this.boxWidth == renderer.getBoxWidth());
668             result = result && (this.paint.equals(renderer.getPaint()));
669             return result;
670         }
671
672         return false;
673
674     }
675
676     /**
677      * Provides serialization support.
678      *
679      * @param stream the output stream.
680      *
681      * @throws IOException if there is an I/O error.
682      */

683     private void writeObject(ObjectOutputStream JavaDoc stream) throws IOException JavaDoc {
684
685         stream.defaultWriteObject();
686         SerialUtilities.writePaint(this.paint, stream);
687
688     }
689
690     /**
691      * Provides serialization support.
692      *
693      * @param stream the input stream.
694      *
695      * @throws IOException if there is an I/O error.
696      * @throws ClassNotFoundException if there is a classpath problem.
697      */

698     private void readObject(ObjectInputStream JavaDoc stream) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
699
700         stream.defaultReadObject();
701         this.paint = SerialUtilities.readPaint(stream);
702
703     }
704
705     /**
706      * Returns a clone of the renderer.
707      *
708      * @return A clone.
709      *
710      * @throws CloneNotSupportedException if the renderer cannot be cloned.
711      */

712     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
713         return super.clone();
714     }
715
716 }
717
Popular Tags