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