001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2013, 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 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 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 057package org.jfree.data.statistics; 058 059import java.util.List; 060 061import org.jfree.data.KeyedObjects2D; 062import org.jfree.data.Range; 063import org.jfree.data.RangeInfo; 064import org.jfree.data.general.AbstractDataset; 065import org.jfree.data.general.DatasetChangeEvent; 066import org.jfree.util.ObjectUtilities; 067import org.jfree.util.PublicCloneable; 068 069/** 070 * A convenience class that provides a default implementation of the 071 * {@link BoxAndWhiskerCategoryDataset} interface. 072 */ 073public 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 @Override 320 public Number getValue(int row, int column) { 321 return getMedianValue(row, column); 322 } 323 324 /** 325 * Returns the value for an item. 326 * 327 * @param rowKey the row key. 328 * @param columnKey the columnKey. 329 * 330 * @return The value. 331 * 332 * @see #getMedianValue(Comparable, Comparable) 333 * @see #getValue(int, int) 334 */ 335 @Override 336 public Number getValue(Comparable rowKey, Comparable columnKey) { 337 return getMedianValue(rowKey, columnKey); 338 } 339 340 /** 341 * Returns the mean value for an item. 342 * 343 * @param row the row index (zero-based). 344 * @param column the column index (zero-based). 345 * 346 * @return The mean value. 347 * 348 * @see #getItem(int, int) 349 */ 350 @Override 351 public Number getMeanValue(int row, int column) { 352 353 Number result = null; 354 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(row, 355 column); 356 if (item != null) { 357 result = item.getMean(); 358 } 359 return result; 360 361 } 362 363 /** 364 * Returns the mean value for an item. 365 * 366 * @param rowKey the row key. 367 * @param columnKey the column key. 368 * 369 * @return The mean value. 370 * 371 * @see #getItem(int, int) 372 */ 373 @Override 374 public Number getMeanValue(Comparable rowKey, Comparable columnKey) { 375 Number result = null; 376 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 377 rowKey, columnKey); 378 if (item != null) { 379 result = item.getMean(); 380 } 381 return result; 382 } 383 384 /** 385 * Returns the median value for an item. 386 * 387 * @param row the row index (zero-based). 388 * @param column the column index (zero-based). 389 * 390 * @return The median value. 391 * 392 * @see #getItem(int, int) 393 */ 394 @Override 395 public Number getMedianValue(int row, int column) { 396 Number result = null; 397 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(row, 398 column); 399 if (item != null) { 400 result = item.getMedian(); 401 } 402 return result; 403 } 404 405 /** 406 * Returns the median value for an item. 407 * 408 * @param rowKey the row key. 409 * @param columnKey the columnKey. 410 * 411 * @return The median value. 412 * 413 * @see #getItem(int, int) 414 */ 415 @Override 416 public Number getMedianValue(Comparable rowKey, Comparable columnKey) { 417 Number result = null; 418 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 419 rowKey, columnKey); 420 if (item != null) { 421 result = item.getMedian(); 422 } 423 return result; 424 } 425 426 /** 427 * Returns the first quartile value. 428 * 429 * @param row the row index (zero-based). 430 * @param column the column index (zero-based). 431 * 432 * @return The first quartile value. 433 * 434 * @see #getItem(int, int) 435 */ 436 @Override 437 public Number getQ1Value(int row, int column) { 438 Number result = null; 439 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 440 row, column); 441 if (item != null) { 442 result = item.getQ1(); 443 } 444 return result; 445 } 446 447 /** 448 * Returns the first quartile value. 449 * 450 * @param rowKey the row key. 451 * @param columnKey the column key. 452 * 453 * @return The first quartile value. 454 * 455 * @see #getItem(int, int) 456 */ 457 @Override 458 public Number getQ1Value(Comparable rowKey, Comparable columnKey) { 459 Number result = null; 460 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 461 rowKey, columnKey); 462 if (item != null) { 463 result = item.getQ1(); 464 } 465 return result; 466 } 467 468 /** 469 * Returns the third quartile value. 470 * 471 * @param row the row index (zero-based). 472 * @param column the column index (zero-based). 473 * 474 * @return The third quartile value. 475 * 476 * @see #getItem(int, int) 477 */ 478 @Override 479 public Number getQ3Value(int row, int column) { 480 Number result = null; 481 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 482 row, column); 483 if (item != null) { 484 result = item.getQ3(); 485 } 486 return result; 487 } 488 489 /** 490 * Returns the third quartile value. 491 * 492 * @param rowKey the row key. 493 * @param columnKey the column key. 494 * 495 * @return The third quartile value. 496 * 497 * @see #getItem(int, int) 498 */ 499 @Override 500 public Number getQ3Value(Comparable rowKey, Comparable columnKey) { 501 Number result = null; 502 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 503 rowKey, columnKey); 504 if (item != null) { 505 result = item.getQ3(); 506 } 507 return result; 508 } 509 510 /** 511 * Returns the column index for a given key. 512 * 513 * @param key the column key (<code>null</code> not permitted). 514 * 515 * @return The column index. 516 * 517 * @see #getColumnKey(int) 518 */ 519 @Override 520 public int getColumnIndex(Comparable key) { 521 return this.data.getColumnIndex(key); 522 } 523 524 /** 525 * Returns a column key. 526 * 527 * @param column the column index (zero-based). 528 * 529 * @return The column key. 530 * 531 * @see #getColumnIndex(Comparable) 532 */ 533 @Override 534 public Comparable getColumnKey(int column) { 535 return this.data.getColumnKey(column); 536 } 537 538 /** 539 * Returns the column keys. 540 * 541 * @return The keys. 542 * 543 * @see #getRowKeys() 544 */ 545 @Override 546 public List getColumnKeys() { 547 return this.data.getColumnKeys(); 548 } 549 550 /** 551 * Returns the row index for a given key. 552 * 553 * @param key the row key (<code>null</code> not permitted). 554 * 555 * @return The row index. 556 * 557 * @see #getRowKey(int) 558 */ 559 @Override 560 public int getRowIndex(Comparable key) { 561 // defer null argument check 562 return this.data.getRowIndex(key); 563 } 564 565 /** 566 * Returns a row key. 567 * 568 * @param row the row index (zero-based). 569 * 570 * @return The row key. 571 * 572 * @see #getRowIndex(Comparable) 573 */ 574 @Override 575 public Comparable getRowKey(int row) { 576 return this.data.getRowKey(row); 577 } 578 579 /** 580 * Returns the row keys. 581 * 582 * @return The keys. 583 * 584 * @see #getColumnKeys() 585 */ 586 @Override 587 public List getRowKeys() { 588 return this.data.getRowKeys(); 589 } 590 591 /** 592 * Returns the number of rows in the table. 593 * 594 * @return The row count. 595 * 596 * @see #getColumnCount() 597 */ 598 @Override 599 public int getRowCount() { 600 return this.data.getRowCount(); 601 } 602 603 /** 604 * Returns the number of columns in the table. 605 * 606 * @return The column count. 607 * 608 * @see #getRowCount() 609 */ 610 @Override 611 public int getColumnCount() { 612 return this.data.getColumnCount(); 613 } 614 615 /** 616 * Returns the minimum y-value in the dataset. 617 * 618 * @param includeInterval a flag that determines whether or not the 619 * y-interval is taken into account. 620 * 621 * @return The minimum value. 622 * 623 * @see #getRangeUpperBound(boolean) 624 */ 625 @Override 626 public double getRangeLowerBound(boolean includeInterval) { 627 return this.minimumRangeValue; 628 } 629 630 /** 631 * Returns the maximum y-value in the dataset. 632 * 633 * @param includeInterval a flag that determines whether or not the 634 * y-interval is taken into account. 635 * 636 * @return The maximum value. 637 * 638 * @see #getRangeLowerBound(boolean) 639 */ 640 @Override 641 public double getRangeUpperBound(boolean includeInterval) { 642 return this.maximumRangeValue; 643 } 644 645 /** 646 * Returns the range of the values in this dataset's range. 647 * 648 * @param includeInterval a flag that determines whether or not the 649 * y-interval is taken into account. 650 * 651 * @return The range. 652 */ 653 @Override 654 public Range getRangeBounds(boolean includeInterval) { 655 return new Range(this.minimumRangeValue, this.maximumRangeValue); 656 } 657 658 /** 659 * Returns the minimum regular (non outlier) value for an item. 660 * 661 * @param row the row index (zero-based). 662 * @param column the column index (zero-based). 663 * 664 * @return The minimum regular value. 665 * 666 * @see #getItem(int, int) 667 */ 668 @Override 669 public Number getMinRegularValue(int row, int column) { 670 Number result = null; 671 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 672 row, column); 673 if (item != null) { 674 result = item.getMinRegularValue(); 675 } 676 return result; 677 } 678 679 /** 680 * Returns the minimum regular (non outlier) value for an item. 681 * 682 * @param rowKey the row key. 683 * @param columnKey the column key. 684 * 685 * @return The minimum regular value. 686 * 687 * @see #getItem(int, int) 688 */ 689 @Override 690 public Number getMinRegularValue(Comparable rowKey, Comparable columnKey) { 691 Number result = null; 692 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 693 rowKey, columnKey); 694 if (item != null) { 695 result = item.getMinRegularValue(); 696 } 697 return result; 698 } 699 700 /** 701 * Returns the maximum regular (non outlier) value for an item. 702 * 703 * @param row the row index (zero-based). 704 * @param column the column index (zero-based). 705 * 706 * @return The maximum regular value. 707 * 708 * @see #getItem(int, int) 709 */ 710 @Override 711 public Number getMaxRegularValue(int row, int column) { 712 Number result = null; 713 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 714 row, column); 715 if (item != null) { 716 result = item.getMaxRegularValue(); 717 } 718 return result; 719 } 720 721 /** 722 * Returns the maximum regular (non outlier) value for an item. 723 * 724 * @param rowKey the row key. 725 * @param columnKey the column key. 726 * 727 * @return The maximum regular value. 728 * 729 * @see #getItem(int, int) 730 */ 731 @Override 732 public Number getMaxRegularValue(Comparable rowKey, Comparable columnKey) { 733 Number result = null; 734 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 735 rowKey, columnKey); 736 if (item != null) { 737 result = item.getMaxRegularValue(); 738 } 739 return result; 740 } 741 742 /** 743 * Returns the minimum outlier (non farout) value for an item. 744 * 745 * @param row the row index (zero-based). 746 * @param column the column index (zero-based). 747 * 748 * @return The minimum outlier. 749 * 750 * @see #getItem(int, int) 751 */ 752 @Override 753 public Number getMinOutlier(int row, int column) { 754 Number result = null; 755 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 756 row, column); 757 if (item != null) { 758 result = item.getMinOutlier(); 759 } 760 return result; 761 } 762 763 /** 764 * Returns the minimum outlier (non farout) value for an item. 765 * 766 * @param rowKey the row key. 767 * @param columnKey the column key. 768 * 769 * @return The minimum outlier. 770 * 771 * @see #getItem(int, int) 772 */ 773 @Override 774 public Number getMinOutlier(Comparable rowKey, Comparable columnKey) { 775 Number result = null; 776 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 777 rowKey, columnKey); 778 if (item != null) { 779 result = item.getMinOutlier(); 780 } 781 return result; 782 } 783 784 /** 785 * Returns the maximum outlier (non farout) value for an item. 786 * 787 * @param row the row index (zero-based). 788 * @param column the column index (zero-based). 789 * 790 * @return The maximum outlier. 791 * 792 * @see #getItem(int, int) 793 */ 794 @Override 795 public Number getMaxOutlier(int row, int column) { 796 Number result = null; 797 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 798 row, column); 799 if (item != null) { 800 result = item.getMaxOutlier(); 801 } 802 return result; 803 } 804 805 /** 806 * Returns the maximum outlier (non farout) value for an item. 807 * 808 * @param rowKey the row key. 809 * @param columnKey the column key. 810 * 811 * @return The maximum outlier. 812 * 813 * @see #getItem(int, int) 814 */ 815 @Override 816 public Number getMaxOutlier(Comparable rowKey, Comparable columnKey) { 817 Number result = null; 818 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 819 rowKey, columnKey); 820 if (item != null) { 821 result = item.getMaxOutlier(); 822 } 823 return result; 824 } 825 826 /** 827 * Returns a list of outlier values for an item. 828 * 829 * @param row the row index (zero-based). 830 * @param column the column index (zero-based). 831 * 832 * @return A list of outlier values. 833 * 834 * @see #getItem(int, int) 835 */ 836 @Override 837 public List getOutliers(int row, int column) { 838 List result = null; 839 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 840 row, column); 841 if (item != null) { 842 result = item.getOutliers(); 843 } 844 return result; 845 } 846 847 /** 848 * Returns a list of outlier values for an item. 849 * 850 * @param rowKey the row key. 851 * @param columnKey the column key. 852 * 853 * @return A list of outlier values. 854 * 855 * @see #getItem(int, int) 856 */ 857 @Override 858 public List getOutliers(Comparable rowKey, Comparable columnKey) { 859 List result = null; 860 BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject( 861 rowKey, columnKey); 862 if (item != null) { 863 result = item.getOutliers(); 864 } 865 return result; 866 } 867 868 /** 869 * Resets the cached bounds, by iterating over the entire dataset to find 870 * the current bounds. 871 */ 872 private void updateBounds() { 873 this.minimumRangeValue = Double.NaN; 874 this.minimumRangeValueRow = -1; 875 this.minimumRangeValueColumn = -1; 876 this.maximumRangeValue = Double.NaN; 877 this.maximumRangeValueRow = -1; 878 this.maximumRangeValueColumn = -1; 879 int rowCount = getRowCount(); 880 int columnCount = getColumnCount(); 881 for (int r = 0; r < rowCount; r++) { 882 for (int c = 0; c < columnCount; c++) { 883 BoxAndWhiskerItem item = getItem(r, c); 884 if (item != null) { 885 Number min = item.getMinOutlier(); 886 if (min != null) { 887 double minv = min.doubleValue(); 888 if (!Double.isNaN(minv)) { 889 if (minv < this.minimumRangeValue || Double.isNaN( 890 this.minimumRangeValue)) { 891 this.minimumRangeValue = minv; 892 this.minimumRangeValueRow = r; 893 this.minimumRangeValueColumn = c; 894 } 895 } 896 } 897 Number max = item.getMaxOutlier(); 898 if (max != null) { 899 double maxv = max.doubleValue(); 900 if (!Double.isNaN(maxv)) { 901 if (maxv > this.maximumRangeValue || Double.isNaN( 902 this.maximumRangeValue)) { 903 this.maximumRangeValue = maxv; 904 this.maximumRangeValueRow = r; 905 this.maximumRangeValueColumn = c; 906 } 907 } 908 } 909 } 910 } 911 } 912 } 913 914 /** 915 * Tests this dataset for equality with an arbitrary object. 916 * 917 * @param obj the object to test against (<code>null</code> permitted). 918 * 919 * @return A boolean. 920 */ 921 @Override 922 public boolean equals(Object obj) { 923 if (obj == this) { 924 return true; 925 } 926 if (obj instanceof DefaultBoxAndWhiskerCategoryDataset) { 927 DefaultBoxAndWhiskerCategoryDataset dataset 928 = (DefaultBoxAndWhiskerCategoryDataset) obj; 929 return ObjectUtilities.equal(this.data, dataset.data); 930 } 931 return false; 932 } 933 934 /** 935 * Returns a clone of this dataset. 936 * 937 * @return A clone. 938 * 939 * @throws CloneNotSupportedException if cloning is not possible. 940 */ 941 @Override 942 public Object clone() throws CloneNotSupportedException { 943 DefaultBoxAndWhiskerCategoryDataset clone 944 = (DefaultBoxAndWhiskerCategoryDataset) super.clone(); 945 clone.data = (KeyedObjects2D) this.data.clone(); 946 return clone; 947 } 948 949}