JAL-2055 removed stub first version of colours
[jalview.git] / src / jalview / schemes / GraduatedColor.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.schemes;
22
23 import jalview.api.FeatureColourI;
24 import jalview.datamodel.SequenceFeature;
25
26 import java.awt.Color;
27
28 /**
29  * Value and/or thresholded colour scale used for colouring by annotation and
30  * feature score
31  * 
32  * @author JimP
33  * 
34  */
35 public class GraduatedColor
36 {
37   int thresholdState = AnnotationColourGradient.NO_THRESHOLD; // or
38                                                               // ABOVE_THRESHOLD
39                                                               // or
40                                                               // BELOW_THRESHOLD
41
42   float lr, lg, lb, dr, dg, db;
43
44   /**
45    * linear scaling parameters, base, minimum colour threshold, range of linear
46    * scale from lower to upper
47    */
48   float base, range, thrsh;
49
50   /**
51    * when true, colour from u to u-d rather than u to u+d
52    */
53   boolean tolow = false;
54
55   /**
56    * when false, min/max range has been manually set so should not be
57    * dynamically adjusted.
58    */
59   boolean autoScale = true;
60
61   /**
62    * construct a graduatedColor object from simple parameters
63    * 
64    * @param low
65    * @param high
66    * @param min
67    * @param max
68    *          color low->high from min->max
69    */
70   public GraduatedColor(Color low, Color high, float min, float max)
71   {
72     thrsh = Float.NaN;
73     tolow = min >= max;
74     lr = low.getRed() / 255f;
75     lg = low.getGreen() / 255f;
76     lb = low.getBlue() / 255f;
77     dr = (high.getRed() / 255f) - lr;
78     dg = (high.getGreen() / 255f) - lg;
79     db = (high.getBlue() / 255f) - lb;
80     if (tolow)
81     {
82       base = max;
83       range = min - max;
84     }
85     else
86     {
87       base = min;
88       range = max - min;
89     }
90   }
91
92   public GraduatedColor(GraduatedColor oldcs)
93   {
94     lr = oldcs.lr;
95     lg = oldcs.lg;
96     lb = oldcs.lb;
97     dr = oldcs.dr;
98     dg = oldcs.dg;
99     db = oldcs.db;
100     base = oldcs.base;
101     range = oldcs.range;
102     tolow = oldcs.tolow;
103     thresholdState = oldcs.thresholdState;
104     thrsh = oldcs.thrsh;
105     autoScale = oldcs.autoScale;
106     colourByLabel = oldcs.colourByLabel;
107     colourAlternately = oldcs.colourAlternately;
108   }
109
110   /**
111    * make a new gradient from an old one with a different scale range
112    * 
113    * @param oldcs
114    * @param min
115    * @param max
116    */
117   public GraduatedColor(GraduatedColor oldcs, float min, float max)
118   {
119     this(oldcs);
120     updateBounds(min, max);
121   }
122
123   public GraduatedColor(FeatureColourI col)
124   {
125     setColourByLabel(col.isColourByLabel());
126   }
127
128   public Color getMinColor()
129   {
130     return new Color(lr, lg, lb);
131   }
132
133   public Color getMaxColor()
134   {
135     return new Color(lr + dr, lg + dg, lb + db);
136   }
137
138   /**
139    * 
140    * @return true if original min/max scale was from high to low
141    */
142   public boolean getTolow()
143   {
144     return tolow;
145   }
146
147   public void setTolow(boolean tolower)
148   {
149     tolow = tolower;
150   }
151
152   public boolean isColored(SequenceFeature feature)
153   {
154     float val = feature.getScore();
155     if (Float.isNaN(val))
156     {
157       return true;
158     }
159     if (this.thresholdState == AnnotationColourGradient.NO_THRESHOLD)
160     {
161       return true;
162     }
163     if (Float.isNaN(this.thrsh))
164     {
165       return true;
166     }
167     boolean rtn = thresholdState == AnnotationColourGradient.ABOVE_THRESHOLD;
168     if (val <= thrsh)
169     {
170       return !rtn; // ? !tolow : tolow;
171     }
172     else
173     {
174       return rtn; // ? tolow : !tolow;
175     }
176   }
177
178   /**
179    * default implementor of a getColourFromString method. TODO: abstract an
180    * interface enabling pluggable colour from string
181    */
182   private UserColourScheme ucs = null;
183
184   private boolean colourByLabel = false;
185
186   private boolean colourAlternately = false;
187
188   /**
189    * 
190    * @return true if colourByLabel style is set
191    */
192   public boolean isColourByLabel()
193   {
194     return colourByLabel;
195   }
196
197   /**
198    * @param colourByLabel
199    *          the colourByLabel to set
200    */
201   public void setColourByLabel(boolean colourByLabel)
202   {
203     this.colourByLabel = colourByLabel;
204   }
205
206   public Color findColor(SequenceFeature feature)
207   {
208     if (colourByLabel)
209     {
210       // TODO: allow user defined feature label colourschemes. Colour space is
211       // {type,regex,%anytype%}x{description string, regex, keyword}
212       if (ucs == null)
213       {
214         ucs = new UserColourScheme();
215       }
216       return ucs.createColourFromName(feature.getDescription());
217     }
218     if (colourAlternately)
219     {
220       int minOrMax = feature.getFeatureNumber() % 2;
221       return minOrMax == 0 ? new Color(lr, lg, lb) : new Color(lr + dr, lg
222               + dg, lb + db);
223     }
224     if (range == 0.0)
225     {
226       return getMaxColor();
227     }
228     float scr = feature.getScore();
229     if (Float.isNaN(scr))
230     {
231       return getMinColor();
232     }
233     float scl = (scr - base) / range;
234     if (tolow)
235     {
236       scl = -scl;
237     }
238     if (scl < 0f)
239     {
240       scl = 0f;
241     }
242     if (scl > 1f)
243     {
244       scl = 1f;
245     }
246     return new Color(lr + scl * dr, lg + scl * dg, lb + scl * db);
247   }
248
249   public void setThresh(float value)
250   {
251     thrsh = value;
252   }
253
254   public float getThresh()
255   {
256     return thrsh;
257   }
258
259   public void setThreshType(int aboveThreshold)
260   {
261     thresholdState = aboveThreshold;
262   }
263
264   public int getThreshType()
265   {
266     return thresholdState;
267   }
268
269   public float getMax()
270   {
271     // regenerate the original values passed in to the constructor
272     return (tolow) ? base : (base + range);
273   }
274
275   public float getMin()
276   {
277     // regenerate the original value passed in to the constructor
278     return (tolow) ? (base + range) : base;
279   }
280
281   public boolean isAutoScale()
282   {
283     return autoScale;
284   }
285
286   public void setAutoScaled(boolean autoscale)
287   {
288     autoScale = autoscale;
289   }
290
291   /**
292    * update the base and range appropriatly for the given minmax range
293    * 
294    * @param a
295    *          float[] {min,max} array containing minmax range for the associated
296    *          score values
297    */
298   public void updateBounds(float min, float max)
299   {
300     if (max < min)
301     {
302       base = max;
303       range = min - max;
304       tolow = true;
305     }
306     else
307     {
308       base = min;
309       range = max - min;
310       tolow = false;
311     }
312   }
313
314   public boolean isColourAlternately()
315   {
316     return colourAlternately;
317   }
318
319   public void setColourAlternately(boolean colourAlternately)
320   {
321     this.colourAlternately = colourAlternately;
322   }
323 }