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}