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