KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > chart2d > Dataset


1 /**
2  * Chart2D, a java library for drawing two dimensional charts.
3  * Copyright (C) 2001 Jason J. Simas
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * The author of this library may be contacted at:
19  * E-mail: jjsimas@users.sourceforge.net
20  * Street Address: J J Simas, 887 Tico Road, Ojai, CA 93023-3555 USA
21  */

22
23
24 package net.sourceforge.chart2d;
25
26
27 import java.util.Vector JavaDoc;
28 import java.awt.geom.*;
29
30
31 /**
32  * The container for the data values to chart.
33  * A dataset is like a third order array (ex. float[][][]). The first order is
34  * the "sets" order. A set contains data divided by category. The "sets" refer
35  * to the objects described by the legend labels, if a legend exists. The
36  * second order is the "cats" or categories order. Data within a set can be
37  * divided by category. A category can have multiple data items. If using a
38  * graph chart, the categories are described by the labels-axis labels. For pie
39  * charts, there is only one category. The third order is the "items" order.
40  * The "items" order are the values for a particular category and set.<br>
41  * For example, if we had data for the years 1999 and 2000 of how many units were
42  * sold on each day during that time, then one way to chart this would be using
43  * a graph chart and making the years correspond to the "sets" order, "months",
44  * correspond to the "cats" order, and the number of units sold per day
45  * correspond to the "items" order.<br>
46  * There are two important rules to
47  * mention about this. For each set, the number of cats must be the same. For
48  * each cat, the number of items must be the same. In our example, we would
49  * probably want to choose the number of items per category to be 30,
50  * corresponding the average number of days per month. For months with less
51  * than thirty days, we would populate the unfilled days with the average of the
52  * filled days or simply carry the last value of the filled days into the
53  * unfilled days. For months with more than thirty days, we would average the
54  * last two days, and use that value as the value of the last day.<br>
55  * If passing to a PieChart2DProperties, the value used for each pie sector is
56  * the sum of the values in each set of data.
57  * Pass this to any number of PieChart2D or GraphChart2D objects.
58  */

