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