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    }