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     * $Id: DefaultBoxAndWhiskerCategoryDataset.java,v 1.9.2.3 2007/02/02 15:50:24 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     * ------------- JFREECHART 1.0.x ---------------------------------------------
049     * 02-Feb-2007 : Removed author tags from all over JFreeChart sources (DG);
050     *
051     */
052    
053    package org.jfree.data.statistics;
054    
055    import java.util.List;
056    
057    import org.jfree.data.KeyedObjects2D;
058    import org.jfree.data.Range;
059    import org.jfree.data.RangeInfo;
060    import org.jfree.data.general.AbstractDataset;
061    import org.jfree.util.ObjectUtilities;
062    
063    /**
064     * A convenience class that provides a default implementation of the
065     * {@link BoxAndWhiskerCategoryDataset} interface.
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 (<code>null</code> not permitted).
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(this.minimumRangeValue.doubleValue(),
138                  this.maximumRangeValue.doubleValue());
139    
140            fireDatasetChanged();
141    
142        }
143    
144        /**
145         * Return an item from within the dataset.
146         * 
147         * @param row  the row index.
148         * @param column  the column index.
149         * 
150         * @return The item.
151         */
152        public BoxAndWhiskerItem getItem(int row, int column) {
153            return (BoxAndWhiskerItem) this.data.getObject(row, column);  
154        }
155    
156        /**
157         * Returns the value for an item.
158         *
159         * @param row  the row index.
160         * @param column  the column index.
161         *
162         * @return The value.
163         */
164        public Number getValue(int row, int column) {
165            return getMedianValue(row, column);
166        }
167    
168        /**
169         * Returns the value for an item.
170         *
171         * @param rowKey  the row key.
172         * @param columnKey  the columnKey.
173         *
174         * @return The value.
175         */
176        public Number getValue(Comparable rowKey, Comparable columnKey) {
177            return getMedianValue(rowKey, columnKey);
178        }
179    
180        /**
181         * Returns the mean value for an item.
182         * 
183         * @param row  the row index (zero-based).
184         * @param column  the column index (zero-based).
185         * 
186         * @return The mean value.
187         */
188        public Number getMeanValue(int row, int column) {
189    
190            Number result = null;
191            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(row, 
192                    column);
193            if (item != null) {
194                result = item.getMean();
195            }
196            return result;
197    
198        }
199    
200        /**
201         * Returns the mean value for an item.
202         * 
203         * @param rowKey  the row key.
204         * @param columnKey  the column key.
205         * 
206         * @return The mean value.
207         */
208        public Number getMeanValue(Comparable rowKey, Comparable columnKey) {
209            Number result = null;
210            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
211                    rowKey, columnKey);
212            if (item != null) {
213                result = item.getMean();
214            }
215            return result;
216        }
217    
218        /**
219         * Returns the median value for an item.
220         *
221         * @param row  the row index (zero-based).
222         * @param column  the column index (zero-based).
223         *
224         * @return The median value.
225         */
226        public Number getMedianValue(int row, int column) {
227            Number result = null;
228            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(row, 
229                    column);
230            if (item != null) {
231                result = item.getMedian();
232            }
233            return result;
234        }
235    
236        /**
237         * Returns the median value for an item.
238         *
239         * @param rowKey  the row key.
240         * @param columnKey  the columnKey.
241         *
242         * @return The median value.
243         */
244        public Number getMedianValue(Comparable rowKey, Comparable columnKey) {
245            Number result = null;
246            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
247                    rowKey, columnKey);
248            if (item != null) {
249                result = item.getMedian();
250            }
251            return result;
252        }
253    
254        /**
255         * Returns the first quartile value.
256         * 
257         * @param row  the row index (zero-based).
258         * @param column  the column index (zero-based).
259         * 
260         * @return The first quartile value.
261         */
262        public Number getQ1Value(int row, int column) {
263            Number result = null;
264            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
265                    row, column);
266            if (item != null) {
267                result = item.getQ1();
268            }
269            return result;
270        }
271    
272        /**
273         * Returns the first quartile value.
274         * 
275         * @param rowKey  the row key.
276         * @param columnKey  the column key.
277         * 
278         * @return The first quartile value.
279         */
280        public Number getQ1Value(Comparable rowKey, Comparable columnKey) {
281            Number result = null;
282            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
283                    rowKey, columnKey);
284            if (item != null) {
285                result = item.getQ1();
286            }
287            return result;
288        }
289    
290        /**
291         * Returns the third quartile value.
292         * 
293         * @param row  the row index (zero-based).
294         * @param column  the column index (zero-based).
295         * 
296         * @return The third quartile value.
297         */
298        public Number getQ3Value(int row, int column) {
299            Number result = null;
300            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
301                    row, column);
302            if (item != null) {
303                result = item.getQ3();
304            }
305            return result;
306        }
307    
308        /**
309         * Returns the third quartile value.
310         * 
311         * @param rowKey  the row key.
312         * @param columnKey  the column key.
313         * 
314         * @return The third quartile value.
315         */
316        public Number getQ3Value(Comparable rowKey, Comparable columnKey) {
317            Number result = null;
318            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
319                    rowKey, columnKey);
320            if (item != null) {
321                result = item.getQ3();
322            }
323            return result;
324        }
325    
326        /**
327         * Returns the column index for a given key.
328         *
329         * @param key  the column key.
330         *
331         * @return The column index.
332         */
333        public int getColumnIndex(Comparable key) {
334            return this.data.getColumnIndex(key);
335        }
336    
337        /**
338         * Returns a column key.
339         *
340         * @param column  the column index (zero-based).
341         *
342         * @return The column key.
343         */
344        public Comparable getColumnKey(int column) {
345            return this.data.getColumnKey(column);
346        }
347    
348        /**
349         * Returns the column keys.
350         *
351         * @return The keys.
352         */
353        public List getColumnKeys() {
354            return this.data.getColumnKeys();
355        }
356    
357        /**
358         * Returns the row index for a given key.
359         *
360         * @param key  the row key.
361         *
362         * @return The row index.
363         */
364        public int getRowIndex(Comparable key) {
365            return this.data.getRowIndex(key);
366        }
367    
368        /**
369         * Returns a row key.
370         *
371         * @param row  the row index (zero-based).
372         *
373         * @return The row key.
374         */
375        public Comparable getRowKey(int row) {
376            return this.data.getRowKey(row);
377        }
378    
379        /**
380         * Returns the row keys.
381         *
382         * @return The keys.
383         */
384        public List getRowKeys() {
385            return this.data.getRowKeys();
386        }
387    
388        /**
389         * Returns the number of rows in the table.
390         *
391         * @return The row count.
392         */
393        public int getRowCount() {
394            return this.data.getRowCount();
395        }
396    
397        /**
398         * Returns the number of columns in the table.
399         *
400         * @return The column count.
401         */
402        public int getColumnCount() {
403            return this.data.getColumnCount();
404        }
405    
406        /**
407         * Returns the minimum y-value in the dataset.
408         *
409         * @param includeInterval  a flag that determines whether or not the
410         *                         y-interval is taken into account.
411         * 
412         * @return The minimum value.
413         */
414        public double getRangeLowerBound(boolean includeInterval) {
415            double result = Double.NaN;
416            if (this.minimumRangeValue != null) {
417                result = this.minimumRangeValue.doubleValue();
418            }
419            return result;
420        }
421    
422        /**
423         * Returns the maximum y-value in the dataset.
424         *
425         * @param includeInterval  a flag that determines whether or not the
426         *                         y-interval is taken into account.
427         * 
428         * @return The maximum value.
429         */
430        public double getRangeUpperBound(boolean includeInterval) {
431            double result = Double.NaN;
432            if (this.maximumRangeValue != null) {
433                result = this.maximumRangeValue.doubleValue();
434            }
435            return result;
436        }
437    
438        /**
439         * Returns the range of the values in this dataset's range.
440         *
441         * @param includeInterval  a flag that determines whether or not the
442         *                         y-interval is taken into account.
443         * 
444         * @return The range.
445         */
446        public Range getRangeBounds(boolean includeInterval) {
447            return this.rangeBounds;
448        }
449        
450        /**
451         * Returns the minimum regular (non outlier) value for an item.
452         * 
453         * @param row  the row index (zero-based).
454         * @param column  the column index (zero-based).
455         * 
456         * @return The minimum regular value.
457         */
458        public Number getMinRegularValue(int row, int column) {
459            Number result = null;
460            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
461                    row, column);
462            if (item != null) {
463                result = item.getMinRegularValue();
464            }
465            return result;
466        }
467    
468        /**
469         * Returns the minimum regular (non outlier) value for an item.
470         * 
471         * @param rowKey  the row key.
472         * @param columnKey  the column key.
473         * 
474         * @return The minimum regular value.
475         */
476        public Number getMinRegularValue(Comparable rowKey, Comparable columnKey) {
477            Number result = null;
478            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
479                    rowKey, columnKey);
480            if (item != null) {
481                result = item.getMinRegularValue();
482            }
483            return result;
484        }
485    
486        /**
487         * Returns the maximum regular (non outlier) value for an item.
488         * 
489         * @param row  the row index (zero-based).
490         * @param column  the column index (zero-based).
491         * 
492         * @return The maximum regular value.
493         */
494        public Number getMaxRegularValue(int row, int column) {
495            Number result = null;
496            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
497                    row, column);
498            if (item != null) {
499                result = item.getMaxRegularValue();
500            }
501            return result;
502        }
503    
504        /**
505         * Returns the maximum regular (non outlier) value for an item.
506         * 
507         * @param rowKey  the row key.
508         * @param columnKey  the column key.
509         * 
510         * @return The maximum regular value.
511         */
512        public Number getMaxRegularValue(Comparable rowKey, Comparable columnKey) {
513            Number result = null;
514            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
515                    rowKey, columnKey);
516            if (item != null) {
517                result = item.getMaxRegularValue();
518            }
519            return result;
520        }
521    
522        /**
523         * Returns the minimum outlier (non farout) value for an item.
524         * 
525         * @param row  the row index (zero-based).
526         * @param column  the column index (zero-based).
527         * 
528         * @return The minimum outlier.
529         */
530        public Number getMinOutlier(int row, int column) {
531            Number result = null;
532            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
533                    row, column);
534            if (item != null) {
535                result = item.getMinOutlier();
536            }
537            return result;
538        }
539    
540        /**
541         * Returns the minimum outlier (non farout) value for an item.
542         * 
543         * @param rowKey  the row key.
544         * @param columnKey  the column key.
545         * 
546         * @return The minimum outlier.
547         */
548        public Number getMinOutlier(Comparable rowKey, Comparable columnKey) {
549            Number result = null;
550            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
551                    rowKey, columnKey);
552            if (item != null) {
553                result = item.getMinOutlier();
554            }
555            return result;
556        }
557    
558        /**
559         * Returns the maximum outlier (non farout) value for an item.
560         * 
561         * @param row  the row index (zero-based).
562         * @param column  the column index (zero-based).
563         * 
564         * @return The maximum outlier.
565         */
566        public Number getMaxOutlier(int row, int column) {
567            Number result = null;
568            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
569                    row, column);
570            if (item != null) {
571                result = item.getMaxOutlier();
572            }
573            return result;
574        }
575    
576        /**
577         * Returns the maximum outlier (non farout) value for an item.
578         * 
579         * @param rowKey  the row key.
580         * @param columnKey  the column key.
581         * 
582         * @return The maximum outlier.
583         */
584        public Number getMaxOutlier(Comparable rowKey, Comparable columnKey) {
585            Number result = null;
586            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
587                    rowKey, columnKey);
588            if (item != null) {
589                result = item.getMaxOutlier();
590            }
591            return result;
592        }
593    
594        /**
595         * Returns a list of outlier values for an item.
596         * 
597         * @param row  the row index (zero-based).
598         * @param column  the column index (zero-based).
599         * 
600         * @return A list of outlier values.
601         */
602        public List getOutliers(int row, int column) {
603            List result = null;
604            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
605                    row, column);
606            if (item != null) {
607                result = item.getOutliers();
608            }
609            return result;
610        }
611    
612        /**
613         * Returns a list of outlier values for an item.
614         * 
615         * @param rowKey  the row key.
616         * @param columnKey  the column key.
617         * 
618         * @return A list of outlier values.
619         */
620        public List getOutliers(Comparable rowKey, Comparable columnKey) {
621            List result = null;
622            BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(
623                    rowKey, columnKey);
624            if (item != null) {
625                result = item.getOutliers();
626            }
627            return result;
628        }
629        
630        /**
631         * Tests this dataset for equality with an arbitrary object.
632         * 
633         * @param obj  the object to test against (<code>null</code> permitted).
634         * 
635         * @return A boolean.
636         */
637        public boolean equals(Object obj) {
638            if (obj == this) {
639                return true;   
640            }
641            if (obj instanceof DefaultBoxAndWhiskerCategoryDataset) {
642                DefaultBoxAndWhiskerCategoryDataset dataset 
643                        = (DefaultBoxAndWhiskerCategoryDataset) obj;
644                return ObjectUtilities.equal(this.data, dataset.data);
645            }
646            return false;
647        }
648    
649    }