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