Formatting changes
[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 package jalview.datamodel;\r
20 \r
21 import jalview.analysis.*;\r
22 \r
23 import jalview.util.*;\r
24 \r
25 import java.util.*;\r
26 \r
27 \r
28 /** Data structure to hold and manipulate a multiple sequence alignment\r
29  */\r
30 public class Alignment implements AlignmentI\r
31 {\r
32     protected Vector sequences;\r
33     protected Vector groups = new Vector();\r
34     protected Vector superGroup = new Vector();\r
35     protected char gapCharacter = '-';\r
36 \r
37     /** DOCUMENT ME!! */\r
38     public AlignmentAnnotation[] annotations;\r
39 \r
40     /** DOCUMENT ME!! */\r
41     public boolean featuresAdded = false;\r
42 \r
43     /** Make an alignment from an array of Sequences.\r
44      *\r
45      * @param sequences\r
46      */\r
47     public Alignment(SequenceI[] seqs)\r
48     {\r
49         sequences = new Vector();\r
50 \r
51         for (int i = 0; i < seqs.length; i++)\r
52         {\r
53             sequences.addElement(seqs[i]);\r
54         }\r
55 \r
56         getWidth();\r
57     }\r
58 \r
59     /**\r
60      * DOCUMENT ME!\r
61      *\r
62      * @return DOCUMENT ME!\r
63      */\r
64     public Vector getSequences()\r
65     {\r
66         return sequences;\r
67     }\r
68 \r
69     /**\r
70      * DOCUMENT ME!\r
71      *\r
72      * @param i DOCUMENT ME!\r
73      *\r
74      * @return DOCUMENT ME!\r
75      */\r
76     public SequenceI getSequenceAt(int i)\r
77     {\r
78         if (i < sequences.size())\r
79         {\r
80             return (SequenceI) sequences.elementAt(i);\r
81         }\r
82 \r
83         return null;\r
84     }\r
85 \r
86     /** Adds a sequence to the alignment.  Recalculates maxLength and size.\r
87      *\r
88      * @param snew\r
89      */\r
90     public void addSequence(SequenceI snew)\r
91     {\r
92         sequences.addElement(snew);\r
93     }\r
94 \r
95     /**\r
96      * DOCUMENT ME!\r
97      *\r
98      * @param seq DOCUMENT ME!\r
99      */\r
100     public void addSequence(SequenceI[] seq)\r
101     {\r
102         for (int i = 0; i < seq.length; i++)\r
103         {\r
104             addSequence(seq[i]);\r
105         }\r
106     }\r
107 \r
108     /** Adds a sequence to the alignment.  Recalculates maxLength and size.\r
109      *\r
110      * @param snew\r
111      */\r
112     public void setSequenceAt(int i, SequenceI snew)\r
113     {\r
114         SequenceI oldseq = getSequenceAt(i);\r
115         deleteSequence(oldseq);\r
116 \r
117         sequences.setElementAt(snew, i);\r
118     }\r
119 \r
120     /**\r
121      * DOCUMENT ME!\r
122      *\r
123      * @return DOCUMENT ME!\r
124      */\r
125     public Vector getGroups()\r
126     {\r
127         return groups;\r
128     }\r
129 \r
130     /** Takes out columns consisting entirely of gaps (-,.," ")\r
131      */\r
132     public void removeGaps()\r
133     {\r
134         SequenceI current;\r
135         int iSize = getWidth();\r
136 \r
137         for (int i = 0; i < iSize; i++)\r
138         {\r
139             boolean delete = true;\r
140 \r
141             for (int j = 0; j < getHeight(); j++)\r
142             {\r
143                 current = getSequenceAt(j);\r
144 \r
145                 if (current.getLength() > i)\r
146                 {\r
147                     /* MC Should move this to a method somewhere */\r
148                     if (!jalview.util.Comparison.isGap(current.getCharAt(i)))\r
149                     {\r
150                         delete = false;\r
151                     }\r
152                 }\r
153             }\r
154 \r
155             if (delete)\r
156             {\r
157                 deleteColumns(i, i);\r
158                 iSize--;\r
159                 i--;\r
160             }\r
161         }\r
162     }\r
163 \r
164     /** Removes a range of columns (start to end inclusive).\r
165      *\r
166      * @param start Start column in the alignment\r
167      * @param end End column in the alignment\r
168      */\r
169     public void deleteColumns(int start, int end)\r
170     {\r
171         deleteColumns(0, getHeight() - 1, start, end);\r
172     }\r
173 \r
174     /**\r
175      * DOCUMENT ME!\r
176      *\r
177      * @param seq1 DOCUMENT ME!\r
178      * @param seq2 DOCUMENT ME!\r
179      * @param start DOCUMENT ME!\r
180      * @param end DOCUMENT ME!\r
181      */\r
182     public void deleteColumns(int seq1, int seq2, int start, int end)\r
183     {\r
184         for (int i = 0; i <= (end - start); i++)\r
185         {\r
186             for (int j = seq1; j <= seq2; j++)\r
187             {\r
188                 getSequenceAt(j).deleteCharAt(start);\r
189             }\r
190         }\r
191     }\r
192 \r
193     /**\r
194      * DOCUMENT ME!\r
195      *\r
196      * @param i DOCUMENT ME!\r
197      */\r
198     public void trimLeft(int i)\r
199     {\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      * DOCUMENT ME!\r
212      *\r
213      * @param i DOCUMENT ME!\r
214      */\r
215     public void trimRight(int i)\r
216     {\r
217         for (int j = 0; j < getHeight(); j++)\r
218         {\r
219             SequenceI s = getSequenceAt(j);\r
220             int newend = s.findPosition(i);\r
221 \r
222             s.setEnd(newend);\r
223             s.setSequence(s.getSequence().substring(0, i + 1));\r
224         }\r
225     }\r
226 \r
227     /**\r
228      * DOCUMENT ME!\r
229      *\r
230      * @param s DOCUMENT ME!\r
231      */\r
232     public void deleteSequence(SequenceI s)\r
233     {\r
234         for (int i = 0; i < getHeight(); i++)\r
235         {\r
236             if (getSequenceAt(i) == s)\r
237             {\r
238                 deleteSequence(i);\r
239             }\r
240         }\r
241     }\r
242 \r
243     /**\r
244      * DOCUMENT ME!\r
245      *\r
246      * @param i DOCUMENT ME!\r
247      */\r
248     public void deleteSequence(int i)\r
249     {\r
250         sequences.removeElementAt(i);\r
251     }\r
252 \r
253     /**\r
254      * DOCUMENT ME!\r
255      *\r
256      * @param threshold DOCUMENT ME!\r
257      * @param sel DOCUMENT ME!\r
258      *\r
259      * @return DOCUMENT ME!\r
260      */\r
261     public Vector removeRedundancy(float threshold, Vector sel)\r
262     {\r
263         Vector del = new Vector();\r
264 \r
265         for (int i = 1; i < sel.size(); i++)\r
266         {\r
267             for (int j = 0; j < i; j++)\r
268             {\r
269                 // Only do the comparison if either have not been deleted\r
270                 if (!del.contains((SequenceI) sel.elementAt(i)) ||\r
271                         !del.contains((SequenceI) sel.elementAt(j)))\r
272                 {\r
273                     // use PID instead of Comparison (which is really not pleasant)\r
274                     float pid = Comparison.PID((SequenceI) sel.elementAt(j),\r
275                             (SequenceI) sel.elementAt(i));\r
276 \r
277                     if (pid >= threshold)\r
278                     {\r
279                         // Delete the shortest one\r
280                         if (((SequenceI) sel.elementAt(j)).getSequence().length() > ((SequenceI) sel\r
281                                                                                          .elementAt(\r
282                                     i)).getSequence().length())\r
283                         {\r
284                             del.addElement(sel.elementAt(i));\r
285                         }\r
286                         else\r
287                         {\r
288                             del.addElement(sel.elementAt(i));\r
289                         }\r
290                     }\r
291                 }\r
292             }\r
293         }\r
294 \r
295         // Now delete the sequences\r
296         for (int i = 0; i < del.size(); i++)\r
297         {\r
298             deleteSequence((SequenceI) del.elementAt(i));\r
299         }\r
300 \r
301         return del;\r
302     }\r
303 \r
304     /**    */\r
305     public SequenceGroup findGroup(int i)\r
306     {\r
307         return findGroup(getSequenceAt(i));\r
308     }\r
309 \r
310     /**    */\r
311     public SequenceGroup findGroup(SequenceI s)\r
312     {\r
313         for (int i = 0; i < this.groups.size(); i++)\r
314         {\r
315             SequenceGroup sg = (SequenceGroup) groups.elementAt(i);\r
316 \r
317             if (sg.sequences.contains(s))\r
318             {\r
319                 return sg;\r
320             }\r
321         }\r
322 \r
323         return null;\r
324     }\r
325 \r
326     /**\r
327      * DOCUMENT ME!\r
328      *\r
329      * @param s DOCUMENT ME!\r
330      *\r
331      * @return DOCUMENT ME!\r
332      */\r
333     public SequenceGroup[] findAllGroups(SequenceI s)\r
334     {\r
335         Vector temp = new Vector();\r
336 \r
337         for (int i = 0; i < this.groups.size(); i++)\r
338         {\r
339             SequenceGroup sg = (SequenceGroup) groups.elementAt(i);\r
340 \r
341             if (sg.sequences.contains(s))\r
342             {\r
343                 temp.addElement(sg);\r
344             }\r
345         }\r
346 \r
347         SequenceGroup[] ret = new SequenceGroup[temp.size()];\r
348 \r
349         for (int i = 0; i < temp.size(); i++)\r
350         {\r
351             ret[i] = (SequenceGroup) temp.elementAt(i);\r
352         }\r
353 \r
354         return ret;\r
355     }\r
356 \r
357     /**\r
358      * DOCUMENT ME!\r
359      *\r
360      * @param sg DOCUMENT ME!\r
361      */\r
362     public void addSuperGroup(SuperGroup sg)\r
363     {\r
364         superGroup.addElement(sg);\r
365     }\r
366 \r
367     /**\r
368      * DOCUMENT ME!\r
369      *\r
370      * @param sg DOCUMENT ME!\r
371      */\r
372     public void removeSuperGroup(SuperGroup sg)\r
373     {\r
374         superGroup.removeElement(sg);\r
375     }\r
376 \r
377     /**\r
378      * DOCUMENT ME!\r
379      *\r
380      * @param sg DOCUMENT ME!\r
381      *\r
382      * @return DOCUMENT ME!\r
383      */\r
384     public SuperGroup getSuperGroup(SequenceGroup sg)\r
385     {\r
386         for (int i = 0; i < this.superGroup.size(); i++)\r
387         {\r
388             SuperGroup temp = (SuperGroup) superGroup.elementAt(i);\r
389 \r
390             if (temp.sequenceGroups.contains(sg))\r
391             {\r
392                 return temp;\r
393             }\r
394         }\r
395 \r
396         return null;\r
397     }\r
398 \r
399     /**    */\r
400     public void addGroup(SequenceGroup sg)\r
401     {\r
402         if (!groups.contains(sg))\r
403         {\r
404             groups.addElement(sg);\r
405         }\r
406     }\r
407 \r
408     /**\r
409      * DOCUMENT ME!\r
410      */\r
411     public void deleteAllGroups()\r
412     {\r
413         groups.removeAllElements();\r
414         superGroup.removeAllElements();\r
415 \r
416         int i = 0;\r
417 \r
418         while (i < sequences.size())\r
419         {\r
420             SequenceI s = getSequenceAt(i);\r
421             s.setColor(java.awt.Color.white);\r
422             i++;\r
423         }\r
424     }\r
425 \r
426     /**    */\r
427     public void deleteGroup(SequenceGroup g)\r
428     {\r
429         if (groups.contains(g))\r
430         {\r
431             groups.removeElement(g);\r
432         }\r
433     }\r
434 \r
435     /**    */\r
436     public SequenceI findName(String name)\r
437     {\r
438         int i = 0;\r
439 \r
440         while (i < sequences.size())\r
441         {\r
442             SequenceI s = getSequenceAt(i);\r
443 \r
444             if (s.getName().equals(name))\r
445             {\r
446                 return s;\r
447             }\r
448 \r
449             i++;\r
450         }\r
451 \r
452         return null;\r
453     }\r
454 \r
455     /**    */\r
456     public SequenceI findbyDisplayId(String name)\r
457     {\r
458         int i = 0;\r
459 \r
460         while (i < sequences.size())\r
461         {\r
462             SequenceI s = getSequenceAt(i);\r
463 \r
464             if (s.getDisplayId().equals(name))\r
465             {\r
466                 return s;\r
467             }\r
468 \r
469             i++;\r
470         }\r
471 \r
472         return null;\r
473     }\r
474 \r
475     /**    */\r
476     public int findIndex(SequenceI s)\r
477     {\r
478         int i = 0;\r
479 \r
480         while (i < sequences.size())\r
481         {\r
482             if (s == getSequenceAt(i))\r
483             {\r
484                 return i;\r
485             }\r
486 \r
487             i++;\r
488         }\r
489 \r
490         return -1;\r
491     }\r
492 \r
493     /**\r
494      * DOCUMENT ME!\r
495      *\r
496      * @return DOCUMENT ME!\r
497      */\r
498     public int getHeight()\r
499     {\r
500         return sequences.size();\r
501     }\r
502 \r
503     /**\r
504      * DOCUMENT ME!\r
505      *\r
506      * @return DOCUMENT ME!\r
507      */\r
508     public int getWidth()\r
509     {\r
510         int maxLength = -1;\r
511 \r
512         for (int i = 0; i < sequences.size(); i++)\r
513         {\r
514             if (getSequenceAt(i).getLength() > maxLength)\r
515             {\r
516                 maxLength = getSequenceAt(i).getLength();\r
517             }\r
518         }\r
519 \r
520         return maxLength;\r
521     }\r
522 \r
523     /**\r
524      * DOCUMENT ME!\r
525      *\r
526      * @return DOCUMENT ME!\r
527      */\r
528     public int getMaxIdLength()\r
529     {\r
530         int max = 0;\r
531         int i = 0;\r
532 \r
533         while (i < sequences.size())\r
534         {\r
535             SequenceI seq = getSequenceAt(i);\r
536             String tmp = seq.getName() + "/" + seq.getStart() + "-" +\r
537                 seq.getEnd();\r
538 \r
539             if (tmp.length() > max)\r
540             {\r
541                 max = tmp.length();\r
542             }\r
543 \r
544             i++;\r
545         }\r
546 \r
547         return max;\r
548     }\r
549 \r
550     /**\r
551      * DOCUMENT ME!\r
552      *\r
553      * @param gc DOCUMENT ME!\r
554      */\r
555     public void setGapCharacter(char gc)\r
556     {\r
557         gapCharacter = gc;\r
558 \r
559         for (int i = 0; i < sequences.size(); i++)\r
560         {\r
561             Sequence seq = (Sequence) sequences.elementAt(i);\r
562             seq.sequence = seq.sequence.replace('.', gc);\r
563             seq.sequence = seq.sequence.replace('-', gc);\r
564             seq.sequence = seq.sequence.replace(' ', gc);\r
565         }\r
566     }\r
567 \r
568     /**\r
569      * DOCUMENT ME!\r
570      *\r
571      * @return DOCUMENT ME!\r
572      */\r
573     public char getGapCharacter()\r
574     {\r
575         return gapCharacter;\r
576     }\r
577 \r
578     /**\r
579      * DOCUMENT ME!\r
580      *\r
581      * @return DOCUMENT ME!\r
582      */\r
583     public Vector getAAFrequency()\r
584     {\r
585         return AAFrequency.calculate(sequences, 0, getWidth());\r
586     }\r
587 \r
588     /**\r
589      * DOCUMENT ME!\r
590      *\r
591      * @return DOCUMENT ME!\r
592      */\r
593     public boolean isAligned()\r
594     {\r
595         int width = getWidth();\r
596 \r
597         for (int i = 0; i < sequences.size(); i++)\r
598         {\r
599             if (getSequenceAt(i).getLength() != width)\r
600             {\r
601                 return false;\r
602             }\r
603         }\r
604 \r
605         return true;\r
606     }\r
607 \r
608     /**\r
609      * DOCUMENT ME!\r
610      *\r
611      * @param aa DOCUMENT ME!\r
612      */\r
613     public void deleteAnnotation(AlignmentAnnotation aa)\r
614     {\r
615         int aSize = 1;\r
616 \r
617         if (annotations != null)\r
618         {\r
619             aSize = annotations.length;\r
620         }\r
621 \r
622         AlignmentAnnotation[] temp = new AlignmentAnnotation[aSize - 1];\r
623 \r
624         int tIndex = 0;\r
625 \r
626         for (int i = 0; i < aSize; i++)\r
627         {\r
628             if (annotations[i] == aa)\r
629             {\r
630                 continue;\r
631             }\r
632 \r
633             temp[tIndex] = annotations[i];\r
634             tIndex++;\r
635         }\r
636 \r
637         annotations = temp;\r
638     }\r
639 \r
640     /**\r
641      * DOCUMENT ME!\r
642      *\r
643      * @param aa DOCUMENT ME!\r
644      */\r
645     public void addAnnotation(AlignmentAnnotation aa)\r
646     {\r
647         int aSize = 1;\r
648 \r
649         if (annotations != null)\r
650         {\r
651             aSize = annotations.length + 1;\r
652         }\r
653 \r
654         AlignmentAnnotation[] temp = new AlignmentAnnotation[aSize];\r
655         int i = 0;\r
656 \r
657         if (aSize > 1)\r
658         {\r
659             for (i = 0; i < (aSize - 1); i++)\r
660             {\r
661                 temp[i] = annotations[i];\r
662             }\r
663         }\r
664 \r
665         temp[i] = aa;\r
666 \r
667         annotations = temp;\r
668     }\r
669 \r
670     /**\r
671      * DOCUMENT ME!\r
672      *\r
673      * @return DOCUMENT ME!\r
674      */\r
675     public AlignmentAnnotation[] getAlignmentAnnotation()\r
676     {\r
677         return annotations;\r
678     }\r
679 }\r