59 public final class Dataset {
60
61
62   private Vector JavaDoc setVector;
63   private float greatest;
64   private float least;
65
66   private boolean needsUpdate = true;
67   private Vector JavaDoc needsUpdateVector = new Vector JavaDoc (5, 5);
68   private Vector JavaDoc chart2DVector = new Vector JavaDoc (5, 5);
69
70
71   /**
72    * Creates a dataset with 0 sets, 0 categories, and 0 items.
73    * Use the add (int, int, int, float) method to add data items.
74    */

75   public Dataset() {
76
77     needsUpdate = true;
78     setDatasetToDefaults();
79   }
80
81
82   /**
83    * Creates a dataset with the specified number of sets, categories per set,
84    * and items per set and per category.
85    * All internal objects are created at once.
86    * Use the set (int, int, int, float) method to add data items.
87    * @param sets The number of sets.
88    * @param cats The number of categories per set.
89    * @param items The number of items per category and per set.
90    */

91   public Dataset (int sets, int cats, int items) {
92
93     needsUpdate = true;
94     constructor (sets, cats, items);
95   }
96
97
98   /**
99    * Creates a dataset that is a copy of another dataset.
100    * Copying is a deep copy.
101    * @param dataset The dataset to copy.
102    */

103   public Dataset (Dataset dataset) {
104
105     needsUpdate = true;
106     set (dataset);
107   }
108
109
110   /**
111    * Sets the dataset to its default state.
112    * It's default state is a dataset with no sets, no cats, and no items.
113    */

114   public final void setDatasetToDefaults() {
115
116     needsUpdate = true;
117     constructor (0, 0, 0);
118   }
119
120
121   /**
122    * Sets the value for the variable in the set specified by set, the
123    * category specified by cat within the set, and the item specified by item
124    * within the category.
125    * If internal resources have not yet been allocated for this item, a null pointer will occurr.
126    * @param set The specified set of the variable.
127    * @param cat The specified cat of the variable.
128    * @param item The specified item of the variable.
129    * @param value The specified value of the variable.
130    */

131    public final void set (int set, int cat, int item, float value) {
132
133     needsUpdate = true;
134     ((Vector JavaDoc)((Vector JavaDoc)setVector.get (set)).get (cat)).set (item, new Float JavaDoc (value));
135    }
136
137
138   /**
139    * Sets all the values of this dataset from another Dataset.
140    * The values are copied using a deep copy.
141    * @param dataset The Dataset to copy.
142    */

143   public final void set (Dataset dataset) {
144
145     needsUpdate = true;
146     constructor (dataset.getNumSets(), dataset.getNumCats(), dataset.getNumItems());
147     int numSets = getNumSets();
148     int numCats = getNumCats();
149     int numItems = getNumItems();
150     for (int i = 0; i < numSets; ++i) {
151       for (int j = 0; j < numCats; ++j) {
152         for (int k = 0; k < numItems; ++k) {
153           set (i, j, k, dataset.get (i, j, k));
154         }
155       }
156     }
157   }
158
159
160   /**
161    * Resets the size of the dataset. Similar to the constructor Dataset (sets, cats, items).
162    * If current size is smaller, then fills with zeroes.
163    * @param sets The number of sets.
164    * @param cats The number of categories per set.
165    * @param items The number of items per category and per set.
166    */

167   public final void setSize (int sets, int cats, int items) {
168
169     needsUpdate = true;
170     //correct number of sets
171
if (setVector.size() > sets) setVector.setSize (sets);
172     for (int i = setVector.size(); i < sets; ++i) setVector.add (new Vector JavaDoc (cats, 10));
173     //correct number of cats in sets
174
for (int i = 0; i < sets; ++i) {
175       Vector JavaDoc catVector = (Vector JavaDoc)setVector.get (i);
176       if (catVector.size() > cats) catVector.setSize (cats);
177       for (int j = catVector.size(); j < cats; ++j) catVector.add (new Vector JavaDoc (items, 10));
178     }
179     //correct number of items in cats
180
for (int i = 0; i < sets; ++i) {
181       Vector JavaDoc catVector = (Vector JavaDoc)setVector.get (i);
182       for (int j = 0; j < cats; ++j) {
183         Vector JavaDoc itemVector = (Vector JavaDoc)catVector.get (j);
184         if (itemVector.size() > items) itemVector.setSize (items);
185         for (int k = itemVector.size(); k < items; ++k) itemVector.add (new Float JavaDoc (0f));
186       }
187     }
188   }
189
190
191   /**
192    * Gets the value for the variable in the set specified by set, the
193    * category specified by cat within the set, and the item specified by item
194    * within the category. If internal resources have not yet been allocated to
195    * contain such a variable a null pointer error may occurr.
196    * @param set The specified set of the variable.
197    * @param cat The specified cat of the variable.
198    * @param item The specified item of the variable.
199    * @return float The value of this variable.
200    */

201   public final float get (int set, int cat, int item) {
202
203     return ((Float JavaDoc)((Vector JavaDoc)((Vector JavaDoc)setVector.get (set)).get (cat)).get (item)).floatValue();
204   }
205
206
207   /**
208    * Gets the number of sets of data in this dataset.
209    * @return int The number of sets of this dataset.
210    */

211   public final int getNumSets() {
212     return setVector.size();
213   }
214
215
216   /**
217    * Gets the number of categories per set of data in this dataset. This
218    * method requires that the dataset be valid according to the method
219    * validate(). If not, then a null pointer error may occurr.
220    * @return int The number of cats per set of this dataset.
221    */

222   public final int getNumCats() {
223
224     if (getNumSets() > 0) return ((Vector JavaDoc)setVector.get (0)).size();
225     else return 0;
226   }
227
228
229   /**
230    * Gets the number of items per category of data in this dataset. This
231    * method requires that the dataset be valid according to the method
232    * validate(). If not, then a null pointer error may occurr.
233    * @return int The number of items per category of this dataset.
234    */

235   public final int getNumItems() {
236
237     if (getNumSets() > 0 && getNumCats() > 0) {
238       return ((Vector JavaDoc)(((Vector JavaDoc)setVector.get (0))).get (0)).size();
239     }
240     else return 0;
241   }
242
243
244   /**
245    * Gets the greatest value of all the data in the datset. If the dataset
246    * is invalid or empty, then returns Float.MIN_VALUE;
247    * @return float The greatest value in the dataset.
248    */

249   public final float getGreatest() {
250
251     update();
252     return greatest;
253   }
254
255
256   /**
257    * Gets the least value of all the data in the datset. If the dataset
258    * is invalid or empty, then returns Float.MAX_VALUE;
259    * @return float The least value in the dataset.
260    */

261   public final float getLeast() {
262
263     update();
264     return least;
265   }
266
267
268   /**
269    * Gets the average of some set of numbers.
270    * There are three possibilities.
271    * If you want the average of all data items in a particular set and cat, then pass -1 for item.
272    * If you want the average of all data items in a particular set and item, then pass -1 for cat.
273    * If you want the average of all data items in a particular cat and item, then pass -1 for set.
274    * Note, only one -1 may be passed in over all three parameters.
275    * @param set Which particular set or -1 for all.
276    * @param cat Which particular cat or -1 for all.
277    * @param item Which particular item or -1 for all.
278    */

279   public final float getAverage (int set, int cat, int item) {
280
281     float average = 0f;
282     if (getNumSets() > 0 && getNumCats() > 0 && getNumItems() > 0) {
283       if (set == -1) {
284         float sum = 0f;
285         for (int i = 0; i < getNumSets(); ++i) {
286           sum += get (i, cat, item);
287         }
288         average = sum / getNumSets();
289       }
290       if (cat == -1) {
291         float sum = 0f;
292         for (int j = 0; j < getNumCats(); ++j) {
293           sum += get (set, j, item);
294         }
295         average = sum / getNumCats();
296       }
297       if (item == -1) {
298         float sum = 0f;
299         for (int k = 0; k < getNumItems(); ++k) {
300           sum += get (set, cat, k);
301         }
302         average = sum / getNumItems();
303       }
304     }
305     return average;
306   }
307
308
309   /**
310    * Adds a value to the dataset increasing its internal data structure if necessary.
311    * @param set The specified set of the variable.
312    * @param cat The specified cat of the variable.
313    * @param item The specified item of the variable.
314    * @param value The specified value of the variable.
315    */

316   public final void add (int set, int cat, int item, float value) {
317
318     needsUpdate = true;
319     for (int i = setVector.size(); i <= set; ++i) {
320       setVector.add (new Vector JavaDoc (10, 10));
321     }
322     Vector JavaDoc catVector = (Vector JavaDoc)setVector.get (set);
323     for (int i = catVector.size(); i <= cat; ++i) {
324       catVector.add (new Vector JavaDoc (10, 10));
325     }
326     Vector JavaDoc itemVector = (Vector JavaDoc)catVector.get (cat);
327     for (int i = itemVector.size(); i <= item; ++i) {
328       itemVector.add (new Float JavaDoc (0f));
329     }
330     itemVector.set (item, new Float JavaDoc (value));
331   }
332
333
334   /**
335    * Analyzes the (input) dataset and adds moving average trend data to this dataset.
336    * Moving averages are computed by taking some odd number of adjacent items, computing their
337    * average and doing that from left to right for each item. How many adjacent items are used in
338    * computing the moving average is specified in the scope parameter.
339    * @param dataset The dataset to analyze.
340    * @param scope The number of data points to compute over.
341    */

342   public final void addMovingAverage (Dataset dataset, int scope) {
343
344     //make sure there is enough data
345
int numItemsTotal = dataset.getNumSets() > 0 ? dataset.getNumCats() * dataset.getNumItems() : 0;
346
347     if (numItemsTotal >= 3) { //do moving average calculation
348

349       //make sure scope is valid
350
if (scope < 3) scope = 3;
351       else {
352         if (scope > numItemsTotal) scope = numItemsTotal;
353         if (scope % 2 == 0) scope--;
354       }
355
356       //begin moving average calculation
357
int internalSetOffset = getNumSets(); //offset in case this object holds other sets of data
358
int itemOffset = (scope / 2); //location of first real moving average data
359
Vector JavaDoc itemGroup = new Vector JavaDoc (scope); //create enough data holders
360

361       //prepare for first real moving average data
362
ItemsForSet items = new ItemsForSet (dataset, 0, 0);
363       itemGroup.add (items);
364       for (int i = 0; i < scope - 1; ++i) {
365         items = items.getNextItemsForSet();
366         itemGroup.add (items);
367       }
368
369       //get the first moving average data (guaranteed)
370
ItemsForSet firstItems = (ItemsForSet)itemGroup.get (0); //hold first item for later
371
items = (ItemsForSet)itemGroup.get (itemOffset);
372       float firstAverage = getAverageOfItemsForSetGroup (itemGroup);
373       add (internalSetOffset, items.getCat(), items.getItem(), firstAverage);
374       itemGroup.remove (0);
375       itemGroup.add (((ItemsForSet)itemGroup.lastElement()).getNextItemsForSet()); //maybe null
376

377       //get the rest except for the last real moving average data
378
for (int i = itemOffset + 1; i < numItemsTotal - itemOffset - 1; ++i) {
379         items = (ItemsForSet)itemGroup.get (itemOffset);
380         add (internalSetOffset, items.getCat(), items.getItem(),
381           getAverageOfItemsForSetGroup (itemGroup));
382         itemGroup.remove (0);
383         itemGroup.add(((ItemsForSet)itemGroup.lastElement()).getNextItemsForSet());
384       }
385
386       //check if only one real moving average data
387
float lastAverage = firstAverage;
388       ItemsForSet lastItems = items.getNextItemsForSet(); //okay for 3,3
389
if (numItemsTotal > scope) {
390
391         //get the last real moving average data
392
items = (ItemsForSet)itemGroup.get (itemOffset);
393         lastAverage = getAverageOfItemsForSetGroup (itemGroup);
394         add (internalSetOffset, items.getCat(), items.getItem(), lastAverage);
395         lastItems = items.getNextItemsForSet();
396       }
397
398       //populate beginning with fake moving average data
399
for (int i = 0; i < itemOffset; ++i) {
400         add (internalSetOffset, firstItems.getCat(), firstItems.getItem(), firstAverage);
401         firstItems = firstItems.getNextItemsForSet();
402       }
403
404       //populate end with fake moving average data
405
for (int i = numItemsTotal - itemOffset; i < numItemsTotal; ++i) {
406         add (internalSetOffset, lastItems.getCat(), lastItems.getItem(), lastAverage);
407         lastItems = lastItems.getNextItemsForSet();
408       }
409     }
410     else if (numItemsTotal > 0) { //do standard average calculation
411
int currSet = setVector.size();
412       for (int j = 0; j < dataset.getNumCats(); ++j) {
413         for (int k = 0; k < dataset.getNumItems(); ++k) {
414           add (currSet, j, k, dataset.getAverage (-1, j, k));
415         }
416       }
417       needsUpdate = true;
418     }
419   }
420
421
422   /**
423    * Analyzes the (input) dataset and sets moving average trend data to this dataset.
424    * Moving averages are computed by taking some odd number of adjacent items, computing their
425    * average and doing that from left to right for each item. How many adjacent items are used in
426    * computing the moving average is specified in the scope parameter.
427    * Assumes this dataset already has the same number of cats and items, and that the set exists.
428    * @param set The set into this dataset to put the moving average.
429    * @param dataset The dataset to analyze.
430    * @param scope The number of data points to compute over.
431    */

432   public final void setMovingAverage (int set, Dataset dataset, int scope) {
433
434     //make sure there is enough data
435
int numItemsTotal = dataset.getNumSets() > 0 ? dataset.getNumCats() * dataset.getNumItems() : 0;
436
437     if (numItemsTotal >= 3) { //do moving average calculation
438

439       //make sure scope is valid
440
if (scope < 3) scope = 3;
441       else {
442         if (scope > numItemsTotal) scope = numItemsTotal;
443         if (scope % 2 == 0) scope--;
444       }
445
446       //begin moving average calculation
447
int internalSetOffset = set; //offset in case this object holds other sets of data
448
int itemOffset = (scope / 2); //location of first real moving average data
449
Vector JavaDoc itemGroup = new Vector JavaDoc (scope); //create enough data holders
450

451       //prepare for first real moving average data
452
ItemsForSet items = new ItemsForSet (dataset, 0, 0);
453       itemGroup.add (items);
454       for (int i = 0; i < scope - 1; ++i) {
455         items = items.getNextItemsForSet();
456         itemGroup.add (items);
457       }
458
459       //get the first moving average data (guaranteed)
460
ItemsForSet firstItems = (ItemsForSet)itemGroup.get (0); //hold first item for later
461
items = (ItemsForSet)itemGroup.get (itemOffset);
462       float firstAverage = getAverageOfItemsForSetGroup (itemGroup);
463       set (internalSetOffset, items.getCat(), items.getItem(), firstAverage);
464       itemGroup.remove (0);
465       itemGroup.add (((ItemsForSet)itemGroup.lastElement()).getNextItemsForSet()); //maybe null
466

467       //get the rest except for the last real moving average data
468
for (int i = itemOffset + 1; i < numItemsTotal - itemOffset - 1; ++i) {
469         items = (ItemsForSet)itemGroup.get (itemOffset);
470         set (internalSetOffset, items.getCat(), items.getItem(),
471           getAverageOfItemsForSetGroup (itemGroup));
472         itemGroup.remove (0);
473         itemGroup.add(((ItemsForSet)itemGroup.lastElement()).getNextItemsForSet());
474       }
475
476       //check if only one real moving average data
477
float lastAverage = firstAverage;
478       ItemsForSet lastItems = items.getNextItemsForSet(); //okay for 3,3
479
if (numItemsTotal > scope) {
480
481         //get the last real moving average data
482
items = (ItemsForSet)itemGroup.get (itemOffset);
483         lastAverage = getAverageOfItemsForSetGroup (itemGroup);
484         set (internalSetOffset, items.getCat(), items.getItem(), lastAverage);
485         lastItems = items.getNextItemsForSet();
486       }
487
488       //populate beginning with fake moving average data
489
for (int i = 0; i < itemOffset; ++i) {
490         set (internalSetOffset, firstItems.getCat(), firstItems.getItem(), firstAverage);
491         firstItems = firstItems.getNextItemsForSet();
492       }
493
494       //populate end with fake moving average data
495
for (int i = numItemsTotal - itemOffset; i < numItemsTotal; ++i) {
496         set (internalSetOffset, lastItems.getCat(), lastItems.getItem(), lastAverage);
497         lastItems = lastItems.getNextItemsForSet();
498       }
499     }
500     else if (numItemsTotal > 0) { //do standard average calculation
501
int currSet = setVector.size();
502       for (int j = 0; j < dataset.getNumCats(); ++j) {
503         for (int k = 0; k < dataset.getNumItems(); ++k) {
504           set (currSet, j, k, dataset.getAverage (-1, j, k));
505         }
506       }
507       needsUpdate = true;
508     }
509   }
510
511
512   /**
513    * Removes values from the dataset. Depending on the values of the paramters,
514    * eight different operations may result. The simplest is to remove a
515    * particular item from a particular set and a particular category. But one
516    * can also perform more complex operations. For example, one can remove
517    * every set of data. The key to modifying the behavior is passing in
518    * a negative one or -1 value for a parameter. A -1 value specifies that
519    * whatever is to be removed, will be removed for all such things
520    * (ie sets, cats, or items) corresponding to that parameter. So if one
521    * wanted to remove every set of data, one could pass -1 to set, to cat, and
522    * to item. This would be specify to remove all items, for all cats, for all
523    * sets. If one wanted to remove only a single item from a particular set and
524    * a particular category, then one would pass a non -1 value for each of the
525    * parameters. Below is a listing of the options and a short description.
526    * The letters "a", "b", "c" indicates a non -1 value.<br>
527    * set= -1, cat= -1, item= -1 Removes every set of data.<br>
528    * set= a, cat= -1, item= -1 Removes a particular set of data.<br>
529    * set= -1, cat= a, item= -1 Removes a particular category of data for every
530    * set.<br>
531    * set= a, cat= b, item= -1 Removes a particular category of data for a
532    * particular set.<br>
533    * set= -1, cat= -1, item= a Removes a particular item for every set and
534    * every category.<br>
535    * set= -1, cat= a, item= b Removes a particular item of a particular
536    * category in every set.<br>
537    * set= a, cat= -1, item= b Removes a particular item of a particular set in
538    * every category.<br>
539    * set= a, cat= b, item= c Removes a particular item of a particular category
540    * of a particular set.<br>
541    * @param set The set of data within which data is to be removed.
542    * @param cat The cat of data within which data is to be removed.
543    * @param item The item of data that is to be removed.
544    */

545    public final void remove (int set, int cat, int item) {
546
547     needsUpdate = true;
548
549     //remove all sets
550
if (set == -1 && cat == -1 && item == -1) {
551       constructor (0, 0, 0);
552       return;
553     }
554
555     int numSets = getNumSets();
556     int numCats = getNumCats();
557     int numItems = getNumItems();
558     if (set != -1 && set >= numSets) return;
559     if (cat != -1 && cat >= numCats) return;
560     if (item != -1 && item >= numItems) return;
561
562     //removes a particular set
563
if (set != -1 && cat == -1 && item == -1) {
564       setVector.remove (set);
565     }
566     //removes a cat for all sets
567
else if (set == -1 && cat != -1 && item == -1) {
568       for (int i = 0; i < numSets; ++i) {
569         ((Vector JavaDoc)setVector.get (i)).remove (cat);
570       }
571     }
572     //removes a cat for a particular set
573
else if (set != 1 && cat != 1 && item == -1) {
574      ((Vector JavaDoc)setVector.get (set)).remove (cat);
575     }
576     //removes an item for all sets/cats
577
else if (set == -1 && cat == -1 && item != 1) {
578       for (int i = 0; i < numSets; ++i) {
579         Vector JavaDoc catVector = (Vector JavaDoc)setVector.get (i);
580         for (int j = 0; j < numCats; ++i) {
581           ((Vector JavaDoc)catVector.get (j)).remove (item);
582         }
583       }
584     }
585     //removes an item for all sets and a particular cat
586
else if (set == -1 && cat != -1 && item != -1) {
587       for (int i = 0; i < numSets; ++i) {
588         ((Vector JavaDoc)((Vector JavaDoc)setVector.get (i)).get (cat)).remove (item);
589       }
590     }
591     //removes an item for all cats and a particular set
592
else if (set != -1 && cat == -1 && item != -1) {
593       for (int j = 0; j < numCats; ++j) {
594         ((Vector JavaDoc)((Vector JavaDoc)setVector.get (set)).get (j)).remove (item);
595       }
596     }
597     //removes an item for a particular set/cat
598
else if (set != -1 && cat != -1 && item != -1) {
599      ((Vector JavaDoc)((Vector JavaDoc)setVector.get (set)).get (cat)).remove (item);
600     }
601    }
602
603
604
605   /**
606    * Shifts all the data items one place, from the higher order to the lower
607    * order, replacing the highest order items with the specified items. This
608    * method is designed to be used with graph charts where the data is
609    * dynamically updated and graphed over time categories. For example, if you
610    * picture a normal line chart with say three sets of data, that charts the
611    * amount of memory being used by various programs on your computer and is
612    * updated every second. The number of lines would correspond to the number
613    * of programs being charted. The number of x axis labels would refer to the
614    * number of seconds of data is being charted (ex 10 seconds). Every second,
615    * we could call shiftLower and this would shift left all the old data in the
616    * chart, and shift in to the right of the chart, some new data. There would
617    * have to be a new data value for each line in the chart. The the number of
618    * lines corresponds to the number of programs, and the number of programs,
619    * corresponds to the number of legend labels, etc, the number of data values
620    * shifted in must be equal to the number of sets in the dataset.
621    * @param values An array of values of length getNumSets() to shift in.
622    */

623   public final void doShiftLower (float[] values) {
624     needsUpdate = true;
625     for (int i = 0; i < setVector.size() && i < values.length; ++i) {
626       Vector JavaDoc catVector = (Vector JavaDoc)setVector.get (i);
627       for (int j = 0; j < catVector.size() - 1; ++j) {
628         Vector JavaDoc itemVector = (Vector JavaDoc)catVector.get (j);
629         itemVector.remove (0);
630         Vector JavaDoc itemVectorNext = (Vector JavaDoc)catVector.get (j + 1);
631         itemVector.add (itemVectorNext.get (0));
632       }
633       Vector JavaDoc itemVector = (Vector JavaDoc)catVector.get (catVector.size() - 1);
634       itemVector.remove (0);
635       itemVector.add (new Float JavaDoc (values[i]));
636     }
637   }
638
639
640   /**
641    * Converts the dataset for use in "stacked" charts. This is a convenience
642    * method. Stacked charts are those where each set of data is to be stacked
643    * on top of the previous set. So if you have multiple sets of data and you
644    * want the graph components corresponding to each set to be stacked on top
645    * of the previous set but you don't want to have to adjust your data
646    * yourself to get this ***affect*** then use this method. Multiple calls
647    * to this method will change your dataset each time. You will only want to call it once. Unless
648    * you repopulate your whole dataset with virgin (i.e. never before stacked) values again.
649    */

650   public final void doConvertToStacked() {
651
652     needsUpdate = true;
653     for (int j = 0; j < getNumCats(); ++j) {
654       for (int k = 0; k < getNumItems(); ++k) {
655         float posSum = 0f;
656         float negSum = 0f;
657         for (int i = 0; i < getNumSets(); ++i) {
658           float item = get (i, j, k);
659           if (item >= 0f) {
660             posSum = posSum + get (i, j, k);
661             set (i, j, k, posSum);
662           }
663           else {
664             negSum = negSum + get (i, j, k);
665             set (i, j, k, negSum);
666           }
667         }
668       }
669     }
670   }
671
672
673   /**
674    * Gets a float[][] representation of this dataset for use by GraphChartArea.
675    * @return float[][] A representation of this dataset.
676    */

677   final float[][] getOldGraphStruct() {
678
679     float[][] dataset;
680     if (setVector.size() == 0) dataset = new float[0][0];
681     else {
682       dataset = new float
683         [setVector.size()]
684         [((Vector JavaDoc)setVector.get(0)).size() *
685         ((Vector JavaDoc)((Vector JavaDoc)setVector.get(0)).get(0)).size()];
686       for (int i = 0; i < setVector.size(); ++i) {
687         Vector JavaDoc catVector = (Vector JavaDoc)setVector.get (i);
688         for (int j = 0; j < catVector.size(); ++j) {
689           Vector JavaDoc itemVector = (Vector JavaDoc)catVector.get (j);
690           for (int k = 0; k < itemVector.size(); ++k) {
691             dataset[i][j*itemVector.size() + k] =
692               ((Float JavaDoc)itemVector.get (k)).floatValue();
693           }
694         }
695       }
696     }
697     return dataset;
698   }
699
700
701   /**
702    * Gets a float[] representation of this dataset for use by PieChartArea.
703    * @return float[] A representation of this dataset.
704    */

705   final float[] getOldPieStruct() {
706
707     float[] dataset = new float[setVector.size()];
708     for (int i = 0; i < setVector.size(); ++i) {
709       float sum = 0;
710       Vector JavaDoc catVector = (Vector JavaDoc)setVector.get(i);
711       for (int j = 0; j < catVector.size(); ++j) {
712         Vector JavaDoc itemVector = (Vector JavaDoc)catVector.get(j);
713         for (int k = 0; k < itemVector.size(); ++k) {
714           sum += ((Float JavaDoc)itemVector.get(k)).floatValue();
715         }
716       }
717       dataset[i] = sum;
718     }
719     return dataset;
720   }
721
722
723   /**
724    * Gets whether this object needs to be updated with new properties.
725    * @param chart2D The object that may need to be updated.
726    * @return If true then needs update.
727    */

728   final boolean getChart2DNeedsUpdate (Chart2D chart2D) {
729     if (needsUpdate) return true;
730     int index = -1;
731     if ((index = chart2DVector.indexOf (chart2D)) != -1) {
732       return ((Boolean JavaDoc)needsUpdateVector.get (index)).booleanValue();
733     }
734     return false;
735   }
736
737
738   /**
739    * Adds a Chart2D to the set of objects using these properties.
740    * @param chart2D The object to add.
741    */

742   final void addChart2D (Chart2D chart2D) {
743
744     if (!chart2DVector.contains (chart2D)) {
745       chart2DVector.add (chart2D);
746       needsUpdateVector.add (new Boolean JavaDoc (true));
747     }
748   }
749
750
751   /**
752    * Removes a Chart2D from the set of objects using these properties.
753    * @param chart2D The object to remove.
754    */

755   final void removeChart2D (Chart2D chart2D) {
756
757     int index = -1;
758     if ((index = chart2DVector.indexOf (chart2D)) != -1) {
759       chart2DVector.remove (index);
760       needsUpdateVector.remove (index);
761     }
762   }
763
764
765   /**
766    * Validates the properties of this object.
767    * If debug is true then prints a messages indicating whether each property is valid.
768    * Returns true if all the properties were valid and false otherwise.
769    * @param debug If true then will print status messages.
770    * @return If true then valid.
771    */

772   final boolean validate (boolean debug) {
773
774     if (debug) System.out.println ("Validating Dataset");
775
776     boolean valid = true;
777
778     int numSets = setVector.size();
779     int numCats = 0;
780     Vector JavaDoc catVector = null;
781     if (numSets > 0) {
782       catVector = (Vector JavaDoc)setVector.get (0);
783       numCats = catVector.size();
784     }
785     int numItems = 0;
786     Vector JavaDoc itemVector = null;
787     if (numCats > 0) {
788       itemVector = (Vector JavaDoc)catVector.get (0);
789       numItems = itemVector.size();
790     }
791
792     for (int i = 0; i < numSets && valid; ++i) {
793       catVector = (Vector JavaDoc)setVector.get (i);
794       if (numCats != catVector.size()) {
795         valid = false;
796         break;
797       }
798       for (int j = 0; j < catVector.size() && valid; ++j) {
799         itemVector = (Vector JavaDoc)catVector.get (j);
800         if (numItems != itemVector.size()) {
801           valid = false;
802           break;
803         }
804       }
805     }
806
807     if (debug && !valid) System.out.println ("Problem with Dataset");
808
809     if (debug) {
810       if (valid) System.out.println ("Dataset was valid");
811       else System.out.println ("Dataset was invalid");
812     }
813
814     return valid;
815   }
816
817
818   /**
819    * Updates the properties of this Chart2D.
820    * @param chart2D The object to update.
821    */

822   final void updateChart2D (Chart2D chart2D) {
823
824     if (getChart2DNeedsUpdate (chart2D)) {
825
826       update();
827
828       int index = -1;
829       if ((index = chart2DVector.indexOf (chart2D)) != -1) {
830         needsUpdateVector.set (index, new Boolean JavaDoc (false));
831       }
832     }
833   }
834
835
836   private void constructor (int sets, int cats, int items) {
837
838     needsUpdate = true;
839     setVector = new Vector JavaDoc (sets, 10);
840     for (int i = 0; i < sets; ++i) {
841       Vector JavaDoc catVector = new Vector JavaDoc (cats, 10);
842       setVector.add (i, catVector);
843       for (int j = 0; j < cats; ++j) {
844         Vector JavaDoc itemVector = new Vector JavaDoc (items, 10);
845         catVector.add (j, itemVector);
846         for (int k = 0; k < items; ++k) {
847           itemVector.add (k, new Float JavaDoc (0f));
848         }
849       }
850     }
851   }
852
853
854   private void update() {
855
856     if (needsUpdate) {
857
858       for (int i = 0; i < needsUpdateVector.size(); ++i) {
859         needsUpdateVector.set (i, new Boolean JavaDoc (true));
860       }
861       needsUpdate = false;
862
863       greatest = -9999999999999999f;
864       least = 9999999999999999f;
865       for (int i = 0; i < setVector.size(); ++i) {
866         Vector JavaDoc catVector = (Vector JavaDoc)setVector.get (i);
867         for (int j = 0; j < catVector.size(); ++j) {
868           Vector JavaDoc itemVector = (Vector JavaDoc)catVector.get (j);
869           for (int k = 0; k < itemVector.size(); ++k) {
870             float value = ((Float JavaDoc)itemVector.get (k)).floatValue();
871             greatest = value > greatest ? value : greatest;
872             least = value < least ? value : least;
873       } } }
874       if (greatest < least) greatest = least = 0;
875     }
876   }
877
878
879   private float getAverageOfItemsForSetGroup (Vector JavaDoc group) {
880
881     float sum = 0f;
882     for (int i = 0; i < group.size(); ++i) {
883       sum += ((ItemsForSet)group.get(i)).getSum();
884     }
885     return sum / group.size();
886   }
887
888
889   private class ItemsForSet {
890
891     private int cat;
892     private int item;
893     private Dataset dataset;
894
895     ItemsForSet (Dataset dataset, int cat, int item) {
896
897       this.cat = cat;
898       this.item = item;
899       this.dataset = dataset;
900     }
901
902     private int getCat() {
903       return cat;
904     }
905
906     private int getItem() {
907       return item;
908     }
909
910     private float getSum() {
911       float sum = 0;
912       int numSets = dataset.getNumSets();
913       for (int i = 0; i < numSets; ++i) {
914         sum += dataset.get (i, cat, item);
915       }
916       return sum;
917     }
918
919     private ItemsForSet getNextItemsForSet() {
920       int nextCat = cat;
921       int nextItem = item;
922       if (item >= (dataset.getNumItems() - 1)) {
923         nextCat++;
924         nextItem = 0;
925       }
926       else {
927         nextItem++;
928       }
929       if (nextCat >= dataset.getNumCats()) return null;
930       else return new ItemsForSet (dataset, nextCat, nextItem);
931     }
932   }
933 }
Popular Tags