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