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