featuresAdded = false
[jalview.git] / src / jalview / datamodel / Alignment.java
1 package jalview.datamodel;\r
2 \r
3 import jalview.analysis.*;\r
4 import jalview.util.*;\r
5 import java.util.*;\r
6 \r
7 /** Data structure to hold and manipulate a multiple sequence alignment\r
8  */\r
9 public class Alignment implements AlignmentI\r
10 {\r
11 \r
12   protected Vector      sequences;\r
13   protected Vector      groups = new Vector();\r
14   protected ArrayList   superGroup = new ArrayList();\r
15   protected char        gapCharacter = '-';\r
16   public boolean featuresAdded = false;\r
17 \r
18   /** Make an alignment from an array of Sequences.\r
19   *\r
20   * @param sequences\r
21   */\r
22   public Alignment(SequenceI[] seqs) {\r
23     sequences = new Vector();\r
24 \r
25     for (int i=0; i < seqs.length; i++)\r
26       sequences.addElement(seqs[i]);\r
27 \r
28     getWidth();\r
29   }\r
30 \r
31   public Vector      getSequences() {\r
32     return sequences;\r
33   }\r
34 \r
35   public SequenceI getSequenceAt(int i) {\r
36     if (i < sequences.size()) {\r
37       return (SequenceI)sequences.elementAt(i);\r
38     }\r
39 \r
40     return null;\r
41   }\r
42 \r
43   /** Adds a sequence to the alignment.  Recalculates maxLength and size.\r
44    *\r
45    * @param snew\r
46    */\r
47   public void addSequence(SequenceI snew) {\r
48     sequences.addElement(snew);\r
49   }\r
50 \r
51   public void addSequence(SequenceI[] seq) {\r
52     for (int i=0; i < seq.length; i++) {\r
53       addSequence(seq[i]);\r
54     }\r
55   }\r
56 \r
57   /** Adds a sequence to the alignment.  Recalculates maxLength and size.\r
58     *\r
59    * @param snew\r
60    */\r
61   public void setSequenceAt(int i,SequenceI snew) {\r
62     SequenceI oldseq = getSequenceAt(i);\r
63     deleteSequence(oldseq);\r
64 \r
65     sequences.setElementAt(snew,i);\r
66   }\r
67 \r
68   public Vector getGroups() {\r
69     return groups;\r
70   }\r
71 \r
72   /** Sorts the sequences by sequence group size - largest to smallest.\r
73    * Uses QuickSort.\r
74    */\r
75   public void sortGroups() {\r
76     float[]  arr = new float [groups.size()];\r
77     Object[] s   = new Object[groups.size()];\r
78 \r
79     for (int i=0; i < groups.size(); i++) {\r
80       arr[i] = ((SequenceGroup)groups.elementAt(i)).sequences.size();\r
81       s[i]   = groups.elementAt(i);\r
82     }\r
83 \r
84     QuickSort.sort(arr,s);\r
85 \r
86     Vector newg = new Vector(groups.size());\r
87 \r
88     for (int i=groups.size()-1; i >= 0; i--) {\r
89       newg.addElement(s[i]);\r
90     }\r
91 \r
92     groups = newg;\r
93   }\r
94 \r
95   /** Takes out columns consisting entirely of gaps (-,.," ")\r
96    */\r
97   public void removeGaps()\r
98   {\r
99 \r
100     SequenceI current;\r
101     int iSize = getWidth();\r
102     for (int i=0; i < iSize; i++)\r
103     {\r
104       boolean delete = true;\r
105       for (int j=0; j < getHeight(); j++)\r
106       {\r
107         current = getSequenceAt(j);\r
108         if (current.getLength() > i)\r
109         {\r
110             /* MC Should move this to a method somewhere */\r
111           if ( !jalview.util.Comparison.isGap(current.getCharAt(i)))\r
112             delete = false;\r
113 \r
114         }\r
115       }\r
116 \r
117       if ( delete )\r
118       {\r
119         deleteColumns(i,i);\r
120         iSize--;\r
121         i--;\r
122       }\r
123     }\r
124 \r
125 \r
126   }\r
127 \r
128   /** Returns an array of Sequences containing columns\r
129    * start to end (inclusive) only.\r
130    *\r
131    * @param start start column to fetch\r
132    * @param end end column to fetch\r
133    * @return Array of Sequences, ready to put into a new Alignment\r
134    */\r
135   public SequenceI[] getColumns(int start, int end) {\r
136     return getColumns(0,getHeight()-1,start,end);\r
137   }\r
138 \r
139   /** Removes a range of columns (start to end inclusive).\r
140    *\r
141    * @param start Start column in the alignment\r
142    * @param end End column in the alignment\r
143    */\r
144   public void deleteColumns(int start, int end) {\r
145     deleteColumns(0,getHeight()-1,start,end);\r
146   }\r
147 \r
148   public void deleteColumns(int seq1, int seq2, int start, int end) {\r
149 \r
150     for (int i=0; i <= (end-start); i++) {\r
151       for (int j=seq1; j <= seq2; j++) {\r
152         getSequenceAt(j).deleteCharAt(start);\r
153       }\r
154     }\r
155   }\r
156 \r
157   public void insertColumns(SequenceI[] seqs, int pos) {\r
158     if (seqs.length == getHeight()) {\r
159       for (int i=0; i < getHeight();i++) {\r
160         String tmp = new String(getSequenceAt(i).getSequence());\r
161         getSequenceAt(i).setSequence(tmp.substring(0,pos) + seqs[i].getSequence() + tmp.substring(pos));\r
162       }\r
163 \r
164     }\r
165   }\r
166 \r
167   public SequenceI[] getColumns(int seq1, int seq2, int start, int end) {\r
168     SequenceI[] seqs = new Sequence[(seq2-seq1)+1];\r
169     for (int i=seq1; i<= seq2; i++ ) {\r
170       seqs[i] = new Sequence(getSequenceAt(i).getName(),\r
171                              getSequenceAt(i).getSequence().substring(start,end),\r
172                              getSequenceAt(i).findPosition(start),\r
173                              getSequenceAt(i).findPosition(end));\r
174     }\r
175     return seqs;\r
176   }\r
177 \r
178   public void trimLeft(int i) {\r
179     for (int j = 0;j< getHeight();j++) {\r
180 \r
181       SequenceI s        = getSequenceAt(j);\r
182       int       newstart = s.findPosition(i);\r
183 \r
184       s.setStart(newstart);\r
185       s.setSequence(s.getSequence().substring(i));\r
186 \r
187     }\r
188   }\r
189 \r
190   public void  trimRight(int i) {\r
191     for (int j = 0;j< getHeight();j++) {\r
192       SequenceI s      = getSequenceAt(j);\r
193       int       newend = s.findPosition(i);\r
194 \r
195       s.setEnd(newend);\r
196       s.setSequence(s.getSequence().substring(0,i+1));\r
197     }\r
198   }\r
199 \r
200   public void deleteSequence(SequenceI s)\r
201   {\r
202     for (int i=0; i < getHeight(); i++)\r
203       if (getSequenceAt(i) == s)\r
204         deleteSequence(i);\r
205   }\r
206 \r
207   public void  deleteSequence(int i)\r
208   {\r
209     sequences.removeElementAt(i);\r
210   }\r
211 \r
212 \r
213   public Vector removeRedundancy(float threshold, Vector sel) {\r
214     Vector del = new Vector();\r
215 \r
216     for (int i = 1; i < sel.size(); i++)\r
217     {\r
218       for (int j = 0; j < i; j++)\r
219       {\r
220         // Only do the comparison if either have not been deleted\r
221         if (!del.contains( (SequenceI) sel.elementAt(i)) ||\r
222             !del.contains( (SequenceI) sel.elementAt(j)))\r
223         {\r
224 \r
225           float pid = Comparison.compare( (SequenceI) sel.elementAt(j),\r
226                                          (SequenceI) sel.elementAt(i));\r
227 \r
228           if (pid >= threshold)\r
229           {\r
230             // Delete the shortest one\r
231             if ( ( (SequenceI) sel.elementAt(j)).getSequence().length() >\r
232                 ( (SequenceI) sel.elementAt(i)).getSequence().length())\r
233               del.addElement(sel.elementAt(i));\r
234             else\r
235               del.addElement(sel.elementAt(i));\r
236           }\r
237         }\r
238       }\r
239     }\r
240 \r
241     // Now delete the sequences\r
242     for (int i=0; i < del.size(); i++)\r
243       deleteSequence((SequenceI)del.elementAt(i));\r
244 \r
245     return del;\r
246   }\r
247 \r
248   public void sortByPID(SequenceI s) {\r
249 \r
250     float     scores[] = new float[getHeight()];\r
251     SequenceI seqs[]   = new SequenceI[getHeight()];\r
252 \r
253     for (int i = 0; i < getHeight(); i++) {\r
254       scores[i] = Comparison.compare(getSequenceAt(i),s);\r
255       seqs[i]   = getSequenceAt(i);\r
256     }\r
257 \r
258     QuickSort.sort(scores,0,scores.length-1,seqs);\r
259 \r
260     int len = 0;\r
261 \r
262     if (getHeight()%2 == 0) {\r
263       len = getHeight()/2;\r
264     } else {\r
265       len = (getHeight()+1)/2;\r
266     }\r
267 \r
268     for (int i = 0; i < len; i++) {\r
269       SequenceI tmp = seqs[i];\r
270       sequences.setElementAt(seqs[getHeight()-i-1],i);\r
271       sequences.setElementAt(tmp,getHeight()-i-1);\r
272     }\r
273   }\r
274 \r
275   public void sortByID() {\r
276     String    ids[]   = new String[getHeight()];\r
277     SequenceI seqs[]  = new SequenceI[getHeight()];\r
278 \r
279     for (int i = 0; i < getHeight(); i++) {\r
280       ids[i]  = getSequenceAt(i).getName();\r
281       seqs[i] = getSequenceAt(i);\r
282     }\r
283 \r
284     QuickSort.sort(ids,seqs);\r
285 \r
286     int len = 0;\r
287 \r
288     if (getHeight()%2 == 0) {\r
289       len = getHeight()/2;\r
290     } else {\r
291       len = (getHeight()+1)/2;\r
292       System.out.println("Sort len is odd = " + len);\r
293     }\r
294     for (int i = 0; i < len; i++) {\r
295       System.out.println("Swapping " + seqs[i].getName() + " and " + seqs[getHeight()-i-1].getName());\r
296       SequenceI tmp = seqs[i];\r
297       sequences.setElementAt(seqs[getHeight()-i-1],i);\r
298       sequences.setElementAt(tmp,getHeight()-i-1);\r
299     }\r
300   }\r
301 \r
302   /**    */\r
303   public SequenceGroup findGroup(int i) {\r
304     return findGroup(getSequenceAt(i));\r
305   }\r
306 \r
307   /**    */\r
308   public SequenceGroup findGroup(SequenceI s) {\r
309     for (int i = 0; i < this.groups.size();i++)\r
310     {\r
311       SequenceGroup sg = (SequenceGroup)groups.elementAt(i);\r
312       if (sg.sequences.contains(s))\r
313         return sg;\r
314 \r
315     }\r
316     return null;\r
317   }\r
318 \r
319   public SequenceGroup [] findAllGroups(SequenceI s)\r
320   {\r
321 \r
322     ArrayList temp = new ArrayList();\r
323 \r
324     for (int i = 0; i < this.groups.size();i++)\r
325     {\r
326       SequenceGroup sg = (SequenceGroup)groups.elementAt(i);\r
327 \r
328       if (sg.sequences.contains(s))\r
329        temp.add(sg);\r
330     }\r
331 \r
332     SequenceGroup [] ret = new SequenceGroup[temp.size()];\r
333     temp.toArray( ret );\r
334 \r
335     return ret;\r
336 \r
337   }\r
338   /**    */\r
339   public void addToGroup(SequenceGroup g, SequenceI s) {\r
340     if (!(g.sequences.contains(s))) {\r
341       g.sequences.addElement(s);\r
342     }\r
343   }\r
344   /**    */\r
345   public void removeFromGroup(SequenceGroup g,SequenceI s) {\r
346     if (g != null && g.sequences != null) {\r
347       if (g.sequences.contains(s)) {\r
348         g.sequences.removeElement(s);\r
349         if (g.sequences.size() == 0) {\r
350           groups.removeElement(g);\r
351         }\r
352       }\r
353     }\r
354   }\r
355 \r
356   public void addSuperGroup(SuperGroup sg)\r
357   {\r
358     superGroup.add(sg);\r
359   }\r
360 \r
361   public void removeSuperGroup(SuperGroup sg)\r
362   {\r
363     superGroup.remove(sg);\r
364   }\r
365 \r
366   public SuperGroup     getSuperGroup(SequenceGroup sg)\r
367   {\r
368     for (int i = 0; i < this.superGroup.size(); i++)\r
369     {\r
370       SuperGroup temp = (SuperGroup) superGroup.get(i);\r
371       if (temp.sequenceGroups.contains(sg))\r
372         return temp;\r
373     }\r
374     return null;\r
375   }\r
376 \r
377   /**    */\r
378   public void addGroup(SequenceGroup sg) {\r
379     if(!groups.contains(sg))\r
380       groups.addElement(sg);\r
381   }\r
382 \r
383   public void deleteAllGroups()\r
384   {\r
385     groups.clear();\r
386     superGroup.clear();\r
387    int i=0;\r
388     while (i < sequences.size()) {\r
389      SequenceI s = getSequenceAt(i);\r
390      s.setColor(java.awt.Color.white);\r
391      i++;\r
392    }\r
393 \r
394 \r
395   }\r
396 \r
397   /**    */\r
398   public void deleteGroup(SequenceGroup g) {\r
399     if (groups.contains(g)) {\r
400       groups.removeElement(g);\r
401     }\r
402   }\r
403 \r
404   /**    */\r
405   public SequenceI findName(String name) {\r
406     int i = 0;\r
407     while (i < sequences.size()) {\r
408       SequenceI s = getSequenceAt(i);\r
409       if (s.getName().equals(name))\r
410         return s;\r
411 \r
412       i++;\r
413     }\r
414     return null;\r
415   }\r
416 \r
417   /**    */\r
418   public SequenceI findbyDisplayId(String name) {\r
419     int i = 0;\r
420     while (i < sequences.size()) {\r
421       SequenceI s = getSequenceAt(i);\r
422       if (s.getDisplayId().equals(name))\r
423         return s;\r
424 \r
425       i++;\r
426     }\r
427     return null;\r
428   }\r
429 \r
430   /**    */\r
431   public int findIndex(SequenceI s)\r
432   {\r
433     int i=0;\r
434     while (i < sequences.size())\r
435     {\r
436       if (s == getSequenceAt(i))\r
437         return i;\r
438 \r
439       i++;\r
440     }\r
441     return -1;\r
442   }\r
443 \r
444   public int getHeight() {\r
445     return sequences.size();\r
446   }\r
447 \r
448 \r
449   public int getWidth()\r
450   {\r
451     int maxLength = -1;\r
452     for (int i = 0; i < sequences.size(); i++)\r
453     {\r
454       if (getSequenceAt(i).getLength() > maxLength)\r
455         maxLength = getSequenceAt(i).getLength();\r
456     }\r
457 \r
458     return maxLength;\r
459   }\r
460 \r
461 \r
462   public int getMaxIdLength() {\r
463     int max = 0;\r
464     int i   = 0;\r
465 \r
466     while (i < sequences.size()) {\r
467       SequenceI seq = getSequenceAt(i);\r
468       String    tmp = seq.getName() + "/" + seq.getStart() + "-" + seq.getEnd();\r
469 \r
470       if (tmp.length() > max) {\r
471         max = tmp.length();\r
472       }\r
473 \r
474       i++;\r
475     }\r
476     return max;\r
477   }\r
478 \r
479   public void setGapCharacter(char gc)\r
480   {\r
481     char old = getGapCharacter();\r
482     gapCharacter = gc;\r
483     for (int i=0; i < sequences.size(); i++)\r
484      {\r
485        Sequence seq = (Sequence)sequences.elementAt(i);\r
486        seq.sequence = seq.sequence.replace(old, gc);\r
487      }\r
488   }\r
489 \r
490   public char getGapCharacter() {\r
491     return gapCharacter;\r
492   }\r
493 \r
494   public Vector getAAFrequency()\r
495   {\r
496     return AAFrequency.calculate(sequences, 0, getWidth());\r
497   }\r
498 \r
499   public boolean isAligned()\r
500   {\r
501     int width = getWidth();\r
502     for (int i = 0; i < sequences.size(); i++)\r
503       if (getSequenceAt(i).getLength() != width)\r
504         return false;\r
505 \r
506     return true;\r
507 \r
508   }\r
509 }\r
510 \r
511 \r
512 \r
513 \r
514 \r
515 \r
516 \r
517 \r