Prov not used in this version
[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         for (int j = 0; j < getHeight(); j++)\r
209         {\r
210             SequenceI s = getSequenceAt(j);\r
211             int newstart = s.findPosition(i);\r
212 \r
213             s.setStart(newstart);\r
214             s.setSequence(s.getSequence().substring(i));\r
215         }\r
216     }\r
217 \r
218     /**\r
219      * DOCUMENT ME!\r
220      *\r
221      * @param i DOCUMENT ME!\r
222      */\r
223     public void trimRight(int i)\r
224     {\r
225         for (int j = 0; j < getHeight(); j++)\r
226         {\r
227             SequenceI s = getSequenceAt(j);\r
228             int newend = s.findPosition(i);\r
229 \r
230             s.setEnd(newend);\r
231             s.setSequence(s.getSequence().substring(0, i + 1));\r
232         }\r
233     }\r
234 \r
235     /**\r
236      * DOCUMENT ME!\r
237      *\r
238      * @param s DOCUMENT ME!\r
239      */\r
240     public void deleteSequence(SequenceI s)\r
241     {\r
242         for (int i = 0; i < getHeight(); i++)\r
243         {\r
244             if (getSequenceAt(i) == s)\r
245             {\r
246                 deleteSequence(i);\r
247             }\r
248         }\r
249     }\r
250 \r
251     /**\r
252      * DOCUMENT ME!\r
253      *\r
254      * @param i DOCUMENT ME!\r
255      */\r
256     public void deleteSequence(int i)\r
257     {\r
258         sequences.removeElementAt(i);\r
259     }\r
260 \r
261     /**\r
262      * DOCUMENT ME!\r
263      *\r
264      * @param threshold DOCUMENT ME!\r
265      * @param sel DOCUMENT ME!\r
266      *\r
267      * @return DOCUMENT ME!\r
268      */\r
269     public Vector removeRedundancy(float threshold, Vector sel)\r
270     {\r
271         Vector del = new Vector();\r
272 \r
273         for (int i = 1; i < sel.size(); i++)\r
274         {\r
275             for (int j = 0; j < i; j++)\r
276             {\r
277                 // Only do the comparison if either have not been deleted\r
278                 if (!del.contains((SequenceI) sel.elementAt(i)) ||\r
279                         !del.contains((SequenceI) sel.elementAt(j)))\r
280                 {\r
281                     // use PID instead of Comparison (which is really not pleasant)\r
282                     float pid = Comparison.PID((SequenceI) sel.elementAt(j),\r
283                             (SequenceI) sel.elementAt(i));\r
284 \r
285                     if (pid >= threshold)\r
286                     {\r
287                         // Delete the shortest one\r
288                         if (((SequenceI) sel.elementAt(j)).getSequence().length() > ((SequenceI) sel\r
289                                                                                          .elementAt(\r
290                                     i)).getSequence().length())\r
291                         {\r
292                             del.addElement(sel.elementAt(i));\r
293                         }\r
294                         else\r
295                         {\r
296                             del.addElement(sel.elementAt(i));\r
297                         }\r
298                     }\r
299                 }\r
300             }\r
301         }\r
302 \r
303         // Now delete the sequences\r
304         for (int i = 0; i < del.size(); i++)\r
305         {\r
306             deleteSequence((SequenceI) del.elementAt(i));\r
307         }\r
308 \r
309         return del;\r
310     }\r
311 \r
312     /**    */\r
313     public SequenceGroup findGroup(int i)\r
314     {\r
315         return findGroup(getSequenceAt(i));\r
316     }\r
317 \r
318     /**    */\r
319     public SequenceGroup findGroup(SequenceI s)\r
320     {\r
321         for (int i = 0; i < this.groups.size(); i++)\r
322         {\r
323             SequenceGroup sg = (SequenceGroup) groups.elementAt(i);\r
324 \r
325             if (sg.sequences.contains(s))\r
326             {\r
327                 return sg;\r
328             }\r
329         }\r
330 \r
331         return null;\r
332     }\r
333 \r
334     /**\r
335      * DOCUMENT ME!\r
336      *\r
337      * @param s DOCUMENT ME!\r
338      *\r
339      * @return DOCUMENT ME!\r
340      */\r
341     public SequenceGroup[] findAllGroups(SequenceI s)\r
342     {\r
343         Vector temp = new Vector();\r
344 \r
345         int gSize = groups.size();\r
346         for (int i = 0; i < gSize; i++)\r
347         {\r
348             SequenceGroup sg = (SequenceGroup) groups.elementAt(i);\r
349             if(sg==null || sg.sequences==null)\r
350             {\r
351               this.deleteGroup(sg);\r
352               gSize--;\r
353               continue;\r
354             }\r
355 \r
356             if (sg.sequences.contains(s))\r
357             {\r
358                 temp.addElement(sg);\r
359             }\r
360         }\r
361 \r
362         SequenceGroup[] ret = new SequenceGroup[temp.size()];\r
363 \r
364         for (int i = 0; i < temp.size(); i++)\r
365         {\r
366             ret[i] = (SequenceGroup) temp.elementAt(i);\r
367         }\r
368 \r
369         return ret;\r
370     }\r
371 \r
372     /**\r
373      * DOCUMENT ME!\r
374      *\r
375      * @param sg DOCUMENT ME!\r
376      */\r
377     public void addSuperGroup(SuperGroup sg)\r
378     {\r
379         superGroup.addElement(sg);\r
380     }\r
381 \r
382     /**\r
383      * DOCUMENT ME!\r
384      *\r
385      * @param sg DOCUMENT ME!\r
386      */\r
387     public void removeSuperGroup(SuperGroup sg)\r
388     {\r
389         superGroup.removeElement(sg);\r
390     }\r
391 \r
392     /**\r
393      * DOCUMENT ME!\r
394      *\r
395      * @param sg DOCUMENT ME!\r
396      *\r
397      * @return DOCUMENT ME!\r
398      */\r
399     public SuperGroup getSuperGroup(SequenceGroup sg)\r
400     {\r
401         for (int i = 0; i < this.superGroup.size(); i++)\r
402         {\r
403             SuperGroup temp = (SuperGroup) superGroup.elementAt(i);\r
404 \r
405             if (temp.sequenceGroups.contains(sg))\r
406             {\r
407                 return temp;\r
408             }\r
409         }\r
410 \r
411         return null;\r
412     }\r
413 \r
414     /**    */\r
415     public void addGroup(SequenceGroup sg)\r
416     {\r
417         if (!groups.contains(sg))\r
418         {\r
419             groups.addElement(sg);\r
420         }\r
421     }\r
422 \r
423     /**\r
424      * DOCUMENT ME!\r
425      */\r
426     public void deleteAllGroups()\r
427     {\r
428         groups.removeAllElements();\r
429         superGroup.removeAllElements();\r
430 \r
431         int i = 0;\r
432 \r
433         while (i < sequences.size())\r
434         {\r
435             SequenceI s = getSequenceAt(i);\r
436             s.setColor(java.awt.Color.white);\r
437             i++;\r
438         }\r
439     }\r
440 \r
441     /**    */\r
442     public void deleteGroup(SequenceGroup g)\r
443     {\r
444         if (groups.contains(g))\r
445         {\r
446             groups.removeElement(g);\r
447         }\r
448     }\r
449 \r
450     /**    */\r
451     public SequenceI findName(String name)\r
452     {\r
453         int i = 0;\r
454 \r
455         while (i < sequences.size())\r
456         {\r
457             if (getSequenceAt(i).getName().equals(name))\r
458             {\r
459                 return getSequenceAt(i);\r
460             }\r
461 \r
462             i++;\r
463         }\r
464 \r
465         return null;\r
466     }\r
467 \r
468 \r
469     /**    */\r
470     public int findIndex(SequenceI s)\r
471     {\r
472         int i = 0;\r
473 \r
474         while (i < sequences.size())\r
475         {\r
476             if (s == getSequenceAt(i))\r
477             {\r
478                 return i;\r
479             }\r
480 \r
481             i++;\r
482         }\r
483 \r
484         return -1;\r
485     }\r
486 \r
487     /**\r
488      * DOCUMENT ME!\r
489      *\r
490      * @return DOCUMENT ME!\r
491      */\r
492     public int getHeight()\r
493     {\r
494         return sequences.size();\r
495     }\r
496 \r
497     /**\r
498      * DOCUMENT ME!\r
499      *\r
500      * @return DOCUMENT ME!\r
501      */\r
502     public int getWidth()\r
503     {\r
504         int maxLength = -1;\r
505 \r
506         for (int i = 0; i < sequences.size(); i++)\r
507         {\r
508             if (getSequenceAt(i).getLength() > maxLength)\r
509             {\r
510                 maxLength = getSequenceAt(i).getLength();\r
511             }\r
512         }\r
513 \r
514         return maxLength;\r
515     }\r
516 \r
517     /**\r
518      * DOCUMENT ME!\r
519      *\r
520      * @return DOCUMENT ME!\r
521      */\r
522     public int getMaxIdLength()\r
523     {\r
524         int max = 0;\r
525         int i = 0;\r
526 \r
527         while (i < sequences.size())\r
528         {\r
529             SequenceI seq = getSequenceAt(i);\r
530             String tmp = seq.getName() + "/" + seq.getStart() + "-" +\r
531                 seq.getEnd();\r
532 \r
533             if (tmp.length() > max)\r
534             {\r
535                 max = tmp.length();\r
536             }\r
537 \r
538             i++;\r
539         }\r
540 \r
541         return max;\r
542     }\r
543 \r
544     /**\r
545      * DOCUMENT ME!\r
546      *\r
547      * @param gc DOCUMENT ME!\r
548      */\r
549     public void setGapCharacter(char gc)\r
550     {\r
551         gapCharacter = gc;\r
552 \r
553         for (int i = 0; i < sequences.size(); i++)\r
554         {\r
555             Sequence seq = (Sequence) sequences.elementAt(i);\r
556             seq.sequence = seq.sequence.replace('.', gc);\r
557             seq.sequence = seq.sequence.replace('-', gc);\r
558             seq.sequence = seq.sequence.replace(' ', gc);\r
559         }\r
560     }\r
561 \r
562     /**\r
563      * DOCUMENT ME!\r
564      *\r
565      * @return DOCUMENT ME!\r
566      */\r
567     public char getGapCharacter()\r
568     {\r
569         return gapCharacter;\r
570     }\r
571 \r
572     /**\r
573      * DOCUMENT ME!\r
574      *\r
575      * @return DOCUMENT ME!\r
576      */\r
577     public Vector getAAFrequency()\r
578     {\r
579         return AAFrequency.calculate(sequences, 0, getWidth());\r
580     }\r
581 \r
582     /**\r
583      * DOCUMENT ME!\r
584      *\r
585      * @return DOCUMENT ME!\r
586      */\r
587     public boolean isAligned()\r
588     {\r
589         int width = getWidth();\r
590 \r
591         for (int i = 0; i < sequences.size(); i++)\r
592         {\r
593             if (getSequenceAt(i).getLength() != width)\r
594             {\r
595                 return false;\r
596             }\r
597         }\r
598 \r
599         return true;\r
600     }\r
601 \r
602     /**\r
603      * DOCUMENT ME!\r
604      *\r
605      * @param aa DOCUMENT ME!\r
606      */\r
607     public void deleteAnnotation(AlignmentAnnotation aa)\r
608     {\r
609         int aSize = 1;\r
610 \r
611         if (annotations != null)\r
612         {\r
613             aSize = annotations.length;\r
614         }\r
615 \r
616         AlignmentAnnotation[] temp = new AlignmentAnnotation[aSize - 1];\r
617 \r
618         int tIndex = 0;\r
619 \r
620         for (int i = 0; i < aSize; i++)\r
621         {\r
622             if (annotations[i] == aa)\r
623             {\r
624                 continue;\r
625             }\r
626 \r
627             temp[tIndex] = annotations[i];\r
628             tIndex++;\r
629         }\r
630 \r
631         annotations = temp;\r
632     }\r
633 \r
634     /**\r
635      * DOCUMENT ME!\r
636      *\r
637      * @param aa DOCUMENT ME!\r
638      */\r
639     public void addAnnotation(AlignmentAnnotation aa)\r
640     {\r
641         int aSize = 1;\r
642 \r
643         if (annotations != null)\r
644         {\r
645             aSize = annotations.length + 1;\r
646         }\r
647 \r
648 \r
649         AlignmentAnnotation[] temp = new AlignmentAnnotation[aSize];\r
650         int i = 0;\r
651 \r
652         if (aSize > 1)\r
653         {\r
654             for (i = 0; i < (aSize - 1); i++)\r
655             {\r
656                 temp[i] = annotations[i];\r
657             }\r
658         }\r
659 \r
660         temp[i] = aa;\r
661 \r
662         annotations = temp;\r
663     }\r
664 \r
665     /**\r
666      * DOCUMENT ME!\r
667      *\r
668      * @return DOCUMENT ME!\r
669      */\r
670     public AlignmentAnnotation[] getAlignmentAnnotation()\r
671     {\r
672         return annotations;\r
673     }\r
674 \r
675     public void setNucleotide(boolean b)\r
676     {\r
677       if(b)\r
678         type = NUCLEOTIDE;\r
679       else\r
680         type = PROTEIN;\r
681     }\r
682 \r
683     public boolean isNucleotide()\r
684     {\r
685       if(type==NUCLEOTIDE)\r
686         return true;\r
687       else\r
688         return false;\r
689     }\r
690 \r
691     public void setDataset(Alignment data)\r
692     {\r
693       if(dataset==null && data==null)\r
694       {\r
695         // Create a new dataset for this alignment.\r
696         // Can only be done once, if dataset is not null\r
697         // This will not be performed\r
698         Sequence[] seqs = new Sequence[getHeight()];\r
699         for (int i = 0; i < getHeight(); i++)\r
700         {\r
701 \r
702           seqs[i] = new Sequence(getSequenceAt(i).getName(),\r
703                                  AlignSeq.extractGaps(\r
704                                      jalview.util.Comparison.GapChars,\r
705                                      getSequenceAt(i).getSequence()\r
706                                  ),\r
707                                  getSequenceAt(i).getStart(),\r
708                                  getSequenceAt(i).getEnd());\r
709 \r
710           getSequenceAt(i).setDatasetSequence(seqs[i]);\r
711         }\r
712 \r
713         dataset = new Alignment(seqs);\r
714       }\r
715       else if(dataset==null && data!=null)\r
716       {\r
717         dataset = data;\r
718       }\r
719     }\r
720 \r
721     public Alignment getDataset()\r
722     {\r
723       return dataset;\r
724     }\r
725 \r
726 }\r