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