    001    /* ===========================================================
    002     * JFreeChart : a free chart library for the Java(tm) platform
    003     * ===========================================================
    004     *
    005     * (C) Copyright 2000-2005, 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-2005, 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     * $Id: DefaultBoxAndWhiskerCategoryDataset.java,v 1.9.2.1 2005/10/25 21:34:46 mungady Exp $
    037     *
    038     * Changes
    039     * -------
    040     * 05-Aug-2003 : Version 1, contributed by David Browning (DG);
    041     * 27-Aug-2003 : Moved from org.jfree.data --> org.jfree.data.statistics (DG);
    042     * 12-Nov-2003 : Changed 'data' from private to protected and added a new 'add'
    043     *               method as proposed by Tim Bardzil.  Also removed old code (DG);
    044     * 01-Mar-2004 : Added equals() method (DG);
    045     * 18-Nov-2004 : Updates for changes in RangeInfo interface (DG);
    046     * 11-Jan-2005 : Removed deprecated code in preparation for the 1.0.0
    047     *               release (DG);
    048     *
    049     */
    050
    051    package org.jfree.data.statistics;
    052
    053    import java.util.List;
    054
    055    import org.jfree.data.KeyedObjects2D;
    056    import org.jfree.data.Range;
    057    import org.jfree.data.RangeInfo;
    058    import org.jfree.data.general.AbstractDataset;
    059    import org.jfree.util.ObjectUtilities;
    060
    061    /**
    062     * A convenience class that provides a default implementation of the
    063     * {@link BoxAndWhiskerCategoryDataset} interface.
    064     *
    065     * @author David Browning (for Australian Institute of Marine Science)
    066     */
    067    public class DefaultBoxAndWhiskerCategoryDataset extends AbstractDataset
    068        implements BoxAndWhiskerCategoryDataset, RangeInfo {
    069
    070        /** Storage for the data. */
    071        protected KeyedObjects2D data;
    072
    073        /** The minimum range value. */
    074        private Number minimumRangeValue;
    075
    076        /** The maximum range value. */
    077        private Number maximumRangeValue;
    078
    079        /** The range of values. */
    080        private Range rangeBounds;
    081
    082        /**
    083         * Creates a new dataset.
    084         */
    085        public DefaultBoxAndWhiskerCategoryDataset() {
    086            this.data = new KeyedObjects2D();
    087            this.minimumRangeValue = null;
    088            this.maximumRangeValue = null;
    089            this.rangeBounds = new Range(0.0, 0.0);
    090        }
    091
    092        /**
    093         * Adds a list of values relating to one box-and-whisker entity to the
    094         * table.  The various median values are calculated.
    095         *
    096         * @param list  a collection of values from which the various medians will
    097         *              be calculated.
    098         * @param rowKey  the row key.
    099         * @param columnKey  the column key.
    100         */
    101        public void add(List list, Comparable rowKey, Comparable columnKey) {
    102            BoxAndWhiskerItem item
    103                = BoxAndWhiskerCalculator.calculateBoxAndWhiskerStatistics(list);
    104            add(item, rowKey, columnKey);
    105        }
    106
    107        /**
    108         * Adds a list of values relating to one Box and Whisker entity to the
    109         * table.  The various median values are calculated.
    110         *
    111         * @param item  a box and whisker item.
    112         * @param rowKey  the row key.
    113         * @param columnKey  the column key.
    114         */
    115        public void add(BoxAndWhiskerItem item,
    116                        Comparable rowKey,
    117                        Comparable columnKey) {
    118
    119            this.data.addObject(item, rowKey, columnKey);
    120            double minval = item.getMinOutlier().doubleValue();
    121            double maxval = item.getMaxOutlier().doubleValue();
    122
    123            if (this.maximumRangeValue == null) {
    124                this.maximumRangeValue = new Double(maxval);
    125            }
    126            else if (maxval > this.maximumRangeValue.doubleValue()) {
    127                this.maximumRangeValue = new Double(maxval);
    128            }
    129
    130            if (this.minimumRangeValue == null) {
    131                this.minimumRangeValue = new Double(minval);
    132            }
    133            else if (minval < this.minimumRangeValue.doubleValue()) {
    134                this.minimumRangeValue = new Double(minval);
    135            }
    136
    137            this.rangeBounds = new Range(
    138                this.minimumRangeValue.doubleValue(),
    139                this.maximumRangeValue.doubleValue()
    140            );
    141
    142            fireDatasetChanged();
    143
    144        }
    145
    146        /**
    147         * Return an item from within the dataset.
    148         *
    149         * @param row  the row index.
    150         * @param column  the column index.
    151         *
    152         * @return The item.
    153         */
    154        public BoxAndWhiskerItem getItem(int row, int column) {
    155            return (BoxAndWhiskerItem) this.data.getObject(row, column);
    156        }
    157
    158        /**
    159         * Returns the value for an item.
    160         *
    161         * @param row  the row index.
    162         * @param column  the column index.
    163         *
    164         * @return The value.
    165         */
    166        public Number getValue(int row, int column) {
    167            return getMedianValue(row, column);
    168        }
    169
    170        /**
    171         * Returns the value for an item.
    172         *
    173         * @param rowKey  the row key.
    174         * @param columnKey  the columnKey.
    175         *
    176         * @return The value.
    177         */
    178        public Number getValue(Comparable rowKey, Comparable columnKey) {
    179            return getMedianValue(rowKey, columnKey);
    180        }
    181
    182        /**
    183         * Returns the mean value for an item.
    184         *
    185         * @param row  the row index (zero-based).
    186         * @param column  the column index (zero-based).
    187         *
    188         * @return The mean value.
    189         */
    190        public Number getMeanValue(int row, int column) {
    191
    192            Number result = null;
    193            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    194                row, column
    195            );
    196            if (item != null) {
    197                result = item.getMean();
    198            }
    199            return result;
    200
    201        }
    202
    203        /**
    204         * Returns the mean value for an item.
    205         *
    206         * @param rowKey  the row key.
    207         * @param columnKey  the column key.
    208         *
    209         * @return The mean value.
    210         */
    211        public Number getMeanValue(Comparable rowKey, Comparable columnKey) {
    212
    213            Number result = null;
    214            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    215                rowKey, columnKey
    216            );
    217            if (item != null) {
    218                result = item.getMean();
    219            }
    220            return result;
    221
    222        }
    223
    224        /**
    225         * Returns the median value for an item.
    226         *
    227         * @param row  the row index (zero-based).
    228         * @param column  the column index (zero-based).
    229         *
    230         * @return The median value.
    231         */
    232        public Number getMedianValue(int row, int column) {
    233            Number result = null;
    234            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    235                row, column
    236            );
    237            if (item != null) {
    238                result = item.getMedian();
    239            }
    240            return result;
    241        }
    242
    243        /**
    244         * Returns the median value for an item.
    245         *
    246         * @param rowKey  the row key.
    247         * @param columnKey  the columnKey.
    248         *
    249         * @return The median value.
    250         */
    251        public Number getMedianValue(Comparable rowKey, Comparable columnKey) {
    252            Number result = null;
    253            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    254                rowKey, columnKey
    255            );
    256            if (item != null) {
    257                result = item.getMedian();
    258            }
    259            return result;
    260        }
    261
    262        /**
    263         * Returns the first quartile value.
    264         *
    265         * @param row  the row index (zero-based).
    266         * @param column  the column index (zero-based).
    267         *
    268         * @return The first quartile value.
    269         */
    270        public Number getQ1Value(int row, int column) {
    271            Number result = null;
    272            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    273                row, column
    274            );
    275            if (item != null) {
    276                result = item.getQ1();
    277            }
    278            return result;
    279        }
    280
    281        /**
    282         * Returns the first quartile value.
    283         *
    284         * @param rowKey  the row key.
    285         * @param columnKey  the column key.
    286         *
    287         * @return The first quartile value.
    288         */
    289        public Number getQ1Value(Comparable rowKey, Comparable columnKey) {
    290            Number result = null;
    291            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    292                rowKey, columnKey
    293            );
    294            if (item != null) {
    295                result = item.getQ1();
    296            }
    297            return result;
    298        }
    299
    300        /**
    301         * Returns the third quartile value.
    302         *
    303         * @param row  the row index (zero-based).
    304         * @param column  the column index (zero-based).
    305         *
    306         * @return The third quartile value.
    307         */
    308        public Number getQ3Value(int row, int column) {
    309            Number result = null;
    310            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    311                row, column
    312            );
    313            if (item != null) {
    314                result = item.getQ3();
    315            }
    316            return result;
    317        }
    318
    319        /**
    320         * Returns the third quartile value.
    321         *
    322         * @param rowKey  the row key.
    323         * @param columnKey  the column key.
    324         *
    325         * @return The third quartile value.
    326         */
    327        public Number getQ3Value(Comparable rowKey, Comparable columnKey) {
    328            Number result = null;
    329            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    330                rowKey, columnKey
    331            );
    332            if (item != null) {
    333                result = item.getQ3();
    334            }
    335            return result;
    336        }
    337
    338        /**
    339         * Returns the column index for a given key.
    340         *
    341         * @param key  the column key.
    342         *
    343         * @return The column index.
    344         */
    345        public int getColumnIndex(Comparable key) {
    346            return this.data.getColumnIndex(key);
    347        }
    348
    349        /**
    350         * Returns a column key.
    351         *
    352         * @param column  the column index (zero-based).
    353         *
    354         * @return The column key.
    355         */
    356        public Comparable getColumnKey(int column) {
    357            return this.data.getColumnKey(column);
    358        }
    359
    360        /**
    361         * Returns the column keys.
    362         *
    363         * @return The keys.
    364         */
    365        public List getColumnKeys() {
    366            return this.data.getColumnKeys();
    367        }
    368
    369        /**
    370         * Returns the row index for a given key.
    371         *
    372         * @param key  the row key.
    373         *
    374         * @return The row index.
    375         */
    376        public int getRowIndex(Comparable key) {
    377            return this.data.getRowIndex(key);
    378        }
    379
    380        /**
    381         * Returns a row key.
    382         *
    383         * @param row  the row index (zero-based).
    384         *
    385         * @return The row key.
    386         */
    387        public Comparable getRowKey(int row) {
    388            return this.data.getRowKey(row);
    389        }
    390
    391        /**
    392         * Returns the row keys.
    393         *
    394         * @return The keys.
    395         */
    396        public List getRowKeys() {
    397            return this.data.getRowKeys();
    398        }
    399
    400        /**
    401         * Returns the number of rows in the table.
    402         *
    403         * @return The row count.
    404         */
    405        public int getRowCount() {
    406            return this.data.getRowCount();
    407        }
    408
    409        /**
    410         * Returns the number of columns in the table.
    411         *
    412         * @return The column count.
    413         */
    414        public int getColumnCount() {
    415            return this.data.getColumnCount();
    416        }
    417
    418        /**
    419         * Returns the minimum y-value in the dataset.
    420         *
    421         * @param includeInterval  a flag that determines whether or not the
    422         *                         y-interval is taken into account.
    423         *
    424         * @return The minimum value.
    425         */
    426        public double getRangeLowerBound(boolean includeInterval) {
    427            double result = Double.NaN;
    428            if (this.minimumRangeValue != null) {
    429                result = this.minimumRangeValue.doubleValue();
    430            }
    431            return result;
    432        }
    433
    434        /**
    435         * Returns the maximum y-value in the dataset.
    436         *
    437         * @param includeInterval  a flag that determines whether or not the
    438         *                         y-interval is taken into account.
    439         *
    440         * @return The maximum value.
    441         */
    442        public double getRangeUpperBound(boolean includeInterval) {
    443            double result = Double.NaN;
    444            if (this.maximumRangeValue != null) {
    445                result = this.maximumRangeValue.doubleValue();
    446            }
    447            return result;
    448        }
    449
    450        /**
    451         * Returns the range of the values in this dataset's range.
    452         *
    453         * @param includeInterval  a flag that determines whether or not the
    454         *                         y-interval is taken into account.
    455         *
    456         * @return The range.
    457         */
    458        public Range getRangeBounds(boolean includeInterval) {
    459            return this.rangeBounds;
    460        }
    461
    462        /**
    463         * Returns the minimum regular (non outlier) value for an item.
    464         *
    465         * @param row  the row index (zero-based).
    466         * @param column  the column index (zero-based).
    467         *
    468         * @return The minimum regular value.
    469         */
    470        public Number getMinRegularValue(int row, int column) {
    471
    472            Number result = null;
    473            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    474                row, column
    475            );
    476            if (item != null) {
    477                result = item.getMinRegularValue();
    478            }
    479            return result;
    480
    481        }
    482
    483        /**
    484         * Returns the minimum regular (non outlier) value for an item.
    485         *
    486         * @param rowKey  the row key.
    487         * @param columnKey  the column key.
    488         *
    489         * @return The minimum regular value.
    490         */
    491        public Number getMinRegularValue(Comparable rowKey, Comparable columnKey) {
    492
    493            Number result = null;
    494            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    495                rowKey, columnKey
    496            );
    497            if (item != null) {
    498                result = item.getMinRegularValue();
    499            }
    500            return result;
    501
    502        }
    503
    504        /**
    505         * Returns the maximum regular (non outlier) value for an item.
    506         *
    507         * @param row  the row index (zero-based).
    508         * @param column  the column index (zero-based).
    509         *
    510         * @return The maximum regular value.
    511         */
    512        public Number getMaxRegularValue(int row, int column) {
    513
    514            Number result = null;
    515            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    516                row, column
    517            );
    518            if (item != null) {
    519                result = item.getMaxRegularValue();
    520            }
    521            return result;
    522
    523        }
    524
    525        /**
    526         * Returns the maximum regular (non outlier) value for an item.
    527         *
    528         * @param rowKey  the row key.
    529         * @param columnKey  the column key.
    530         *
    531         * @return The maximum regular value.
    532         */
    533        public Number getMaxRegularValue(Comparable rowKey, Comparable columnKey) {
    534
    535            Number result = null;
    536            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    537                rowKey, columnKey
    538            );
    539            if (item != null) {
    540                result = item.getMaxRegularValue();
    541            }
    542            return result;
    543
    544        }
    545
    546        /**
    547         * Returns the minimum outlier (non farout) value for an item.
    548         *
    549         * @param row  the row index (zero-based).
    550         * @param column  the column index (zero-based).
    551         *
    552         * @return The minimum outlier.
    553         */
    554        public Number getMinOutlier(int row, int column) {
    555
    556            Number result = null;
    557            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    558                row, column
    559            );
    560            if (item != null) {
    561                result = item.getMinOutlier();
    562            }
    563            return result;
    564
    565        }
    566
    567        /**
    568         * Returns the minimum outlier (non farout) value for an item.
    569         *
    570         * @param rowKey  the row key.
    571         * @param columnKey  the column key.
    572         *
    573         * @return The minimum outlier.
    574         */
    575        public Number getMinOutlier(Comparable rowKey, Comparable columnKey) {
    576
    577            Number result = null;
    578            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    579                rowKey, columnKey
    580            );
    581            if (item != null) {
    582                result = item.getMinOutlier();
    583            }
    584            return result;
    585
    586        }
    587
    588        /**
    589         * Returns the maximum outlier (non farout) value for an item.
    590         *
    591         * @param row  the row index (zero-based).
    592         * @param column  the column index (zero-based).
    593         *
    594         * @return The maximum outlier.
    595         */
    596        public Number getMaxOutlier(int row, int column) {
    597
    598            Number result = null;
    599            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    600                row, column
    601            );
    602            if (item != null) {
    603                result = item.getMaxOutlier();
    604            }
    605            return result;
    606
    607        }
    608
    609        /**
    610         * Returns the maximum outlier (non farout) value for an item.
    611         *
    612         * @param rowKey  the row key.
    613         * @param columnKey  the column key.
    614         *
    615         * @return The maximum outlier.
    616         */
    617        public Number getMaxOutlier(Comparable rowKey, Comparable columnKey) {
    618
    619            Number result = null;
    620            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    621                rowKey, columnKey
    622            );
    623            if (item != null) {
    624                result = item.getMaxOutlier();
    625            }
    626            return result;
    627
    628        }
    629
    630        /**
    631         * Returns a list of outlier values for an item.
    632         *
    633         * @param row  the row index (zero-based).
    634         * @param column  the column index (zero-based).
    635         *
    636         * @return A list of outlier values.
    637         */
    638        public List getOutliers(int row, int column) {
    639
    640            List result = null;
    641            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    642                row, column
    643            );
    644            if (item != null) {
    645                result = item.getOutliers();
    646            }
    647            return result;
    648
    649        }
    650
    651        /**
    652         * Returns a list of outlier values for an item.
    653         *
    654         * @param rowKey  the row key.
    655         * @param columnKey  the column key.
    656         *
    657         * @return A list of outlier values.
    658         */
    659        public List getOutliers(Comparable rowKey, Comparable columnKey) {
    660
    661            List result = null;
    662            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
    663                rowKey, columnKey
    664            );
    665            if (item != null) {
    666                result = item.getOutliers();
    667            }
    668            return result;
    669
    670        }
    671
    672        /**
    673         * Tests this dataset for equality with an arbitrary object.
    674         *
    675         * @param obj  the object to test against (<code>null</code> permitted).
    676         *
    677         * @return A boolean.
    678         */
    679        public boolean equals(Object obj) {
    680
    681            if (obj == null) {
    682                return false;
    683            }
    684
    685            if (obj == this) {
    686                return true;
    687            }
    688
    689            if (obj instanceof DefaultBoxAndWhiskerCategoryDataset) {
    690                DefaultBoxAndWhiskerCategoryDataset dataset
    691                    = (DefaultBoxAndWhiskerCategoryDataset) obj;
    692                return ObjectUtilities.equal(this.data, dataset.data);
    693            }
    694
    695            return false;
    696        }
    697
    698    }