jalview 2.5 release banner
[jalview.git] / src / jalview / analysis / AAFrequency.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.5)
3  * Copyright (C) 2010 J Procter, AM Waterhouse, 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.analysis;
19
20 import java.util.*;
21
22 import jalview.datamodel.*;
23
24 /**
25  * Takes in a vector or array of sequences and column start and column end and
26  * returns a new Hashtable[] of size maxSeqLength, if Hashtable not supplied.
27  * This class is used extensively in calculating alignment colourschemes that
28  * depend on the amount of conservation in each alignment column.
29  * 
30  * @author $author$
31  * @version $Revision$
32  */
33 public class AAFrequency
34 {
35   // No need to store 1000s of strings which are not
36   // visible to the user.
37   public static final String MAXCOUNT = "C";
38
39   public static final String MAXRESIDUE = "R";
40
41   public static final String PID_GAPS = "G";
42
43   public static final String PID_NOGAPS = "N";
44
45   public static final String PROFILE = "P";
46
47   public static final Hashtable[] calculate(Vector sequences, int start,
48           int end)
49   {
50     return calculate(sequences, start, end, false);
51   }
52
53   public static final Hashtable[] calculate(Vector sequences, int start,
54           int end, boolean profile)
55   {
56     SequenceI[] seqs = new SequenceI[sequences.size()];
57     int width = 0;
58     for (int i = 0; i < sequences.size(); i++)
59     {
60       seqs[i] = (SequenceI) sequences.elementAt(i);
61       if (seqs[i].getLength() > width)
62       {
63         width = seqs[i].getLength();
64       }
65     }
66
67     Hashtable[] reply = new Hashtable[width];
68
69     if (end >= width)
70     {
71       end = width;
72     }
73
74     calculate(seqs, start, end, reply, profile);
75
76     return reply;
77   }
78
79   public static final void calculate(SequenceI[] sequences, int start,
80           int end, Hashtable[] result)
81   {
82     calculate(sequences, start, end, result, false);
83   }
84
85   public static final void calculate(SequenceI[] sequences, int start,
86           int end, Hashtable[] result, boolean profile)
87   {
88     Hashtable residueHash;
89     int maxCount, nongap, i, j, v, jSize = sequences.length;
90     String maxResidue;
91     char c;
92     float percentage;
93
94     int[] values = new int[255];
95
96     char[] seq;
97
98     for (i = start; i < end; i++)
99     {
100       residueHash = new Hashtable();
101       maxCount = 0;
102       maxResidue = "";
103       nongap = 0;
104       values = new int[255];
105
106       for (j = 0; j < jSize; j++)
107       {
108         seq = sequences[j].getSequence();
109         if (seq.length > i)
110         {
111           c = seq[i];
112
113           if (c == '.' || c == ' ')
114           {
115             c = '-';
116           }
117
118           if (c == '-')
119           {
120             values['-']++;
121             continue;
122           }
123           else if ('a' <= c && c <= 'z')
124           {
125             c -= 32; // ('a' - 'A');
126           }
127
128           nongap++;
129           values[c]++;
130
131         }
132         else
133         {
134           values['-']++;
135         }
136       }
137
138       for (v = 'A'; v < 'Z'; v++)
139       {
140         if (values[v] < 2 || values[v] < maxCount)
141         {
142           continue;
143         }
144
145         if (values[v] > maxCount)
146         {
147           maxResidue = String.valueOf((char) v);
148         }
149         else if (values[v] == maxCount)
150         {
151           maxResidue += String.valueOf((char) v);
152         }
153         maxCount = values[v];
154       }
155
156       if (maxResidue.length() == 0)
157       {
158         maxResidue = "-";
159       }
160       if (profile)
161       {
162         residueHash.put(PROFILE, new int[][]
163         { values, new int[]
164         { jSize, nongap } });
165       }
166       residueHash.put(MAXCOUNT, new Integer(maxCount));
167       residueHash.put(MAXRESIDUE, maxResidue);
168
169       percentage = ((float) maxCount * 100) / (float) jSize;
170       residueHash.put(PID_GAPS, new Float(percentage));
171
172       percentage = ((float) maxCount * 100) / (float) nongap;
173       residueHash.put(PID_NOGAPS, new Float(percentage));
174       result[i] = residueHash;
175     }
176   }
177
178   /**
179    * Compute all or part of the annotation row from the given consensus
180    * hashtable
181    * 
182    * @param consensus
183    *          - pre-allocated annotation row
184    * @param hconsensus
185    * @param iStart
186    * @param width
187    * @param ignoreGapsInConsensusCalculation
188    * @param includeAllConsSymbols
189    */
190   public static void completeConsensus(AlignmentAnnotation consensus,
191           Hashtable[] hconsensus, int iStart, int width,
192           boolean ignoreGapsInConsensusCalculation,
193           boolean includeAllConsSymbols)
194   {
195     completeConsensus(consensus, hconsensus, iStart, width,
196             ignoreGapsInConsensusCalculation, includeAllConsSymbols, null); // new
197                                                                             // char[]
198     // { 'A', 'C', 'G', 'T', 'U' });
199   }
200
201   public static void completeConsensus(AlignmentAnnotation consensus,
202           Hashtable[] hconsensus, int iStart, int width,
203           boolean ignoreGapsInConsensusCalculation,
204           boolean includeAllConsSymbols, char[] alphabet)
205   {
206     float tval, value;
207     for (int i = iStart; i < width; i++)
208     {
209       value = 0;
210       if (ignoreGapsInConsensusCalculation)
211       {
212         value = ((Float) hconsensus[i].get(AAFrequency.PID_NOGAPS))
213                 .floatValue();
214       }
215       else
216       {
217         value = ((Float) hconsensus[i].get(AAFrequency.PID_GAPS))
218                 .floatValue();
219       }
220
221       String maxRes = hconsensus[i].get(AAFrequency.MAXRESIDUE).toString();
222       String mouseOver = hconsensus[i].get(AAFrequency.MAXRESIDUE) + " ";
223       if (maxRes.length() > 1)
224       {
225         mouseOver = "[" + maxRes + "] ";
226         maxRes = "+";
227       }
228       int[][] profile = (int[][]) hconsensus[i].get(AAFrequency.PROFILE);
229       if (profile != null && includeAllConsSymbols)
230       {
231         mouseOver = "";
232         if (alphabet != null)
233         {
234           for (int c = 0; c < alphabet.length; c++)
235           {
236             tval = ((float) profile[0][alphabet[c]])
237                     * 100f
238                     / (float) profile[1][ignoreGapsInConsensusCalculation ? 1
239                             : 0];
240             mouseOver += ((c == 0) ? "" : "; ") + alphabet[c] + " "
241                     + ((int) tval) + "%";
242           }
243         }
244         else
245         {
246           Object[] ca = new Object[profile[0].length];
247           float[] vl = new float[profile[0].length];
248           for (int c = 0; c < ca.length; c++)
249           {
250             ca[c] = new char[]
251             { (char) c };
252             vl[c] = (float) profile[0][c];
253           }
254           ;
255           jalview.util.QuickSort.sort(vl, ca);
256           for (int p = 0, c = ca.length - 1; profile[0][((char[]) ca[c])[0]] > 0; c--)
257           {
258             if (((char[]) ca[c])[0] != '-')
259             {
260               tval = ((float) profile[0][((char[]) ca[c])[0]])
261                       * 100f
262                       / (float) profile[1][ignoreGapsInConsensusCalculation ? 1
263                               : 0];
264               mouseOver += ((p == 0) ? "" : "; ") + ((char[]) ca[c])[0]
265                       + " " + ((int) tval) + "%";
266               p++;
267
268             }
269           }
270
271         }
272       }
273       else
274       {
275         mouseOver += ((int) value + "%");
276       }
277       consensus.annotations[i] = new Annotation(maxRes, mouseOver, ' ',
278               value);
279     }
280   }
281
282   /**
283    * get the sorted profile for the given position of the consensus
284    * 
285    * @param hconsensus
286    * @return
287    */
288   public static int[] extractProfile(Hashtable hconsensus,
289           boolean ignoreGapsInConsensusCalculation)
290   {
291     int[] rtnval = new int[64];
292     int[][] profile = (int[][]) hconsensus.get(AAFrequency.PROFILE);
293     if (profile == null)
294       return null;
295     Object[] ca = new Object[profile[0].length];
296     float[] vl = new float[profile[0].length];
297     for (int c = 0; c < ca.length; c++)
298     {
299       ca[c] = new char[]
300       { (char) c };
301       vl[c] = (float) profile[0][c];
302     }
303     ;
304     jalview.util.QuickSort.sort(vl, ca);
305     rtnval[0] = 1;
306     for (int c = ca.length - 1; profile[0][((char[]) ca[c])[0]] > 0; c--)
307     {
308       if (((char[]) ca[c])[0] != '-')
309       {
310         rtnval[rtnval[0]++] = ((char[]) ca[c])[0];
311         rtnval[rtnval[0]++] = (int) (((float) profile[0][((char[]) ca[c])[0]]) * 100f / (float) profile[1][ignoreGapsInConsensusCalculation ? 1
312                 : 0]);
313       }
314     }
315     return rtnval;
316   }
317 }