001: /*
002: JOpenChart Java Charting Library and Toolkit
003: Copyright (C) 2001 Sebastian Müller
004: http://jopenchart.sourceforge.net
005:
006: This library is free software; you can redistribute it and/or
007: modify it under the terms of the GNU Lesser General Public
008: License as published by the Free Software Foundation; either
009: version 2.1 of the License, or (at your option) any later version.
010:
011: This library is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public
017: License along with this library; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019:
020: DefaultChartDataModel.java
021: Created on 28. Juni 2001, 20:41
022: */
023:
024: package de.progra.charting.model;
025:
026: import de.progra.charting.CoordSystem;
027: import de.progra.charting.ChartUtilities;
028: import java.util.ArrayList;
029: import java.util.Arrays;
030: import java.util.TreeSet;
031: import java.util.Set;
032: import java.util.HashMap;
033:
034: /**
035: * Implements a default ChartModel. It uses a DataSet[] and the columns
036: * are numeric. It's purely read-only.
037: * @author mueller
038: * @version 1.0
039: */
040: public class DefaultChartDataModel extends AbstractChartDataModel {
041:
042: /** The sorted x-axis values used for calculating the constraints. */
043: protected TreeSet columnSet = new TreeSet();
044:
045: /** The DataSet list.*/
046: protected ArrayList data = new ArrayList();
047:
048: /** A HashMap containing the ordered data used for calculating the constraints. */
049: protected HashMap valuesbyaxis = new HashMap();
050:
051: /** The constraints for the first and second y-axes.*/
052: protected ChartDataModelConstraints constraints1, constraints2;
053:
054: /** Creates a new empty DefaultChartDataModel.
055: */
056: public DefaultChartDataModel() {
057: TreeSet set1 = new TreeSet();
058: valuesbyaxis.put(new Integer(CoordSystem.FIRST_YAXIS), set1);
059: TreeSet set2 = new TreeSet();
060: valuesbyaxis.put(new Integer(CoordSystem.SECOND_YAXIS), set2);
061: constraints1 = new DefaultChartDataModelConstraints(this ,
062: CoordSystem.FIRST_YAXIS);
063: constraints2 = new DefaultChartDataModelConstraints(this ,
064: CoordSystem.SECOND_YAXIS);
065: }
066:
067: /** Creates new DefaultChartDataModel with the default axis binding.
068: * @param data the array of values. The first index specifies the
069: * datasets, the last one is the value index.
070: * @param columns the array of x-axis values. The length of the
071: * datasets and the length of the column should be equal and the columns should
072: * be ordered.
073: * @param rows the array of DataSet titles. It has to have the same
074: * length as the number of DataSets.
075: */
076: public DefaultChartDataModel(Number[][] data, double[] columns,
077: String[] rows) {
078: this ();
079:
080: columnSet.addAll(Arrays.asList(ChartUtilities
081: .transformArray(columns)));
082:
083: TreeSet set = (TreeSet) valuesbyaxis.get(new Integer(
084: CoordSystem.FIRST_YAXIS));
085:
086: ChartUtilities.addDataToSet(set, data);
087: trimSet(set);
088:
089: for (int i = 0; i < data.length; i++) {
090: this .data.add(new DefaultDataSet(data[i], ChartUtilities
091: .transformArray(columns), CoordSystem.FIRST_YAXIS,
092: rows[i]));
093: }
094: }
095:
096: /** Creates new DefaultChartDataModel.
097: * @param data the array of values. The first index specifies the
098: * datasets, the last one is the value index.
099: * @param columns the array of x-axis values. The length of the
100: * datasets and the length of the column should be equal and
101: * the columns should be ordered.
102: * @param rows the array of DataSet titles. It has to have the same
103: * length as the number of DataSets.
104: */
105: public DefaultChartDataModel(int[][] data, double[] columns,
106: String[] rows) {
107: this ();
108:
109: Number[][] numdata = ChartUtilities.transformArray(data);
110:
111: columnSet.addAll(Arrays.asList(ChartUtilities
112: .transformArray(columns)));
113:
114: TreeSet set = (TreeSet) valuesbyaxis.get(new Integer(
115: CoordSystem.FIRST_YAXIS));
116:
117: ChartUtilities.addDataToSet(set, numdata);
118:
119: trimSet(set);
120:
121: for (int i = 0; i < data.length; i++) {
122: this .data.add(new DefaultDataSet(numdata[i], ChartUtilities
123: .transformArray(columns), CoordSystem.FIRST_YAXIS,
124: rows[i]));
125: }
126: }
127:
128: /** Creates new DefaultChartDataModel.
129: * @param data the array of values. The first index specifies the
130: * datasets, the last one is the value index.
131: * @param columns the array of x-axis values. The length of the
132: * datasets and the length of the column should be equal and
133: * the columns should be ordered.
134: * @param rows the array of DataSet titles. It has to have the same
135: * length as the number of DataSets.
136: */
137: public DefaultChartDataModel(double[][] data, double[] columns,
138: String[] rows) {
139: this ();
140:
141: Number[][] numdata = ChartUtilities.transformArray(data);
142:
143: columnSet.addAll(Arrays.asList(ChartUtilities
144: .transformArray(columns)));
145:
146: TreeSet set = (TreeSet) valuesbyaxis.get(new Integer(
147: CoordSystem.FIRST_YAXIS));
148:
149: ChartUtilities.addDataToSet(set, numdata);
150: trimSet(set);
151: for (int i = 0; i < data.length; i++) {
152: this .data.add(new DefaultDataSet(numdata[i], ChartUtilities
153: .transformArray(columns), CoordSystem.FIRST_YAXIS,
154: rows[i]));
155: }
156: }
157:
158: /** Creates a new DefaultChartDataModel using the
159: * given array of DataSets, effectively enabling the creation
160: * of DataModels with differently sized DataSets.
161: * @param ds the array of DataSets to be used.
162: */
163: public DefaultChartDataModel(DataSet[] ds) {
164: this ();
165:
166: TreeSet set;
167: for (int i = 0; i < ds.length; i++) {
168: data.add(ds[i]);
169: set = (TreeSet) valuesbyaxis.get(new Integer(ds[i]
170: .getYAxis()));
171: for (int j = 0; j < ds[i].getDataSetLength(); j++) {
172: columnSet.add(ds[i].getColumnValueAt(j));
173: set.add(ds[i].getValueAt(j));
174:
175: trimSet(set);
176: }
177: }
178: }
179:
180: /** Returns the length of a certain dataset.
181: * @param set the DataSet
182: * @return the length of the DataSet
183: */
184: public int getDataSetLength(int set) {
185: return ((DataSet) data.get(set)).getDataSetLength();
186: }
187:
188: /** Returns the total amount of datasets.
189: * @return the amount of DataSets
190: */
191: public int getDataSetNumber() {
192: return data.size();
193: }
194:
195: /** Returns the title of the DataSet. This is the number of
196: * the DataSet per default.
197: * @param set the DataSet index
198: * @return the String title
199: */
200: public String getDataSetName(int set) {
201: return ((DataSet) data.get(set)).getTitle();
202: }
203:
204: /** Returns the axis binding for a DataSet
205: * @param set the DataSet index
206: * @return an axis binding constant
207: */
208: public int getAxisBinding(int set) {
209: return ((DataSet) data.get(set)).getYAxis();
210: }
211:
212: /** Returns true if the columns are numeric.
213: * @return <CODE>true</CODE>
214: */
215: public boolean isColumnNumeric() {
216: return true;
217: }
218:
219: /** Returns the class of the column values.
220: * @return <CODE>Double.class</CODE>
221: */
222: public Class getColumnClass() {
223: return Double.class;
224: }
225:
226: /** Returns the Value in a specific dataset at a certain index. *
227: * @param set the DataSet index
228: * @param index the value index
229: * @return the Number value at the specified position
230: */
231: public Number getValueAt(int set, int index) {
232: return (Number) ((DataSet) data.get(set)).getValueAt(index);
233: }
234:
235: /** Use getColumnValue(int set, int col) instead, because DefaultChartDataModel
236: * can contain DataSets with different lengths and column values.
237: * @return null
238: */
239: public Object getColumnValueAt(int col) {
240: return null;
241: }
242:
243: /** Returns a specific column value.
244: * @return the column value or <code>null</code> if the column doesn't exist.
245: * @param col the column index
246: * @param set the DataSet of which the column value is desired
247: */
248: public Object getColumnValueAt(int set, int col) {
249: // PENDING: Why do we create a new Double here?
250: if (col < getDataSetLength(set))
251: return new Double(((Number) ((DataSet) data.get(set))
252: .getColumnValueAt(col)).doubleValue());
253: else
254: return null;
255: }
256:
257: /** Returns a ChartDataModelConstraints Object for a given axis.
258: * This way, there are different constraints for the first and for
259: * the second y-axis. If the model is empty, the maximum values are 1 and
260: * the minimum values are 0, thus enabling proper rendering.
261: * @param axis the axis constant.
262: * @return a ChartDataModelConstraints object with the constraints
263: * for the specified y-axis.
264: */
265: public ChartDataModelConstraints getChartDataModelConstraints(
266: final int axis) {
267: if (axis == CoordSystem.FIRST_YAXIS)
268: return constraints1;
269: else
270: return constraints2;
271: }
272:
273: /** Sets the ChartDataModelConstraints object for the given
274: * axis binding.
275: * @param axis the Axis constant
276: * @param constraints the ChartDataModelConstraints object
277: * @return a ChartDataModelConstraints object.
278: */
279: public void setChartDataModelConstraints(int axis,
280: ChartDataModelConstraints constraints) {
281: if (axis == CoordSystem.FIRST_YAXIS)
282: constraints1 = constraints;
283: else
284: constraints2 = constraints;
285: }
286:
287: /** Removes infinite and NaN values from a TreeSet. Called with the TreeSet
288: * containing all values. If asymptotic functions are plotted, infinite values
289: * are the max / min values, resulting in bogus point-to-pixel rations. Therefore,
290: * these values are omitted from these calculations.
291: */
292: protected void trimSet(TreeSet s) {
293: while (((Number) s.first()).doubleValue() == Double.NEGATIVE_INFINITY) {
294: s.remove(s.first());
295: }
296: double last = ((Number) s.last()).doubleValue();
297:
298: while (last == Double.POSITIVE_INFINITY || last != last) {
299: s.remove(s.last());
300: last = ((Number) s.last()).doubleValue();
301: }
302: }
303:
304: /** Returns an ordered set of all data values for the specified axis.
305: * This is called by the ChartDataModelConstraints classes.
306: */
307: protected TreeSet getOrderedValues(int axis) {
308: return (TreeSet) valuesbyaxis.get(new Integer(axis));
309: }
310:
311: /** Returns the first ordered column value for use by the ChartDataModelConstraints. */
312: protected double getFirstColumnValue() {
313: return ((Number) columnSet.first()).doubleValue();
314: }
315:
316: /** Returns the last ordered column value for use by the ChartDataModelConstraints. */
317: protected double getLastColumnValue() {
318: return ((Number) columnSet.last()).doubleValue();
319: }
320: }
|