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