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