    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    }