001/* ======================================================
002 * JFreeChart : a chart library for the Java(tm) platform
003 * ======================================================
004 *
005 * (C) Copyright 2000-present, by David Gilbert and Contributors.
006 *
007 * Project Info:  https://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    private DataUtils() {
050        // no requirement to instantiate
051    }
052
053    /**
054     * Tests two arrays for equality.  To be considered equal, the arrays must
055     * have exactly the same dimensions, and the values in each array must also
056     * match (two values that qre both NaN or both INF are considered equal
057     * in this test).
058     *
059     * @param a  the first array ({@code null} permitted).
060     * @param b  the second array ({@code null} permitted).
061     *
062     * @return A boolean.
063     */
064    public static boolean equal(double[][] a, double[][] b) {
065        if (a == null) {
066            return (b == null);
067        }
068        if (b == null) {
069            return false;  // already know 'a' isn't null
070        }
071        if (a.length != b.length) {
072            return false;
073        }
074        for (int i = 0; i < a.length; i++) {
075            if (!Arrays.equals(a[i], b[i])) {
076                return false;
077            }
078        }
079        return true;
080    }
081
082    /**
083     * Returns a clone of the specified array.
084     *
085     * @param source  the source array ({@code null} not permitted).
086     *
087     * @return A clone of the array.
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    public static double calculateColumnTotal(Values2D data, int column,
135             int[] validRows) {
136        Args.nullNotPermitted(data, "data");
137        double total = 0.0;
138        int rowCount = data.getRowCount();
139        for (int v = 0; v < validRows.length; v++) {
140            int row = validRows[v];
141            if (row < rowCount) {
142                Number n = data.getValue(row, column);
143                if (n != null) {
144                    total += n.doubleValue();
145                }
146            }
147        }
148        return total;
149    }
150
151    /**
152     * Returns the total of the values in one row of the supplied data
153     * table.
154     *
155     * @param data  the table of values ({@code null} not permitted).
156     * @param row  the row index (zero-based).
157     *
158     * @return The total of the values in the specified row.
159     */
160    public static double calculateRowTotal(Values2D data, int row) {
161        Args.nullNotPermitted(data, "data");
162        double total = 0.0;
163        int columnCount = data.getColumnCount();
164        for (int c = 0; c < columnCount; c++) {
165            Number n = data.getValue(row, c);
166            if (n != null) {
167                total += n.doubleValue();
168            }
169        }
170        return total;
171    }
172
173    /**
174     * Returns the total of the values in one row of the supplied data
175     * table by taking only the column numbers in the array into account.
176     *
177     * @param data  the table of values ({@code null} not permitted).
178     * @param row  the row index (zero-based).
179     * @param validCols the array with valid cols (zero-based).
180     *
181     * @return The total of the valid values in the specified row.
182     */
183    public static double calculateRowTotal(Values2D data, int row,
184             int[] validCols) {
185        Args.nullNotPermitted(data, "data");
186        double total = 0.0;
187        int colCount = data.getColumnCount();
188        for (int v = 0; v < validCols.length; v++) {
189            int col = validCols[v];
190            if (col < colCount) {
191                Number n = data.getValue(row, col);
192                if (n != null) {
193                    total += n.doubleValue();
194                }
195            }
196        }
197        return total;
198    }
199
200    /**
201     * Constructs an array of {@code Number} objects from an array of
202     * {@code double} primitives.
203     *
204     * @param data  the data ({@code null} not permitted).
205     *
206     * @return An array of {@code double}.
207     */
208    public static Number[] createNumberArray(double[] data) {
209        Args.nullNotPermitted(data, "data");
210        Number[] result = new Number[data.length];
211        for (int i = 0; i < data.length; i++) {
212            result[i] = data[i];
213        }
214        return result;
215    }
216
217    /**
218     * Constructs an array of arrays of {@code Number} objects from a
219     * corresponding structure containing {@code double} primitives.
220     *
221     * @param data  the data ({@code null} not permitted).
222     *
223     * @return An array of {@code double}.
224     */
225    public static Number[][] createNumberArray2D(double[][] data) {
226        Args.nullNotPermitted(data, "data");
227        int l1 = data.length;
228        Number[][] result = new Number[l1][];
229        for (int i = 0; i < l1; i++) {
230            result[i] = createNumberArray(data[i]);
231        }
232        return result;
233    }
234
235    /**
236     * Returns a {@link KeyedValues} instance that contains the cumulative
237     * percentage values for the data in another {@link KeyedValues} instance.
238     * <p>
239     * The percentages are values between 0.0 and 1.0 (where 1.0 = 100%).
240     *
241     * @param data  the data ({@code null} not permitted).
242     *
243     * @return The cumulative percentages.
244     */
245    public static KeyedValues getCumulativePercentages(KeyedValues data) {
246        Args.nullNotPermitted(data, "data");
247        DefaultKeyedValues result = new DefaultKeyedValues();
248        double total = 0.0;
249        for (int i = 0; i < data.getItemCount(); i++) {
250            Number v = data.getValue(i);
251            if (v != null) {
252                total = total + v.doubleValue();
253            }
254        }
255        double runningTotal = 0.0;
256        for (int i = 0; i < data.getItemCount(); i++) {
257            Number v = data.getValue(i);
258            if (v != null) {
259                runningTotal = runningTotal + v.doubleValue();
260            }
261            result.addValue(data.getKey(i), runningTotal / total);
262        }
263        return result;
264    }
265
266}