001 /* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
006 *
007 * Project Info: http://www.jfree.org/jfreechart/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022 * USA.
023 *
024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025 * in the United States and other countries.]
026 *
027 * ----------------------------------------
028 * DefaultBoxAndWhiskerCategoryDataset.java
029 * ----------------------------------------
030 * (C) Copyright 2003-2007, by David Browning and Contributors.
031 *
032 * Original Author: David Browning (for Australian Institute of Marine
033 * Science);
034 * Contributor(s): David Gilbert (for Object Refinery Limited);
035 *
036 * Changes
037 * -------
038 * 05-Aug-2003 : Version 1, contributed by David Browning (DG);
039 * 27-Aug-2003 : Moved from org.jfree.data --> org.jfree.data.statistics (DG);
040 * 12-Nov-2003 : Changed 'data' from private to protected and added a new 'add'
041 * method as proposed by Tim Bardzil. Also removed old code (DG);
042 * 01-Mar-2004 : Added equals() method (DG);
043 * 18-Nov-2004 : Updates for changes in RangeInfo interface (DG);
044 * 11-Jan-2005 : Removed deprecated code in preparation for the 1.0.0
045 * release (DG);
046 * ------------- JFREECHART 1.0.x ---------------------------------------------
047 * 02-Feb-2007 : Removed author tags from all over JFreeChart sources (DG);
048 * 17-Apr-2007 : Fixed bug 1701822 (DG);
049 * 13-Jun-2007 : Fixed error in previous patch (DG);
050 * 28-Sep-2007 : Fixed cloning bug (DG);
051 * 02-Oct-2007 : Fixed bug in updating cached bounds (DG);
052 * 03-Oct-2007 : Fixed another bug in updating cached bounds, added removal
053 * methods (DG);
054 *
055 */
056
057 package org.jfree.data.statistics;
058
059 import java.util.List;
060
061 import org.jfree.data.KeyedObjects2D;
062 import org.jfree.data.Range;
063 import org.jfree.data.RangeInfo;
064 import org.jfree.data.general.AbstractDataset;
065 import org.jfree.data.general.DatasetChangeEvent;
066 import org.jfree.util.ObjectUtilities;
067 import org.jfree.util.PublicCloneable;
068
069 /**
070 * A convenience class that provides a default implementation of the
071 * {@link BoxAndWhiskerCategoryDataset} interface.
072 */
073 public class DefaultBoxAndWhiskerCategoryDataset extends AbstractDataset
074 implements BoxAndWhiskerCategoryDataset, RangeInfo, PublicCloneable {
075
076 /** Storage for the data. */
077 protected KeyedObjects2D data;
078
079 /** The minimum range value. */
080 private double minimumRangeValue;
081
082 /** The row index for the cell that the minimum range value comes from. */
083 private int minimumRangeValueRow;
084
085 /**
086 * The column index for the cell that the minimum range value comes from.
087 */
088 private int minimumRangeValueColumn;
089
090 /** The maximum range value. */
091 private double maximumRangeValue;
092
093 /** The row index for the cell that the maximum range value comes from. */
094 private int maximumRangeValueRow;
095
096 /**
097 * The column index for the cell that the maximum range value comes from.
098 */
099 private int maximumRangeValueColumn;
100
101 /**
102 * Creates a new dataset.
103 */
104 public DefaultBoxAndWhiskerCategoryDataset() {
105 this.data = new KeyedObjects2D();
106 this.minimumRangeValue = Double.NaN;
107 this.minimumRangeValueRow = -1;
108 this.minimumRangeValueColumn = -1;
109 this.maximumRangeValue = Double.NaN;
110 this.maximumRangeValueRow = -1;
111 this.maximumRangeValueColumn = -1;
112 }
113
114 /**
115 * Adds a list of values relating to one box-and-whisker entity to the
116 * table. The various median values are calculated.
117 *
118 * @param list a collection of values from which the various medians will
119 * be calculated.
120 * @param rowKey the row key (<code>null</code> not permitted).
121 * @param columnKey the column key (<code>null</code> not permitted).
122 *
123 * @see #add(BoxAndWhiskerItem, Comparable, Comparable)
124 */
125 public void add(List list, Comparable rowKey, Comparable columnKey) {
126 BoxAndWhiskerItem item = BoxAndWhiskerCalculator
127 .calculateBoxAndWhiskerStatistics(list);
128 add(item, rowKey, columnKey);
129 }
130
131 /**
132 * Adds a list of values relating to one Box and Whisker entity to the
133 * table. The various median values are calculated.
134 *
135 * @param item a box and whisker item (<code>null</code> not permitted).
136 * @param rowKey the row key (<code>null</code> not permitted).
137 * @param columnKey the column key (<code>null</code> not permitted).
138 *
139 * @see #add(List, Comparable, Comparable)
140 */
141 public void add(BoxAndWhiskerItem item, Comparable rowKey,
142 Comparable columnKey) {
143
144 this.data.addObject(item, rowKey, columnKey);
145
146 // update cached min and max values
147 int r = this.data.getRowIndex(rowKey);
148 int c = this.data.getColumnIndex(columnKey);
149 if ((this.maximumRangeValueRow == r && this.maximumRangeValueColumn
150 == c) || (this.minimumRangeValueRow == r
151 && this.minimumRangeValueColumn == c)) {
152 updateBounds();
153 }
154 else {
155
156 double minval = Double.NaN;
157 if (item.getMinOutlier() != null) {
158 minval = item.getMinOutlier().doubleValue();
159 }
160 double maxval = Double.NaN;
161 if (item.getMaxOutlier() != null) {
162 maxval = item.getMaxOutlier().doubleValue();
163 }
164
165 if (Double.isNaN(this.maximumRangeValue)) {
166 this.maximumRangeValue = maxval;
167 this.maximumRangeValueRow = r;
168 this.maximumRangeValueColumn = c;
169 }
170 else if (maxval > this.maximumRangeValue) {
171 this.maximumRangeValue = maxval;
172 this.maximumRangeValueRow = r;
173 this.maximumRangeValueColumn = c;
174 }
175
176 if (Double.isNaN(this.minimumRangeValue)) {
177 this.minimumRangeValue = minval;
178 this.minimumRangeValueRow = r;
179 this.minimumRangeValueColumn = c;
180 }
181 else if (minval < this.minimumRangeValue) {
182 this.minimumRangeValue = minval;
183 this.minimumRangeValueRow = r;
184 this.minimumRangeValueColumn = c;
185 }
186 }
187
188 fireDatasetChanged();
189
190 }
191
192 /**
193 * Removes an item from the dataset and sends a {@link DatasetChangeEvent}
194 * to all registered listeners.
195 *
196 * @param rowKey the row key (<code>null</code> not permitted).
197 * @param columnKey the column key (<code>null</code> not permitted).
198 *
199 * @see #add(BoxAndWhiskerItem, Comparable, Comparable)
200 *
201 * @since 1.0.7
202 */
203 public void remove(Comparable rowKey, Comparable columnKey) {
204 // defer null argument checks
205 int r = getRowIndex(rowKey);
206 int c = getColumnIndex(columnKey);
207 this.data.removeObject(rowKey, columnKey);
208
209 // if this cell held a maximum and/or minimum value, we'll need to
210 // update the cached bounds...
211 if ((this.maximumRangeValueRow == r && this.maximumRangeValueColumn
212 == c) || (this.minimumRangeValueRow == r
213 && this.minimumRangeValueColumn == c)) {
214 updateBounds();
215 }
216
217 fireDatasetChanged();
218 }
219
220 /**
221 * Removes a row from the dataset and sends a {@link DatasetChangeEvent}
222 * to all registered listeners.
223 *
224 * @param rowIndex the row index.
225 *
226 * @see #removeColumn(int)
227 *
228 * @since 1.0.7
229 */
230 public void removeRow(int rowIndex) {
231 this.data.removeRow(rowIndex);
232 updateBounds();
233 fireDatasetChanged();
234 }
235
236 /**
237 * Removes a row from the dataset and sends a {@link DatasetChangeEvent}
238 * to all registered listeners.
239 *
240 * @param rowKey the row key.
241 *
242 * @see #removeColumn(Comparable)
243 *
244 * @since 1.0.7
245 */
246 public void removeRow(Comparable rowKey) {
247 this.data.removeRow(rowKey);
248 updateBounds();
249 fireDatasetChanged();
250 }
251
252 /**
253 * Removes a column from the dataset and sends a {@link DatasetChangeEvent}
254 * to all registered listeners.
255 *
256 * @param columnIndex the column index.
257 *
258 * @see #removeRow(int)
259 *
260 * @since 1.0.7
261 */
262 public void removeColumn(int columnIndex) {
263 this.data.removeColumn(columnIndex);
264 updateBounds();
265 fireDatasetChanged();
266 }
267
268 /**
269 * Removes a column from the dataset and sends a {@link DatasetChangeEvent}
270 * to all registered listeners.
271 *
272 * @param columnKey the column key.
273 *
274 * @see #removeRow(Comparable)
275 *
276 * @since 1.0.7
277 */
278 public void removeColumn(Comparable columnKey) {
279 this.data.removeColumn(columnKey);
280 updateBounds();
281 fireDatasetChanged();
282 }
283
284 /**
285 * Clears all data from the dataset and sends a {@link DatasetChangeEvent}
286 * to all registered listeners.
287 *
288 * @since 1.0.7
289 */
290 public void clear() {
291 this.data.clear();
292 updateBounds();
293 fireDatasetChanged();
294 }
295
296 /**
297 * Return an item from within the dataset.
298 *
299 * @param row the row index.
300 * @param column the column index.
301 *
302 * @return The item.
303 */
304 public BoxAndWhiskerItem getItem(int row, int column) {
305 return (BoxAndWhiskerItem) this.data.getObject(row, column);
306 }
307
308 /**
309 * Returns the value for an item.
310 *
311 * @param row the row index.
312 * @param column the column index.
313 *
314 * @return The value.
315 *
316 * @see #getMedianValue(int, int)
317 * @see #getValue(Comparable, Comparable)
318 */
319 public Number getValue(int row, int column) {
320 return getMedianValue(row, column);
321 }
322
323 /**
324 * Returns the value for an item.
325 *
326 * @param rowKey the row key.
327 * @param columnKey the columnKey.
328 *
329 * @return The value.
330 *
331 * @see #getMedianValue(Comparable, Comparable)
332 * @see #getValue(int, int)
333 */
334 public Number getValue(Comparable rowKey, Comparable columnKey) {
335 return getMedianValue(rowKey, columnKey);
336 }
337
338 /**
339 * Returns the mean value for an item.
340 *
341 * @param row the row index (zero-based).
342 * @param column the column index (zero-based).
343 *
344 * @return The mean value.
345 *
346 * @see #getItem(int, int)
347 */
348 public Number getMeanValue(int row, int column) {
349
350 Number result = null;
351 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(row,
352 column);
353 if (item != null) {
354 result = item.getMean();
355 }
356 return result;
357
358 }
359
360 /**
361 * Returns the mean value for an item.
362 *
363 * @param rowKey the row key.
364 * @param columnKey the column key.
365 *
366 * @return The mean value.
367 *
368 * @see #getItem(int, int)
369 */
370 public Number getMeanValue(Comparable rowKey, Comparable columnKey) {
371 Number result = null;
372 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
373 rowKey, columnKey);
374 if (item != null) {
375 result = item.getMean();
376 }
377 return result;
378 }
379
380 /**
381 * Returns the median value for an item.
382 *
383 * @param row the row index (zero-based).
384 * @param column the column index (zero-based).
385 *
386 * @return The median value.
387 *
388 * @see #getItem(int, int)
389 */
390 public Number getMedianValue(int row, int column) {
391 Number result = null;
392 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(row,
393 column);
394 if (item != null) {
395 result = item.getMedian();
396 }
397 return result;
398 }
399
400 /**
401 * Returns the median value for an item.
402 *
403 * @param rowKey the row key.
404 * @param columnKey the columnKey.
405 *
406 * @return The median value.
407 *
408 * @see #getItem(int, int)
409 */
410 public Number getMedianValue(Comparable rowKey, Comparable columnKey) {
411 Number result = null;
412 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
413 rowKey, columnKey);
414 if (item != null) {
415 result = item.getMedian();
416 }
417 return result;
418 }
419
420 /**
421 * Returns the first quartile value.
422 *
423 * @param row the row index (zero-based).
424 * @param column the column index (zero-based).
425 *
426 * @return The first quartile value.
427 *
428 * @see #getItem(int, int)
429 */
430 public Number getQ1Value(int row, int column) {
431 Number result = null;
432 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
433 row, column);
434 if (item != null) {
435 result = item.getQ1();
436 }
437 return result;
438 }
439
440 /**
441 * Returns the first quartile value.
442 *
443 * @param rowKey the row key.
444 * @param columnKey the column key.
445 *
446 * @return The first quartile value.
447 *
448 * @see #getItem(int, int)
449 */
450 public Number getQ1Value(Comparable rowKey, Comparable columnKey) {
451 Number result = null;
452 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
453 rowKey, columnKey);
454 if (item != null) {
455 result = item.getQ1();
456 }
457 return result;
458 }
459
460 /**
461 * Returns the third quartile value.
462 *
463 * @param row the row index (zero-based).
464 * @param column the column index (zero-based).
465 *
466 * @return The third quartile value.
467 *
468 * @see #getItem(int, int)
469 */
470 public Number getQ3Value(int row, int column) {
471 Number result = null;
472 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
473 row, column);
474 if (item != null) {
475 result = item.getQ3();
476 }
477 return result;
478 }
479
480 /**
481 * Returns the third quartile value.
482 *
483 * @param rowKey the row key.
484 * @param columnKey the column key.
485 *
486 * @return The third quartile value.
487 *
488 * @see #getItem(int, int)
489 */
490 public Number getQ3Value(Comparable rowKey, Comparable columnKey) {
491 Number result = null;
492 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
493 rowKey, columnKey);
494 if (item != null) {
495 result = item.getQ3();
496 }
497 return result;
498 }
499
500 /**
501 * Returns the column index for a given key.
502 *
503 * @param key the column key (<code>null</code> not permitted).
504 *
505 * @return The column index.
506 *
507 * @see #getColumnKey(int)
508 */
509 public int getColumnIndex(Comparable key) {
510 return this.data.getColumnIndex(key);
511 }
512
513 /**
514 * Returns a column key.
515 *
516 * @param column the column index (zero-based).
517 *
518 * @return The column key.
519 *
520 * @see #getColumnIndex(Comparable)
521 */
522 public Comparable getColumnKey(int column) {
523 return this.data.getColumnKey(column);
524 }
525
526 /**
527 * Returns the column keys.
528 *
529 * @return The keys.
530 *
531 * @see #getRowKeys()
532 */
533 public List getColumnKeys() {
534 return this.data.getColumnKeys();
535 }
536
537 /**
538 * Returns the row index for a given key.
539 *
540 * @param key the row key (<code>null</code> not permitted).
541 *
542 * @return The row index.
543 *
544 * @see #getRowKey(int)
545 */
546 public int getRowIndex(Comparable key) {
547 // defer null argument check
548 return this.data.getRowIndex(key);
549 }
550
551 /**
552 * Returns a row key.
553 *
554 * @param row the row index (zero-based).
555 *
556 * @return The row key.
557 *
558 * @see #getRowIndex(Comparable)
559 */
560 public Comparable getRowKey(int row) {
561 return this.data.getRowKey(row);
562 }
563
564 /**
565 * Returns the row keys.
566 *
567 * @return The keys.
568 *
569 * @see #getColumnKeys()
570 */
571 public List getRowKeys() {
572 return this.data.getRowKeys();
573 }
574
575 /**
576 * Returns the number of rows in the table.
577 *
578 * @return The row count.
579 *
580 * @see #getColumnCount()
581 */
582 public int getRowCount() {
583 return this.data.getRowCount();
584 }
585
586 /**
587 * Returns the number of columns in the table.
588 *
589 * @return The column count.
590 *
591 * @see #getRowCount()
592 */
593 public int getColumnCount() {
594 return this.data.getColumnCount();
595 }
596
597 /**
598 * Returns the minimum y-value in the dataset.
599 *
600 * @param includeInterval a flag that determines whether or not the
601 * y-interval is taken into account.
602 *
603 * @return The minimum value.
604 *
605 * @see #getRangeUpperBound(boolean)
606 */
607 public double getRangeLowerBound(boolean includeInterval) {
608 return this.minimumRangeValue;
609 }
610
611 /**
612 * Returns the maximum y-value in the dataset.
613 *
614 * @param includeInterval a flag that determines whether or not the
615 * y-interval is taken into account.
616 *
617 * @return The maximum value.
618 *
619 * @see #getRangeLowerBound(boolean)
620 */
621 public double getRangeUpperBound(boolean includeInterval) {
622 return this.maximumRangeValue;
623 }
624
625 /**
626 * Returns the range of the values in this dataset's range.
627 *
628 * @param includeInterval a flag that determines whether or not the
629 * y-interval is taken into account.
630 *
631 * @return The range.
632 */
633 public Range getRangeBounds(boolean includeInterval) {
634 return new Range(this.minimumRangeValue, this.maximumRangeValue);
635 }
636
637 /**
638 * Returns the minimum regular (non outlier) value for an item.
639 *
640 * @param row the row index (zero-based).
641 * @param column the column index (zero-based).
642 *
643 * @return The minimum regular value.
644 *
645 * @see #getItem(int, int)
646 */
647 public Number getMinRegularValue(int row, int column) {
648 Number result = null;
649 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
650 row, column);
651 if (item != null) {
652 result = item.getMinRegularValue();
653 }
654 return result;
655 }
656
657 /**
658 * Returns the minimum regular (non outlier) value for an item.
659 *
660 * @param rowKey the row key.
661 * @param columnKey the column key.
662 *
663 * @return The minimum regular value.
664 *
665 * @see #getItem(int, int)
666 */
667 public Number getMinRegularValue(Comparable rowKey, Comparable columnKey) {
668 Number result = null;
669 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
670 rowKey, columnKey);
671 if (item != null) {
672 result = item.getMinRegularValue();
673 }
674 return result;
675 }
676
677 /**
678 * Returns the maximum regular (non outlier) value for an item.
679 *
680 * @param row the row index (zero-based).
681 * @param column the column index (zero-based).
682 *
683 * @return The maximum regular value.
684 *
685 * @see #getItem(int, int)
686 */
687 public Number getMaxRegularValue(int row, int column) {
688 Number result = null;
689 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
690 row, column);
691 if (item != null) {
692 result = item.getMaxRegularValue();
693 }
694 return result;
695 }
696
697 /**
698 * Returns the maximum regular (non outlier) value for an item.
699 *
700 * @param rowKey the row key.
701 * @param columnKey the column key.
702 *
703 * @return The maximum regular value.
704 *
705 * @see #getItem(int, int)
706 */
707 public Number getMaxRegularValue(Comparable rowKey, Comparable columnKey) {
708 Number result = null;
709 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
710 rowKey, columnKey);
711 if (item != null) {
712 result = item.getMaxRegularValue();
713 }
714 return result;
715 }
716
717 /**
718 * Returns the minimum outlier (non farout) value for an item.
719 *
720 * @param row the row index (zero-based).
721 * @param column the column index (zero-based).
722 *
723 * @return The minimum outlier.
724 *
725 * @see #getItem(int, int)
726 */
727 public Number getMinOutlier(int row, int column) {
728 Number result = null;
729 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
730 row, column);
731 if (item != null) {
732 result = item.getMinOutlier();
733 }
734 return result;
735 }
736
737 /**
738 * Returns the minimum outlier (non farout) value for an item.
739 *
740 * @param rowKey the row key.
741 * @param columnKey the column key.
742 *
743 * @return The minimum outlier.
744 *
745 * @see #getItem(int, int)
746 */
747 public Number getMinOutlier(Comparable rowKey, Comparable columnKey) {
748 Number result = null;
749 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
750 rowKey, columnKey);
751 if (item != null) {
752 result = item.getMinOutlier();
753 }
754 return result;
755 }
756
757 /**
758 * Returns the maximum outlier (non farout) value for an item.
759 *
760 * @param row the row index (zero-based).
761 * @param column the column index (zero-based).
762 *
763 * @return The maximum outlier.
764 *
765 * @see #getItem(int, int)
766 */
767 public Number getMaxOutlier(int row, int column) {
768 Number result = null;
769 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
770 row, column);
771 if (item != null) {
772 result = item.getMaxOutlier();
773 }
774 return result;
775 }
776
777 /**
778 * Returns the maximum outlier (non farout) value for an item.
779 *
780 * @param rowKey the row key.
781 * @param columnKey the column key.
782 *
783 * @return The maximum outlier.
784 *
785 * @see #getItem(int, int)
786 */
787 public Number getMaxOutlier(Comparable rowKey, Comparable columnKey) {
788 Number result = null;
789 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
790 rowKey, columnKey);
791 if (item != null) {
792 result = item.getMaxOutlier();
793 }
794 return result;
795 }
796
797 /**
798 * Returns a list of outlier values for an item.
799 *
800 * @param row the row index (zero-based).
801 * @param column the column index (zero-based).
802 *
803 * @return A list of outlier values.
804 *
805 * @see #getItem(int, int)
806 */
807 public List getOutliers(int row, int column) {
808 List result = null;
809 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
810 row, column);
811 if (item != null) {
812 result = item.getOutliers();
813 }
814 return result;
815 }
816
817 /**
818 * Returns a list of outlier values for an item.
819 *
820 * @param rowKey the row key.
821 * @param columnKey the column key.
822 *
823 * @return A list of outlier values.
824 *
825 * @see #getItem(int, int)
826 */
827 public List getOutliers(Comparable rowKey, Comparable columnKey) {
828 List result = null;
829 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
830 rowKey, columnKey);
831 if (item != null) {
832 result = item.getOutliers();
833 }
834 return result;
835 }
836
837 /**
838 * Resets the cached bounds, by iterating over the entire dataset to find
839 * the current bounds.
840 */
841 private void updateBounds() {
842 this.minimumRangeValue = Double.NaN;
843 this.minimumRangeValueRow = -1;
844 this.minimumRangeValueColumn = -1;
845 this.maximumRangeValue = Double.NaN;
846 this.maximumRangeValueRow = -1;
847 this.maximumRangeValueColumn = -1;
848 int rowCount = getRowCount();
849 int columnCount = getColumnCount();
850 for (int r = 0; r < rowCount; r++) {
851 for (int c = 0; c < columnCount; c++) {
852 BoxAndWhiskerItem item = getItem(r, c);
853 if (item != null) {
854 Number min = item.getMinOutlier();
855 if (min != null) {
856 double minv = min.doubleValue();
857 if (!Double.isNaN(minv)) {
858 if (minv < this.minimumRangeValue || Double.isNaN(
859 this.minimumRangeValue)) {
860 this.minimumRangeValue = minv;
861 this.minimumRangeValueRow = r;
862 this.minimumRangeValueColumn = c;
863 }
864 }
865 }
866 Number max = item.getMaxOutlier();
867 if (max != null) {
868 double maxv = max.doubleValue();
869 if (!Double.isNaN(maxv)) {
870 if (maxv > this.maximumRangeValue || Double.isNaN(
871 this.maximumRangeValue)) {
872 this.maximumRangeValue = maxv;
873 this.maximumRangeValueRow = r;
874 this.maximumRangeValueColumn = c;
875 }
876 }
877 }
878 }
879 }
880 }
881 }
882
883 /**
884 * Tests this dataset for equality with an arbitrary object.
885 *
886 * @param obj the object to test against (<code>null</code> permitted).
887 *
888 * @return A boolean.
889 */
890 public boolean equals(Object obj) {
891 if (obj == this) {
892 return true;
893 }
894 if (obj instanceof DefaultBoxAndWhiskerCategoryDataset) {
895 DefaultBoxAndWhiskerCategoryDataset dataset
896 = (DefaultBoxAndWhiskerCategoryDataset) obj;
897 return ObjectUtilities.equal(this.data, dataset.data);
898 }
899 return false;
900 }
901
902 /**
903 * Returns a clone of this dataset.
904 *
905 * @return A clone.
906 *
907 * @throws CloneNotSupportedException if cloning is not possible.
908 */
909 public Object clone() throws CloneNotSupportedException {
910 DefaultBoxAndWhiskerCategoryDataset clone
911 = (DefaultBoxAndWhiskerCategoryDataset) super.clone();
912 clone.data = (KeyedObjects2D) this.data.clone();
913 return clone;
914 }
915
916 }