90833c9c731d14a72cf4fa6a00789861b3d28fda
[jalview.git] / src / jalview / schemes / ResidueColourScheme.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
3  * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle
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  */
18 package jalview.schemes;
19
20 import jalview.analysis.AAFrequency;
21 import jalview.analysis.Conservation;
22 import jalview.datamodel.AnnotatedCollectionI;
23 import jalview.datamodel.SequenceI;
24
25 import java.awt.Color;
26 import java.util.Hashtable;
27
28 /**
29  * DOCUMENT ME!
30  * 
31  * @author $author$
32  * @version $Revision$
33  */
34 public class ResidueColourScheme implements ColourSchemeI
35 {
36
37   boolean conservationColouring = false;
38
39   Color[] colors = null;
40
41   int threshold = 0;
42
43   /* Set when threshold colouring to either pid_gaps or pid_nogaps */
44   protected String ignoreGaps = AAFrequency.PID_GAPS;
45
46   /** Consenus as a hashtable array */
47   Hashtable[] consensus;
48
49   /** Conservation string as a char array */
50   char[] conservation;
51
52   int conservationLength = 0;
53
54   /** DOCUMENT ME!! */
55   int inc = 30;
56
57   /**
58    * Creates a new ResidueColourScheme object.
59    * 
60    * @param colors
61    *          DOCUMENT ME!
62    * @param threshold
63    *          DOCUMENT ME!
64    */
65   public ResidueColourScheme(Color[] colours, int threshold)
66   {
67     this.colors = colours;
68     this.threshold = threshold;
69   }
70
71   /**
72    * Creates a new ResidueColourScheme object.
73    */
74   public ResidueColourScheme()
75   {
76   }
77
78   /**
79    * Find a colour without an index in a sequence
80    */
81   public Color findColour(char c)
82   {
83     return colors == null ? Color.white
84             : colors[ResidueProperties.aaIndex[c]];
85   }
86
87   @Override
88   public Color findColour(char c, int j, SequenceI seq)
89   {
90     Color currentColour;
91
92     if ((threshold == 0) || aboveThreshold(c, j))
93     {
94       currentColour = colors[ResidueProperties.aaIndex[c]];
95     }
96     else
97     {
98       currentColour = Color.white;
99     }
100
101     if (conservationColouring)
102     {
103       currentColour = applyConservation(currentColour, j);
104     }
105
106     return currentColour;
107   }
108   @Override public void alignmentChanged(AnnotatedCollectionI alignment) {};
109
110   /**
111    * Get the percentage threshold for this colour scheme
112    * 
113    * @return Returns the percentage threshold
114    */
115   public int getThreshold()
116   {
117     return threshold;
118   }
119
120   /**
121    * DOCUMENT ME!
122    * 
123    * @param ct
124    *          DOCUMENT ME!
125    */
126   public void setThreshold(int ct, boolean ignoreGaps)
127   {
128     threshold = ct;
129     if (ignoreGaps)
130     {
131       this.ignoreGaps = AAFrequency.PID_NOGAPS;
132     }
133     else
134     {
135       this.ignoreGaps = AAFrequency.PID_GAPS;
136     }
137   }
138
139   /**
140    * DOCUMENT ME!
141    * 
142    * @param s
143    *          DOCUMENT ME!
144    * @param j
145    *          DOCUMENT ME!
146    * 
147    * @return DOCUMENT ME!
148    */
149   public boolean aboveThreshold(char c, int j)
150   {
151     if ('a' <= c && c <= 'z')
152     {
153       // TO UPPERCASE !!!
154       // Faster than toUpperCase
155       c -= ('a' - 'A');
156     }
157
158     if (consensus == null || consensus.length < j || consensus[j] == null)
159     {
160       return false;
161     }
162
163     if ((((Integer) consensus[j].get(AAFrequency.MAXCOUNT)).intValue() != -1)
164             && consensus[j].contains(String.valueOf(c)))
165     {
166       if (((Float) consensus[j].get(ignoreGaps)).floatValue() >= threshold)
167       {
168         return true;
169       }
170     }
171
172     return false;
173   }
174
175   public boolean conservationApplied()
176   {
177     return conservationColouring;
178   }
179
180   public void setConservationInc(int i)
181   {
182     inc = i;
183   }
184
185   public int getConservationInc()
186   {
187     return inc;
188   }
189
190   /**
191    * DOCUMENT ME!
192    * 
193    * @param consensus
194    *          DOCUMENT ME!
195    */
196   public void setConsensus(Hashtable[] consensus)
197   {
198     if (consensus == null)
199     {
200       return;
201     }
202
203     this.consensus = consensus;
204   }
205
206   public void setConservation(Conservation cons)
207   {
208     if (cons == null)
209     {
210       conservationColouring = false;
211       conservation = null;
212     }
213     else
214     {
215       conservationColouring = true;
216       int i, iSize = cons.getConsSequence().getLength();
217       conservation = new char[iSize];
218       for (i = 0; i < iSize; i++)
219       {
220         conservation[i] = cons.getConsSequence().getCharAt(i);
221       }
222       conservationLength = conservation.length;
223     }
224
225   }
226
227   /**
228    * DOCUMENT ME!
229    * 
230    * @param s
231    *          DOCUMENT ME!
232    * @param i
233    *          DOCUMENT ME!
234    * 
235    * @return DOCUMENT ME!
236    */
237
238   Color applyConservation(Color currentColour, int i)
239   {
240
241     if ((conservationLength > i) && (conservation[i] != '*')
242             && (conservation[i] != '+'))
243     {
244       if (jalview.util.Comparison.isGap(conservation[i]))
245       {
246         currentColour = Color.white;
247       }
248       else
249       {
250         float t = 11 - (conservation[i] - '0');
251         if (t == 0)
252         {
253           return Color.white;
254         }
255
256         int red = currentColour.getRed();
257         int green = currentColour.getGreen();
258         int blue = currentColour.getBlue();
259
260         int dr = 255 - red;
261         int dg = 255 - green;
262         int db = 255 - blue;
263
264         dr *= t / 10f;
265         dg *= t / 10f;
266         db *= t / 10f;
267
268         red += (inc / 20f) * dr;
269         green += (inc / 20f) * dg;
270         blue += (inc / 20f) * db;
271
272         if (red > 255 || green > 255 || blue > 255)
273         {
274           currentColour = Color.white;
275         }
276         else
277         {
278           currentColour = new Color(red, green, blue);
279         }
280       }
281     }
282     return currentColour;
283   }
284
285 }