KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > prefuse > action > assignment > DataColorAction


1 package prefuse.action.assignment;
2
3 import java.util.HashMap JavaDoc;
4 import java.util.Map JavaDoc;
5 import java.util.logging.Logger JavaDoc;
6
7 import prefuse.Constants;
8 import prefuse.data.tuple.TupleSet;
9 import prefuse.util.ColorLib;
10 import prefuse.util.ColorMap;
11 import prefuse.util.DataLib;
12 import prefuse.util.MathLib;
13 import prefuse.visual.VisualItem;
14
15 /**
16  * <p>
17  * Assignment Action that assigns color values for a group of items based upon
18  * a data field. The type of color encoding used is dependent upon the
19  * reported data type. Nominal (categorical) data is encoded using a different
20  * hue for each unique data value. Ordinal (ordered) and Numerical
21  * (quantitative) data is shown using a grayscale color ramp. In all cases,
22  * the default color palette used by this Action can be replaced with a
23  * client-specified palette provided to the DataColorAction constructor.
24  * </p>
25  *
26  * <p>
27  * The color spectra for numerical data is continuous by default, but can also
28  * be binned into a few discrete steps (see {@link #setBinCount(int)}).
29  * Quantitative data can also be colored on different numerical scales. The
30  * default scale is a linear scale (specified by
31  * {@link Constants#LINEAR_SCALE}), but logarithmic and square root scales can
32  * be used (specified by {@link Constants#LOG_SCALE} and
33  * {@link Constants#SQRT_SCALE} respectively. Finally, the scale can be broken
34  * into quantiles, reflecting the statistical distribution of the values rather
35  * than just the total data value range, using the
36  * {@link Constants#QUANTILE_SCALE} value. For the quantile scale to work, you
37  * also need to specify the number of bins to use (see
38  * {@link #setBinCount(int)}). This value will determine the number of
39  * quantiles that the data should be divided into.
40  * </p>
41  *
42  * </p>
43  *
44  * @author <a HREF="http://jheer.org">jeffrey heer</a>
45  */

