001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2022, 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-2022, 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.internal.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 row : validRows) {
136            if (row < rowCount) {
137                Number n = data.getValue(row, column);
138                if (n != null) {
139                    total += n.doubleValue();
140                }
141            }
142        }
143        return total;
144    }
145
146    /**
147     * Returns the total of the values in one row of the supplied data
148     * table.
149     *
150     * @param data  the table of values ({@code null} not permitted).
151     * @param row  the row index (zero-based).
152     *
153     * @return The total of the values in the specified row.
154     */
155    public static double calculateRowTotal(Values2D data, int row) {
156        Args.nullNotPermitted(data, "data");
157        double total = 0.0;
158        int columnCount = data.getColumnCount();
159        for (int c = 0; c < columnCount; c++) {
160            Number n = data.getValue(row, c);
161            if (n != null) {
162                total += n.doubleValue();
163            }
164        }
165        return total;
166    }
167
168    /**
169     * Returns the total of the values in one row of the supplied data
170     * table by taking only the column numbers in the array into account.
171     *
172     * @param data  the table of values ({@code null} not permitted).
173     * @param row  the row index (zero-based).
174     * @param validCols the array with valid cols (zero-based).
175     *
176     * @return The total of the valid values in the specified row.
177     */
178    public static double calculateRowTotal(Values2D data, int row,
179             int[] validCols) {
180        Args.nullNotPermitted(data, "data");
181        double total = 0.0;
182        int colCount = data.getColumnCount();
183        for (int col : validCols) {
184            if (col < colCount) {
185                Number n = data.getValue(row, col);
186                if (n != null) {
187                    total += n.doubleValue();
188                }
189            }
190        }
191        return total;
192    }
193
194    /**
195     * Constructs an array of {@code Number} objects from an array of
196     * {@code double} primitives.
197     *
198     * @param data  the data ({@code null} not permitted).
199     *
200     * @return An array of {@code double}.
201     */
202    public static Number[] createNumberArray(double[] data) {
203        Args.nullNotPermitted(data, "data");
204        Number[] result = new Number[data.length];
205        for (int i = 0; i < data.length; i++) {
206            result[i] = data[i];
207        }
208        return result;
209    }
210
211    /**
212     * Constructs an array of arrays of {@code Number} objects from a
213     * corresponding structure containing {@code double} primitives.
214     *
215     * @param data  the data ({@code null} not permitted).
216     *
217     * @return An array of {@code double}.
218     */
219    public static Number[][] createNumberArray2D(double[][] data) {
220        Args.nullNotPermitted(data, "data");
221        int l1 = data.length;
222        Number[][] result = new Number[l1][];
223        for (int i = 0; i < l1; i++) {
224            result[i] = createNumberArray(data[i]);
225        }
226        return result;
227    }
228
229    /**
230     * Returns a {@link KeyedValues} instance that contains the cumulative
231     * percentage values for the data in another {@link KeyedValues} instance.
232     * <p>
233     * The percentages are values between 0.0 and 1.0 (where 1.0 = 100%).
234     *
235     * @param data  the data ({@code null} not permitted).
236     *
237     * @return The cumulative percentages.
238     */
239    public static <K extends Comparable<K>> KeyedValues<K> getCumulativePercentages(KeyedValues<K> data) {
240        Args.nullNotPermitted(data, "data");
241        DefaultKeyedValues<K> result = new DefaultKeyedValues<>();
242        double total = 0.0;
243        for (int i = 0; i < data.getItemCount(); i++) {
244            Number v = data.getValue(i);
245            if (v != null) {
246                total = total + v.doubleValue();
247            }
248        }
249        double runningTotal = 0.0;
250        for (int i = 0; i < data.getItemCount(); i++) {
251            Number v = data.getValue(i);
252            if (v != null) {
253                runningTotal = runningTotal + v.doubleValue();
254            }
255            result.addValue(data.getKey(i), runningTotal / total);
256        }
257        return result;
258    }
259
260}