001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2008, 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-2008, 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 }