46 public class DataColorAction extends ColorAction {
47
48     private String JavaDoc m_dataField;
49     private int m_type;
50     private int m_scale = Constants.LINEAR_SCALE;
51     private int m_tempScale;
52     
53     private double[] m_dist;
54     private int m_bins = Constants.CONTINUOUS;
55     private Map JavaDoc m_omap;
56     private Object JavaDoc[] m_olist;
57     private ColorMap m_cmap = new ColorMap(null,0,1);
58     private int[] m_palette;
59     
60     
61     /**
62      * Create a new DataColorAction
63      * @param group the data group to process
64      * @param dataField the data field to base size assignments on
65      * @param dataType the data type to use for the data field. One of
66      * {@link prefuse.Constants#NOMINAL}, {@link prefuse.Constants#ORDINAL},
67      * or {@link prefuse.Constants#NUMERICAL}, for whether the data field
68      * represents categories, an ordered sequence, or numerical values.
69      * @param colorField the color field to assign
70      */

71     public DataColorAction(String JavaDoc group, String JavaDoc dataField,
72                              int dataType, String JavaDoc colorField)
73     {
74         super(group, colorField);
75         setDataType(dataType);
76         setDataField(dataField);
77     }
78     
79     /**
80      * Create a new DataColorAction
81      * @param group the data group to process
82      * @param dataField the data field to base size assignments on
83      * @param dataType the data type to use for the data field. One of
84      * {@link prefuse.Constants#NOMINAL}, {@link prefuse.Constants#ORDINAL},
85      * or {@link prefuse.Constants#NUMERICAL}, for whether the data field
86      * represents categories, an ordered sequence, or numerical values.
87      * @param colorField the color field to assign
88      * @param palette the color palette to use. See
89      * {@link prefuse.util.ColorLib} for color palette generators.
90      */

91     public DataColorAction(String JavaDoc group, String JavaDoc dataField,
92             int dataType, String JavaDoc colorField, int[] palette)
93     {
94         super(group, colorField);
95         setDataType(dataType);
96         setDataField(dataField);
97         m_palette = palette;
98     }
99     
100     // ------------------------------------------------------------------------
101

102     /**
103      * Returns the data field used to encode size values.
104      * @return the data field that is mapped to size values
105      */

106     public String JavaDoc getDataField() {
107         return m_dataField;
108     }
109     
110     /**
111      * Set the data field used to encode size values.
112      * @param field the data field to map to size values
113      */

114     public void setDataField(String JavaDoc field) {
115         m_dataField = field;
116     }
117     
118     /**
119      * Return the data type used by this action. This value is one of
120      * {@link prefuse.Constants#NOMINAL}, {@link prefuse.Constants#ORDINAL},
121      * or {@link prefuse.Constants#NUMERICAL}.
122      * @return the data type used by this action
123      */

124     public int getDataType() {
125         return m_type;
126     }
127     
128     /**
129      * Set the data type used by this action.
130      * @param type the data type used by this action, one of
131      * {@link prefuse.Constants#NOMINAL}, {@link prefuse.Constants#ORDINAL},
132      * or {@link prefuse.Constants#NUMERICAL}.
133      */

134     public void setDataType(int type) {
135         if ( type < 0 || type >= Constants.DATATYPE_COUNT )
136             throw new IllegalArgumentException JavaDoc(
137                     "Unrecognized data type: "+type);
138         m_type = type;
139     }
140     
141     /**
142      * Returns the scale type used for encoding color values from the data.
143      * This value is only used for {@link prefuse.Constants#NUMERICAL}
144      * data.
145      * @return the scale type. One of
146      * {@link prefuse.Constants#LINEAR_SCALE},
147      * {@link prefuse.Constants#LOG_SCALE},
148      * {@link prefuse.Constants#SQRT_SCALE},
149      * {@link prefuse.Constants#QUANTILE_SCALE}.
150      */

151     public int getScale() {
152         return m_scale;
153     }
154     
155     /**
156      * Set the scale (linear, square root, or log) to use for encoding color
157      * values from the data. This value is only used for
158      * {@link prefuse.Constants#NUMERICAL} data.
159      * @param scale the scale type to use. This value should be one of
160      * {@link prefuse.Constants#LINEAR_SCALE},
161      * {@link prefuse.Constants#SQRT_SCALE},
162      * {@link prefuse.Constants#LOG_SCALE},
163      * {@link prefuse.Constants#QUANTILE_SCALE}.
164      * If {@link prefuse.Constants#QUANTILE_SCALE} is used, the number of
165      * bins to use must also be specified to a value greater than zero using
166      * the {@link #setBinCount(int)} method.
167      */

168     public void setScale(int scale) {
169         if ( scale < 0 || scale >= Constants.SCALE_COUNT )
170             throw new IllegalArgumentException JavaDoc(
171                     "Unrecognized scale value: "+scale);
172         m_scale = scale;
173     }
174     
175     /**
176      * Returns the number of "bins" or discrete steps of color. This value
177      * is only used for numerical data.
178      * @return the number of bins.
179      */

180     public int getBinCount() {
181         return m_bins;
182     }
183
184     /**
185      * Sets the number of "bins" or or discrete steps of color. This value
186      * is only used for numerical data.
187      * @param count the number of bins to set. The value
188      * {@link Constants#CONTINUOUS} indicates not to use any binning. If the
189      * scale type set using the {@link #setScale(int)} method is
190      * {@link Constants#QUANTILE_SCALE}, the bin count <strong>must</strong>
191      * be greater than zero.
192      */

193     public void setBinCount(int count) {
194         if ( m_scale == Constants.QUANTILE_SCALE && count <= 0 ) {
195             throw new IllegalArgumentException JavaDoc(
196                 "The quantile scale can not be used without binning. " +
197                 "Use a bin value greater than zero.");
198         }
199         m_bins = count;
200     }
201     
202     /**
203      * This operation is not supported by the DataColorAction type.
204      * Calling this method will result in a thrown exception.
205      * @see prefuse.action.assignment.ColorAction#setDefaultColor(int)
206      * @throws UnsupportedOperationException
207      */

208     public void setDefaultColor(int color) {
209         throw new UnsupportedOperationException JavaDoc();
210     }
211     
212     /**
213      * Manually sets the ordered list of values to use for color assignment.
214      * Normally, this ordering is computed using the methods of the
215      * {@link prefuse.util.DataLib} class. This method allows you to set your
216      * own custom ordering. This ordering corresponds to the ordering of
217      * colors in this action's color palette. If the provided array of values
218      * is missing a value contained within the data, an exception will result
219      * during execution of this action.
220      * @param values the ordered list of values. If this array is missing a
221      * value contained within data processed by this action, an exception
222      * will be thrown when this action is run.
223      */

224     public void setOrdinalMap(Object JavaDoc[] values) {
225         m_olist = values;
226         m_omap = new HashMap JavaDoc();
227         for ( int i=0; i<values.length; ++i ) {
228             m_omap.put(values[i], new Integer JavaDoc(i));
229         }
230     }
231     
232     // ------------------------------------------------------------------------
233

234     /**
235      * Set up the state of this encoding Action.
236      * @see prefuse.action.EncoderAction#setup()
237      */

238     protected void setup() {
239         int size = 64;
240         
241         int[] palette = m_palette;
242         
243         // switch up scale if necessary
244
m_tempScale = m_scale;
245         if ( m_scale == Constants.QUANTILE_SCALE && m_bins <= 0 ) {
246             Logger.getLogger(getClass().getName()).warning(
247                     "Can't use quantile scale with no binning. " +
248                     "Defaulting to linear scale. Set the bin value " +
249                     "greater than zero to use a quantile scale.");
250             m_scale = Constants.LINEAR_SCALE;
251         }
252         
253         // compute distribution and color map
254
switch ( m_type ) {
255         case Constants.NOMINAL:
256         case Constants.ORDINAL:
257             m_dist = getDistribution();
258             size = m_omap.size();
259             palette = (m_palette!=null ? m_palette : createPalette(size));
260             m_cmap.setColorPalette(palette);
261             m_cmap.setMinValue(m_dist[0]);
262             m_cmap.setMaxValue(m_dist[1]);
263             return;
264         case Constants.NUMERICAL:
265             m_dist = getDistribution();
266             size = m_bins > 0 ? m_bins : size;
267             palette = (m_palette!=null ? m_palette : createPalette(size));
268             m_cmap.setColorPalette(palette);
269             m_cmap.setMinValue(0.0);
270             m_cmap.setMaxValue(1.0);
271             return;
272         }
273     }
274     
275     protected void finish() {
276         // reset scale in case it needed to be changed due to errors
277
m_scale = m_tempScale;
278     }
279     
280     /**
281      * Computes the distribution (either min/max or quantile values) used to
282      * help assign colors to data values.
283      */

284     protected double[] getDistribution() {
285         TupleSet ts = m_vis.getGroup(m_group);
286
287         if ( m_type == Constants.NUMERICAL ) {
288             m_omap = null;
289             if ( m_scale == Constants.QUANTILE_SCALE && m_bins > 0 ) {
290                 double[] values =
291                         DataLib.toDoubleArray(ts.tuples(), m_dataField);
292                 return MathLib.quantiles(m_bins, values);
293             } else {
294                 double[] dist = new double[2];
295                 dist[0] = DataLib.min(ts, m_dataField).getDouble(m_dataField);
296                 dist[1] = DataLib.max(ts, m_dataField).getDouble(m_dataField);
297                 return dist;
298             }
299         } else {
300             if ( m_olist == null )
301                 m_omap = DataLib.ordinalMap(ts, m_dataField);
302             return new double[] { 0, m_omap.size()-1 };
303         }
304     }
305     
306     /**
307      * Create a color palette of the requested type and size.
308      */

309     protected int[] createPalette(int size) {
310         switch ( m_type ) {
311         case Constants.NOMINAL:
312             return ColorLib.getCategoryPalette(size);
313         case Constants.NUMERICAL:
314         case Constants.ORDINAL:
315         default:
316             return ColorLib.getGrayscalePalette(size);
317         }
318     }
319     
320     /**
321      * @see prefuse.action.assignment.ColorAction#getColor(prefuse.visual.VisualItem)
322      */

323     public int getColor(VisualItem item) {
324         // check for any cascaded rules first
325
Object JavaDoc o = lookup(item);
326         if ( o != null ) {
327             if ( o instanceof ColorAction ) {
328                 return ((ColorAction)o).getColor(item);
329             } else if ( o instanceof Integer JavaDoc ) {
330                 return ((Integer JavaDoc)o).intValue();
331             } else {
332                 Logger.getLogger(this.getClass().getName())
333                     .warning("Unrecognized Object from predicate chain.");
334             }
335         }
336         
337         // otherwise perform data-driven assignment
338
switch ( m_type ) {
339         case Constants.NUMERICAL:
340             double v = item.getDouble(m_dataField);
341             double f = MathLib.interp(m_scale, v, m_dist);
342             return m_cmap.getColor(f);
343         default:
344             Integer JavaDoc idx = (Integer JavaDoc)m_omap.get(item.get(m_dataField));
345             return m_cmap.getColor(idx.doubleValue());
346         }
347     }
348     
349 } // end of class DataColorAction
350
Popular Tags