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