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