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