KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > progra > charting > ChartUtilities


1 /*
2     JOpenChart Java Charting Library and Toolkit
3     Copyright (C) 2001 Sebastian Müller
4     http://jopenchart.sourceforge.net
5
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Lesser General Public
8     License as published by the Free Software Foundation; either
9     version 2.1 of the License, or (at your option) any later version.
10
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14     Lesser General Public License for more details.
15
16     You should have received a copy of the GNU Lesser General Public
17     License along with this library; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20     ChartUtilities.java
21     Created on 21. September 2001, 17:42
22  */

23
24 package de.progra.charting;
25
26 import java.util.*;
27
28 /**
29  * This class offers multiple static methods to perform mathematical
30  * operations concerning the Chart, e.g. methods for rounding the minimal and
31  * maximal x-values gracefully.
32  * @author mueller
33  * @version 1.0
34  */

35 public class ChartUtilities {
36
37     /** This method calculates the optimal rounding for the minimal and
38      * maximal ChartModel values. It computes the difference of the
39      * minimal and maximal value and rounds the values min and max according
40      * to the exponent of the difference.
41      * @param min the minimal column value of the ChartDataModel
42      * @param max the maximal column value of the ChartDataModel
43      * @return a double[] with the rounded minimal value at index 0 and
44      * the maximal value at index 1.
45      */

46     public static double[] performAutoScale(double min, double max) {
47         double[] d = new double[2]; // d[0] = min d[1] = max
48

49         double diff = max - min;
50         
51         d[0] = floor(min, exp(diff));
52         d[1] = ceil(max, exp(diff));
53         
54         return d;
55     }
56     
57     /** Calculates the best tick spacing for the rounded minimal and maximal
58      * values.
59      * @param min the rounded minimal value
60      * @param max the rounded maximal value
61      * @return the spacing of ticks on the x-axis.
62      */

63     public static double calculateTickSpacing(double min, double max) {
64         double spacing = 1.0;
65         
66         double diff = max - min;
67         
68         int exp = exp(diff);
69         
70     exp--;
71         
72         spacing = 1.0 * Math.pow(10.0, (double)exp);
73     
74     // Currently, only every second tick gets a label, so 20 - 40 ticks are fine.
75
// This should be reduced in a loop probably.
76
if((diff / spacing) < 20)
77             return 0.5 * spacing;
78     else if((diff / spacing) > 40)
79         return 2 * spacing;
80         else
81             return spacing;
82     }
83     
84     /** This function performs a polynomial interpolation using a set of
85      * given x and y values. It uses Neville's interpolation algorithm.
86      * @param xa the array of known x-values
87      * @param ya the array of known y-values
88      * @param x the x value for which the y value will be computed
89      * @return the corresponding y value
90      */

91     public static double interpolate(double xa[], double ya[], double x) {
92         /*
93             Given arrays xa[1..n] and ya[1..n], and given a value x,
94             this routine returns a value y.
95             If P(x) is the polynomial of degree N ? 1
96             such that P(xa[i]) = ya[i];
97             i = 1...n, then the returned value y = P(x).
98          */

99
100         if(xa.length != ya.length || xa.length == 0 || ya.length == 0) {
101             System.out.println("** Invalid Parameter");
102             return Double.NaN;
103         }
104         
105         int n = xa.length;
106         double y = 0.0;
107         double dy = 0.0;
108         
109         int i, m, ns = 1;
110         double den, dif, dift, ho, hp, w;
111         double[] c = new double[n];
112         double[] d = new double[n];
113         dif = Math.abs(x - xa[0]);
114         
115         for (i = 0; i < n; i++) { // Here we find the index ns of the closest table entry,
116
if ( (dift = Math.abs(x - xa[i])) < dif) {
117                 ns = i;
118                 dif=dift;
119             }
120             c[i] = ya[i]; // and initialize the tableau of c's and d's.
121
d[i] = ya[i];
122         }
123         
124         y = ya[ns--]; // This is the initial approximation to y.
125
//System.out.println("** y ~ "+y);
126

127         for (m = 0; m < n - 1; m++) { // For each column of the tableau,
128
for (i = 0; i < n - m - 1; i++) { // we loop over the current c's and d's and update them.
129

130                 //System.out.println("** m = "+m+", i = "+i);
131
ho = xa[i] - x;
132                 hp = xa[i + m + 1] - x;
133                 w = c[i + 1] - d[i];
134                 
135                 if ( (den = ho - hp) == 0.0) {
136                     return Double.NaN;
137                 }
138                 // This error can occur only if two input xa's are (to within roundof identical.
139

140                 //System.out.println("** ho = "+ho+", hp = "+hp);
141

142                 den = w / den;
143                 d[i] = hp * den; // Here the c's and d's are updated.
144
c[i] = ho * den;
145                 //System.out.println("** c[i] = "+c[i]+", d[i] = "+d[i]);
146
}
147
148             y += (dy = (2 * (ns + 1) < (n - m) ? c[ns + 1] : d[ns--]));
149             //System.out.println("** dy = "+dy+", y = "+y);
150

151             /*
152             After each column in the tableau is completed, we decide which correction, c or d,
153             we want to add to our accumulating value of y, i.e., which path to take through the
154             tableau forking up or down. We do this in such a way as to take the most "straight
155             line" route through the tableau to its apex, updating ns accordingly to keep track of
156             where we are. This route keeps the partial approximations centered (insofar as possible)
157             on the target x. The last dy added is thus the error indication.
158             */

159       }
160
161       return y;
162     }
163     
164     /** This method returns the largest double value that is smaller than
165      * <code> d = x * 10<sup>exp</sup></code> where x is rounded down to
166      * the closest integer.
167      * @param d the double value to be rounded
168      * @param exp the exponent of 10 to which d should be rounded
169      * @return <code> Math.floor(x) * 10<sup>exp</sup></code>
170      */

171     public static double floor(double d, int exp) {
172         double x = 1.0 * Math.pow(10.0, (double)exp);
173         
174         return Math.floor(d / x) * x;
175     }
176
177     /** This method returns the smallest double value that is smaller than
178      * <code> d = x * 10<sup>exp</exp></code> where x is rounded up to
179      * the closest integer.
180      * @param d the double value to be rounded
181      * @param exp the exponent of 10 to which d should be rounded
182      * @return <code> Math.ceil(x) * 10<sup>exp</sup></code>
183      */

184     public static double ceil(double d, int exp) {
185         double x = 1.0 * Math.pow(10.0, (double)exp);
186         
187         return Math.ceil(d / x) * x;
188     }
189     
190     /** A double value can be represented like
191      * <code>d = x * 10<sup>exp</sup></code> and this method returns
192      * the value of exp for a double d.
193      * @param d the double value
194      * @return the exponent of 10
195      */

196     public static int exp(double d) {
197         int exp = 0;
198         boolean positive = (d <= -1 || d >= 1 );
199         
200         while((d <= -10) || (d >= 10) || ((d > -1) && (d < 1))) {
201             if(positive) {
202                 d /= 10;
203                 exp++;
204             } else {
205                 d *= 10;
206                 exp--;
207             }
208         }
209         
210         return exp;
211     }
212     
213             
214     /** Transforms a two-dimensional array of primitives
215      * to an array of Numbers.
216      */

217     public static Number JavaDoc[][] transformArray(int[][] data) {
218         Number JavaDoc[][] n = new Number JavaDoc[data.length][data[0].length];
219         
220         for(int i = 0; i < data.length; i++)
221             for(int j = 0; j < data[0].length; j++)
222                 n[i][j] = new Integer JavaDoc(data[i][j]);
223                 
224         return n;
225     }
226     
227     /** Transforms a two-dimensional array of primitives
228      * to an array of Numbers.
229      */

230     public static Number JavaDoc[][] transformArray(double[][] data) {
231         Number JavaDoc[][] n = new Number JavaDoc[data.length][data[0].length];
232         
233         for(int i = 0; i < data.length; i++)
234             for(int j = 0; j < data[0].length; j++)
235                 n[i][j] = new Double JavaDoc(data[i][j]);
236                 
237         return n;
238     }
239     
240     /** Transforms an array of primitives
241      * to an array of Numbers.
242      */

243     public static Number JavaDoc[] transformArray(double[] data) {
244         Number JavaDoc[] n = new Number JavaDoc[data.length];
245         
246         for(int i = 0; i < data.length; i++)
247            n[i] = new Double JavaDoc(data[i]);
248                 
249         return n;
250     }
251     
252     /** Transforms an array of primitives
253      * to an array of Numbers.
254      */

255     public static Number JavaDoc[] transformArray(int[] data) {
256         Number JavaDoc[] n = new Number JavaDoc[data.length];
257         
258         for(int i = 0; i < data.length; i++)
259            n[i] = new Integer JavaDoc(data[i]);
260                 
261         return n;
262     }
263     
264     /** Adds a two-dimensional array to a TreeSet. */
265     public static void addDataToSet(TreeSet set, Number JavaDoc[][] data) {
266         for(int i = 0; i < data.length; i++) {
267             set.addAll(Arrays.asList(data[i]));
268         }
269     }
270     
271     /** A test routine. */
272     public static void main(String JavaDoc[] args) {
273         double min = -0.00337;
274         double max = 0.00745;
275         
276         double[] d = performAutoScale(min, max);
277         
278         System.out.println("** AutoScaling: ("+min+", "+max+") -> ("+d[0]+", "+d[1]+")");
279         
280         double s = calculateTickSpacing(d[0], d[1]);
281         
282         System.out.print("** Ticks: ");
283         for(double i = d[0]; i <= d[1]; i += s)
284             System.out.print(" "+i+" ");
285         System.out.println();
286         
287         System.out.println("** Performing interpolation for 4*x^2");
288         System.out.println("** Given values [-4, 64], [0, 0], [3, 36]");
289         
290         double xa[] = {-4.0, 0.0, 3.0};
291         double ya[] = {64.0, 0.0, 36.0};
292         
293         System.out.print("** Calculating values");
294         //double f = interpolate(xa, ya, 1.0);
295
//System.out.println("** f(1) = "+f);
296

297         for(double i = -5.0; i < 6.0; i += 0.5) {
298             System.out.print("["+i+", "+interpolate(xa, ya, i)+"]");
299         }
300         
301         System.out.println();
302         
303         System.out.println("** Performing interpolation for 5 * x^3 - 4 * x^2 + 2 * x - 5");
304         System.out.println("** Given values [-5, -740], [0, -5], [1, -2], [5, 530]");
305         
306         double xb[] = {-5.0, 0.0, 1.0, 5.0};
307         double yb[] = {-740.0, -5.0, -2.0, 530.0};
308         
309         System.out.print("** Calculating values ");
310         
311         for(double i = -5.0; i < 6.0; i += 0.5) {
312             System.out.print("["+i+", "+interpolate(xb, yb, i)+"]");
313         }
314         
315         System.out.println();
316          
317     }
318 }
319
Popular Tags