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