JAL-1503 update version in GPL header
[jalview.git] / src / jalview / schemes / ResidueColourScheme.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.1)
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.analysis.AAFrequency;
22 import jalview.analysis.Conservation;
23 import jalview.datamodel.AnnotatedCollectionI;
24 import jalview.datamodel.SequenceCollectionI;
25 import jalview.datamodel.SequenceI;
26
27 import java.awt.Color;
28 import java.util.Hashtable;
29 import java.util.Map;
30
31 /**
32  * DOCUMENT ME!
33  * 
34  * @author $author$
35  * @version $Revision$
36  */
37 public class ResidueColourScheme implements ColourSchemeI
38 {
39   final int[] symbolIndex;
40
41   boolean conservationColouring = false;
42
43   Color[] colors = null;
44
45   int threshold = 0;
46
47   /* Set when threshold colouring to either pid_gaps or pid_nogaps */
48   protected String ignoreGaps = AAFrequency.PID_GAPS;
49
50   /** Consenus as a hashtable array */
51   Hashtable[] consensus;
52
53   /** Conservation string as a char array */
54   char[] conservation;
55
56   int conservationLength = 0;
57
58   /** DOCUMENT ME!! */
59   int inc = 30;
60
61   /**
62    * Creates a new ResidueColourScheme object.
63    * 
64    * @param final int[] index table into colors (ResidueProperties.naIndex or
65    *        ResidueProperties.aaIndex)
66    * @param colors
67    *          colours for symbols in sequences
68    * @param threshold
69    *          threshold for conservation shading
70    */
71   public ResidueColourScheme(int[] aaOrnaIndex, Color[] colours,
72           int threshold)
73   {
74     symbolIndex = aaOrnaIndex;
75     this.colors = colours;
76     this.threshold = threshold;
77   }
78
79   /**
80    * Creates a new ResidueColourScheme object with a lookup table for indexing
81    * the colour map
82    */
83   public ResidueColourScheme(int[] aaOrNaIndex)
84   {
85     symbolIndex = aaOrNaIndex;
86   }
87
88   /**
89    * Creates a new ResidueColourScheme object - default constructor for
90    * non-sequence dependent colourschemes
91    */
92   public ResidueColourScheme()
93   {
94     symbolIndex = null;
95   }
96
97   /**
98    * Find a colour without an index in a sequence
99    */
100   public Color findColour(char c)
101   {
102     return colors == null ? Color.white : colors[symbolIndex[c]];
103   }
104
105   @Override
106   public Color findColour(char c, int j, SequenceI seq)
107   {
108     Color currentColour;
109
110     if (colors != null && symbolIndex != null && (threshold == 0)
111             || aboveThreshold(c, j))
112     {
113       currentColour = colors[symbolIndex[c]];
114     }
115     else
116     {
117       currentColour = Color.white;
118     }
119
120     if (conservationColouring)
121     {
122       currentColour = applyConservation(currentColour, j);
123     }
124
125     return currentColour;
126   }
127
128   /**
129    * Get the percentage threshold for this colour scheme
130    * 
131    * @return Returns the percentage threshold
132    */
133   public int getThreshold()
134   {
135     return threshold;
136   }
137
138   /**
139    * DOCUMENT ME!
140    * 
141    * @param ct
142    *          DOCUMENT ME!
143    */
144   public void setThreshold(int ct, boolean ignoreGaps)
145   {
146     threshold = ct;
147     if (ignoreGaps)
148     {
149       this.ignoreGaps = AAFrequency.PID_NOGAPS;
150     }
151     else
152     {
153       this.ignoreGaps = AAFrequency.PID_GAPS;
154     }
155   }
156
157   /**
158    * DOCUMENT ME!
159    * 
160    * @param s
161    *          DOCUMENT ME!
162    * @param j
163    *          DOCUMENT ME!
164    * 
165    * @return DOCUMENT ME!
166    */
167   public boolean aboveThreshold(char c, int j)
168   {
169     if ('a' <= c && c <= 'z')
170     {
171       // TO UPPERCASE !!!
172       // Faster than toUpperCase
173       c -= ('a' - 'A');
174     }
175
176     if (consensus == null || consensus.length < j || consensus[j] == null)
177     {
178       return false;
179     }
180
181     if ((((Integer) consensus[j].get(AAFrequency.MAXCOUNT)).intValue() != -1)
182             && consensus[j].contains(String.valueOf(c)))
183     {
184       if (((Float) consensus[j].get(ignoreGaps)).floatValue() >= threshold)
185       {
186         return true;
187       }
188     }
189
190     return false;
191   }
192
193   public boolean conservationApplied()
194   {
195     return conservationColouring;
196   }
197   @Override
198   public void setConservationApplied(boolean conservationApplied)
199   {
200     conservationColouring = conservationApplied;
201   }
202
203   public void setConservationInc(int i)
204   {
205     inc = i;
206   }
207
208   public int getConservationInc()
209   {
210     return inc;
211   }
212
213   /**
214    * DOCUMENT ME!
215    * 
216    * @param consensus
217    *          DOCUMENT ME!
218    */
219   public void setConsensus(Hashtable[] consensus)
220   {
221     if (consensus == null)
222     {
223       return;
224     }
225
226     this.consensus = consensus;
227   }
228
229   public void setConservation(Conservation cons)
230   {
231     if (cons == null)
232     {
233       conservationColouring = false;
234       conservation = null;
235     }
236     else
237     {
238       conservationColouring = true;
239       int i, iSize = cons.getConsSequence().getLength();
240       conservation = new char[iSize];
241       for (i = 0; i < iSize; i++)
242       {
243         conservation[i] = cons.getConsSequence().getCharAt(i);
244       }
245       conservationLength = conservation.length;
246     }
247
248   }
249
250   /**
251    * DOCUMENT ME!
252    * 
253    * @param s
254    *          DOCUMENT ME!
255    * @param i
256    *          DOCUMENT ME!
257    * 
258    * @return DOCUMENT ME!
259    */
260
261   Color applyConservation(Color currentColour, int i)
262   {
263
264     if ((conservationLength > i) && (conservation[i] != '*')
265             && (conservation[i] != '+'))
266     {
267       if (jalview.util.Comparison.isGap(conservation[i]))
268       {
269         currentColour = Color.white;
270       }
271       else
272       {
273         float t = 11 - (conservation[i] - '0');
274         if (t == 0)
275         {
276           return Color.white;
277         }
278
279         int red = currentColour.getRed();
280         int green = currentColour.getGreen();
281         int blue = currentColour.getBlue();
282
283         int dr = 255 - red;
284         int dg = 255 - green;
285         int db = 255 - blue;
286
287         dr *= t / 10f;
288         dg *= t / 10f;
289         db *= t / 10f;
290
291         red += (inc / 20f) * dr;
292         green += (inc / 20f) * dg;
293         blue += (inc / 20f) * db;
294
295         if (red > 255 || green > 255 || blue > 255)
296         {
297           currentColour = Color.white;
298         }
299         else
300         {
301           currentColour = new Color(red, green, blue);
302         }
303       }
304     }
305     return currentColour;
306   }
307
308   @Override
309   public void alignmentChanged(AnnotatedCollectionI alignment,
310           Map<SequenceI, SequenceCollectionI> hiddenReps)
311   {
312   }
313
314   @Override
315   public ColourSchemeI applyTo(AnnotatedCollectionI sg,
316           Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
317   {
318     try {
319       return getClass().newInstance();
320     }
321     catch (Exception q)
322     {
323       throw new Error("Serious implementation error: cannot duplicate colourscheme "+getClass().getName(), q);
324     }
325   }
326 }