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