001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2020, 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 * [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-2020, 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 */
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     * @since 1.0.13
061     */
062    public static boolean equal(double[][] a, double[][] b) {
063        if (a == null) {
064            return (b == null);
065        }
066        if (b == null) {
067            return false;  // already know 'a' isn't null
068        }
069        if (a.length != b.length) {
070            return false;
071        }
072        for (int i = 0; i < a.length; i++) {
073            if (!Arrays.equals(a[i], b[i])) {
074                return false;
075            }
076        }
077        return true;
078    }
079
080    /**
081     * Returns a clone of the specified array.
082     *
083     * @param source  the source array ({@code null} not permitted).
084     *
085     * @return A clone of the array.
086     *
087     * @since 1.0.13
088     */
089    public static double[][] clone(double[][] source) {
090        Args.nullNotPermitted(source, "source");
091        double[][] clone = new double[source.length][];
092        for (int i = 0; i < source.length; i++) {
093            if (source[i] != null) {
094                double[] row = new double[source[i].length];
095                System.arraycopy(source[i], 0, row, 0, source[i].length);
096                clone[i] = row;
097            }
098        }
099        return clone;
100    }
101
102    /**
103     * Returns the total of the values in one column of the supplied data
104     * table.
105     *
106     * @param data  the table of values ({@code null} not permitted).
107     * @param column  the column index (zero-based).
108     *
109     * @return The total of the values in the specified column.
110     */
111    public static double calculateColumnTotal(Values2D data, int column) {
112        Args.nullNotPermitted(data, "data");
113        double total = 0.0;
114        int rowCount = data.getRowCount();
115        for (int r = 0; r < rowCount; r++) {
116            Number n = data.getValue(r, column);
117            if (n != null) {
118                total += n.doubleValue();
119            }
120        }
121        return total;
122    }
123
124    /**
125     * Returns the total of the values in one column of the supplied data
126     * table by taking only the row numbers in the array into account.
127     *
128     * @param data  the table of values ({@code null} not permitted).
129     * @param column  the column index (zero-based).
130     * @param validRows the array with valid rows (zero-based).
131     *
132     * @return The total of the valid values in the specified column.
133     *
134     * @since 1.0.13
135     */
136    public static double calculateColumnTotal(Values2D data, int column,
137             int[] validRows) {
138        Args.nullNotPermitted(data, "data");
139        double total = 0.0;
140        int rowCount = data.getRowCount();
141        for (int v = 0; v < validRows.length; v++) {
142            int row = validRows[v];
143            if (row < rowCount) {
144                Number n = data.getValue(row, column);
145                if (n != null) {
146                    total += n.doubleValue();
147                }
148            }
149        }
150        return total;
151    }
152
153    /**
154     * Returns the total of the values in one row of the supplied data
155     * table.
156     *
157     * @param data  the table of values ({@code null} not permitted).
158     * @param row  the row index (zero-based).
159     *
160     * @return The total of the values in the specified row.
161     */
162    public static double calculateRowTotal(Values2D data, int row) {
163        Args.nullNotPermitted(data, "data");
164        double total = 0.0;
165        int columnCount = data.getColumnCount();
166        for (int c = 0; c < columnCount; c++) {
167            Number n = data.getValue(row, c);
168            if (n != null) {
169                total += n.doubleValue();
170            }
171        }
172        return total;
173    }
174
175    /**
176     * Returns the total of the values in one row of the supplied data
177     * table by taking only the column numbers in the array into account.
178     *
179     * @param data  the table of values ({@code null} not permitted).
180     * @param row  the row index (zero-based).
181     * @param validCols the array with valid cols (zero-based).
182     *
183     * @return The total of the valid values in the specified row.
184     *
185     * @since 1.0.13
186     */
187    public static double calculateRowTotal(Values2D data, int row,
188             int[] validCols) {
189        Args.nullNotPermitted(data, "data");
190        double total = 0.0;
191        int colCount = data.getColumnCount();
192        for (int v = 0; v < validCols.length; v++) {
193            int col = validCols[v];
194            if (col < colCount) {
195                Number n = data.getValue(row, col);
196                if (n != null) {
197                    total += n.doubleValue();
198                }
199            }
200        }
201        return total;
202    }
203
204    /**
205     * Constructs an array of {@code Number} objects from an array of
206     * {@code double} primitives.
207     *
208     * @param data  the data ({@code null} not permitted).
209     *
210     * @return An array of {@code double}.
211     */
212    public static Number[] createNumberArray(double[] data) {
213        Args.nullNotPermitted(data, "data");
214        Number[] result = new Number[data.length];
215        for (int i = 0; i < data.length; i++) {
216            result[i] = data[i];
217        }
218        return result;
219    }
220
221    /**
222     * Constructs an array of arrays of {@code Number} objects from a
223     * corresponding structure containing {@code double} primitives.
224     *
225     * @param data  the data ({@code null} not permitted).
226     *
227     * @return An array of {@code double}.
228     */
229    public static Number[][] createNumberArray2D(double[][] data) {
230        Args.nullNotPermitted(data, "data");
231        int l1 = data.length;
232        Number[][] result = new Number[l1][];
233        for (int i = 0; i < l1; i++) {
234            result[i] = createNumberArray(data[i]);
235        }
236        return result;
237    }
238
239    /**
240     * Returns a {@link KeyedValues} instance that contains the cumulative
241     * percentage values for the data in another {@link KeyedValues} instance.
242     * <p>
243     * The percentages are values between 0.0 and 1.0 (where 1.0 = 100%).
244     *
245     * @param data  the data ({@code null} not permitted).
246     *
247     * @return The cumulative percentages.
248     */
249    public static KeyedValues getCumulativePercentages(KeyedValues data) {
250        Args.nullNotPermitted(data, "data");
251        DefaultKeyedValues result = new DefaultKeyedValues();
252        double total = 0.0;
253        for (int i = 0; i < data.getItemCount(); i++) {
254            Number v = data.getValue(i);
255            if (v != null) {
256                total = total + v.doubleValue();
257            }
258        }
259        double runningTotal = 0.0;
260        for (int i = 0; i < data.getItemCount(); i++) {
261            Number v = data.getValue(i);
262            if (v != null) {
263                runningTotal = runningTotal + v.doubleValue();
264            }
265            result.addValue(data.getKey(i), runningTotal / total);
266        }
267        return result;
268    }
269
270}