001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2009, 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     * DataUtilities.java
029     * ------------------
030     * (C) Copyright 2003-2009, by Object Refinery Limited and contributors.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   Peter Kolb (patch 2511330);
034     *
035     * Changes
036     * -------
037     * 05-Mar-2003 : Version 1 (DG);
038     * 03-Mar-2005 : Moved createNumberArray() and createNumberArray2D() methods
039     *               from the DatasetUtilities class (DG);
040     * 17-May-2005 : Added calculateColumnTotal() and calculateRowTotal()
041     *               methods (DG);
042     * 28-Jan-2009 : Added equal(double[][], double[][]) method (DG);
043     * 28-Jan-2009 : Added clone(double[][]) method (DG);
044     * 04-Feb-2009 : Added calculateColumnTotal/RowTotal variants (PK);
045     *
046     */
047    
048    package org.jfree.data;
049    
050    import java.util.Arrays;
051    import org.jfree.data.general.DatasetUtilities;
052    
053    /**
054     * Utility methods for use with some of the data classes (but not the datasets,
055     * see {@link DatasetUtilities}).
056     */
057    public abstract class DataUtilities {
058    
059        /**
060         * Tests two arrays for equality.  To be considered equal, the arrays must
061         * have exactly the same dimensions, and the values in each array must also
062         * match (two values that qre both NaN or both INF are considered equal
063         * in this test).
064         *
065         * @param a  the first array (<code>null</code> permitted).
066         * @param b  the second array (<code>null</code> permitted).
067         *
068         * @return A boolean.
069         *
070         * @since 1.0.13
071         */
072        public static boolean equal(double[][] a, double[][] b) {
073            if (a == null) {
074                return (b == null);
075            }
076            if (b == null) {
077                return false;  // already know 'a' isn't null
078            }
079            if (a.length != b.length) {
080                return false;
081            }
082            for (int i = 0; i < a.length; i++) {
083                if (!Arrays.equals(a[i], b[i])) {
084                    return false;
085                }
086            }
087            return true;
088        }
089    
090        /**
091         * Returns a clone of the specified array.
092         *
093         * @param source  the source array (<code>null</code> not permitted).
094         *
095         * @return A clone of the array.
096         *
097         * @since 1.0.13
098         */
099        public static double[][] clone(double[][] source) {
100            if (source == null) {
101                throw new IllegalArgumentException("Null 'source' argument.");
102            }
103            double[][] clone = new double[source.length][];
104            for (int i = 0; i < source.length; i++) {
105                if (source[i] != null) {
106                    double[] row = new double[source[i].length];
107                    System.arraycopy(source[i], 0, row, 0, source[i].length);
108                    clone[i] = row;
109                }
110            }
111            return clone;
112        }
113    
114        /**
115         * Returns the total of the values in one column of the supplied data
116         * table.
117         *
118         * @param data  the table of values (<code>null</code> not permitted).
119         * @param column  the column index (zero-based).
120         *
121         * @return The total of the values in the specified column.
122         */
123        public static double calculateColumnTotal(Values2D data, int column) {
124            if (data == null) {
125                throw new IllegalArgumentException("Null 'data' argument.");
126            }
127            double total = 0.0;
128            int rowCount = data.getRowCount();
129            for (int r = 0; r < rowCount; r++) {
130                Number n = data.getValue(r, column);
131                if (n != null) {
132                    total += n.doubleValue();
133                }
134            }
135            return total;
136        }
137    
138        /**
139         * Returns the total of the values in one column of the supplied data
140         * table by taking only the row numbers in the array into account.
141         *
142         * @param data  the table of values (<code>null</code> not permitted).
143         * @param column  the column index (zero-based).
144         * @param validRows the array with valid rows (zero-based).
145         *
146         * @return The total of the valid values in the specified column.
147         *
148         * @since 1.0.13
149         */
150         public static double calculateColumnTotal(Values2D data, int column,
151                 int[] validRows) {
152            if (data == null) {
153                throw new IllegalArgumentException("Null 'data' argument.");
154            }
155            double total = 0.0;
156            int rowCount = data.getRowCount();
157            for (int v = 0; v < validRows.length; v++) {
158                    int row = validRows[v];
159                    if (row < rowCount) {
160                        Number n = data.getValue(row, column);
161                        if (n != null) {
162                            total += n.doubleValue();
163                        }
164                    }
165            }
166            return total;
167        }
168    
169        /**
170         * Returns the total of the values in one row of the supplied data
171         * table.
172         *
173         * @param data  the table of values (<code>null</code> not permitted).
174         * @param row  the row index (zero-based).
175         *
176         * @return The total of the values in the specified row.
177         */
178        public static double calculateRowTotal(Values2D data, int row) {
179            if (data == null) {
180                throw new IllegalArgumentException("Null 'data' argument.");
181            }
182            double total = 0.0;
183            int columnCount = data.getColumnCount();
184            for (int c = 0; c < columnCount; c++) {
185                Number n = data.getValue(row, c);
186                if (n != null) {
187                    total += n.doubleValue();
188                }
189            }
190            return total;
191        }
192    
193        /**
194         * Returns the total of the values in one row of the supplied data
195         * table by taking only the column numbers in the array into account.
196         *
197         * @param data  the table of values (<code>null</code> not permitted).
198         * @param row  the row index (zero-based).
199         * @param validCols the array with valid cols (zero-based).
200         *
201         * @return The total of the valid values in the specified row.
202         *
203         * @since 1.0.13
204         */
205         public static double calculateRowTotal(Values2D data, int row,
206                 int[] validCols) {
207            if (data == null) {
208                throw new IllegalArgumentException("Null 'data' argument.");
209            }
210            double total = 0.0;
211            int colCount = data.getColumnCount();
212            for (int v = 0; v < validCols.length; v++) {
213                    int col = validCols[v];
214                    if (col < colCount) {
215                        Number n = data.getValue(row, col);
216                        if (n != null) {
217                            total += n.doubleValue();
218                        }
219                    }
220            }
221            return total;
222        }
223    
224        /**
225         * Constructs an array of <code>Number</code> objects from an array of
226         * <code>double</code> primitives.
227         *
228         * @param data  the data (<code>null</code> not permitted).
229         *
230         * @return An array of <code>Double</code>.
231         */
232        public static Number[] createNumberArray(double[] data) {
233            if (data == null) {
234                throw new IllegalArgumentException("Null 'data' argument.");
235            }
236            Number[] result = new Number[data.length];
237            for (int i = 0; i < data.length; i++) {
238                result[i] = new Double(data[i]);
239            }
240            return result;
241        }
242    
243        /**
244         * Constructs an array of arrays of <code>Number</code> objects from a
245         * corresponding structure containing <code>double</code> primitives.
246         *
247         * @param data  the data (<code>null</code> not permitted).
248         *
249         * @return An array of <code>Double</code>.
250         */
251        public static Number[][] createNumberArray2D(double[][] data) {
252            if (data == null) {
253                throw new IllegalArgumentException("Null 'data' argument.");
254            }
255            int l1 = data.length;
256            Number[][] result = new Number[l1][];
257            for (int i = 0; i < l1; i++) {
258                result[i] = createNumberArray(data[i]);
259            }
260            return result;
261        }
262    
263        /**
264         * Returns a {@link KeyedValues} instance that contains the cumulative
265         * percentage values for the data in another {@link KeyedValues} instance.
266         * <p>
267         * The percentages are values between 0.0 and 1.0 (where 1.0 = 100%).
268         *
269         * @param data  the data (<code>null</code> not permitted).
270         *
271         * @return The cumulative percentages.
272         */
273        public static KeyedValues getCumulativePercentages(KeyedValues data) {
274            if (data == null) {
275                throw new IllegalArgumentException("Null 'data' argument.");
276            }
277            DefaultKeyedValues result = new DefaultKeyedValues();
278            double total = 0.0;
279            for (int i = 0; i < data.getItemCount(); i++) {
280                Number v = data.getValue(i);
281                if (v != null) {
282                    total = total + v.doubleValue();
283                }
284            }
285            double runningTotal = 0.0;
286            for (int i = 0; i < data.getItemCount(); i++) {
287                Number v = data.getValue(i);
288                if (v != null) {
289                    runningTotal = runningTotal + v.doubleValue();
290                }
291                result.addValue(data.getKey(i), new Double(runningTotal / total));
292            }
293            return result;
294        }
295    
296    }