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