Merge branch 'develop' into releases/Release_2_9_1_Branch
[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   }
108
109   /**
110    * make a new gradient from an old one with a different scale range
111    * 
112    * @param oldcs
113    * @param min
114    * @param max
115    */
116   public GraduatedColor(GraduatedColor oldcs, float min, float max)
117   {
118     this(oldcs);
119     updateBounds(min, max);
120   }
121
122   public GraduatedColor(FeatureColourI col)
123   {
124     setColourByLabel(col.isColourByLabel());
125   }
126
127   public Color getMinColor()
128   {
129     return new Color(lr, lg, lb);
130   }
131
132   public Color getMaxColor()
133   {
134     return new Color(lr + dr, lg + dg, lb + db);
135   }
136
137   /**
138    * 
139    * @return true if original min/max scale was from high to low
140    */
141   public boolean getTolow()
142   {
143     return tolow;
144   }
145
146   public void setTolow(boolean tolower)
147   {
148     tolow = tolower;
149   }
150
151   public boolean isColored(SequenceFeature feature)
152   {
153     float val = feature.getScore();
154     if (Float.isNaN(val))
155     {
156       return true;
157     }
158     if (this.thresholdState == AnnotationColourGradient.NO_THRESHOLD)
159     {
160       return true;
161     }
162     if (Float.isNaN(this.thrsh))
163     {
164       return true;
165     }
166     boolean rtn = thresholdState == AnnotationColourGradient.ABOVE_THRESHOLD;
167     if (val <= thrsh)
168     {
169       return !rtn; // ? !tolow : tolow;
170     }
171     else
172     {
173       return rtn; // ? tolow : !tolow;
174     }
175   }
176
177   /**
178    * default implementor of a getColourFromString method. TODO: abstract an
179    * interface enabling pluggable colour from string
180    */
181   private UserColourScheme ucs = null;
182
183   private boolean colourByLabel = false;
184
185   /**
186    * 
187    * @return true if colourByLabel style is set
188    */
189   public boolean isColourByLabel()
190   {
191     return colourByLabel;
192   }
193
194   /**
195    * @param colourByLabel
196    *          the colourByLabel to set
197    */
198   public void setColourByLabel(boolean colourByLabel)
199   {
200     this.colourByLabel = colourByLabel;
201   }
202
203   public Color findColor(SequenceFeature feature)
204   {
205     if (colourByLabel)
206     {
207       // TODO: allow user defined feature label colourschemes. Colour space is
208       // {type,regex,%anytype%}x{description string, regex, keyword}
209       if (ucs == null)
210       {
211         ucs = new UserColourScheme();
212       }
213       return ucs.createColourFromName(feature.getDescription());
214     }
215     if (range == 0.0)
216     {
217       return getMaxColor();
218     }
219     float scr = feature.getScore();
220     if (Float.isNaN(scr))
221     {
222       return getMinColor();
223     }
224     float scl = (scr - base) / range;
225     if (tolow)
226     {
227       scl = -scl;
228     }
229     if (scl < 0f)
230     {
231       scl = 0f;
232     }
233     if (scl > 1f)
234     {
235       scl = 1f;
236     }
237     return new Color(lr + scl * dr, lg + scl * dg, lb + scl * db);
238   }
239
240   public void setThresh(float value)
241   {
242     thrsh = value;
243   }
244
245   public float getThresh()
246   {
247     return thrsh;
248   }
249
250   public void setThreshType(int aboveThreshold)
251   {
252     thresholdState = aboveThreshold;
253   }
254
255   public int getThreshType()
256   {
257     return thresholdState;
258   }
259
260   public float getMax()
261   {
262     // regenerate the original values passed in to the constructor
263     return (tolow) ? base : (base + range);
264   }
265
266   public float getMin()
267   {
268     // regenerate the original value passed in to the constructor
269     return (tolow) ? (base + range) : base;
270   }
271
272   public boolean isAutoScale()
273   {
274     return autoScale;
275   }
276
277   public void setAutoScaled(boolean autoscale)
278   {
279     autoScale = autoscale;
280   }
281
282   /**
283    * update the base and range appropriatly for the given minmax range
284    * 
285    * @param a
286    *          float[] {min,max} array containing minmax range for the associated
287    *          score values
288    */
289   public void updateBounds(float min, float max)
290   {
291     if (max < min)
292     {
293       base = max;
294       range = min - max;
295       tolow = true;
296     }
297     else
298     {
299       base = min;
300       range = max - min;
301       tolow = false;
302     }
303   }
304 }