Don't parse input id, leave it as it is
[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             if (getSequenceAt(i).getName().equals(name))\r
462             {\r
463                 return getSequenceAt(i);\r
464             }\r
465 \r
466             i++;\r
467         }\r
468 \r
469         return null;\r
470     }\r
471 \r
472 \r
473     /**    */\r
474     public int findIndex(SequenceI s)\r
475     {\r
476         int i = 0;\r
477 \r
478         while (i < sequences.size())\r
479         {\r
480             if (s == getSequenceAt(i))\r
481             {\r
482                 return i;\r
483             }\r
484 \r
485             i++;\r
486         }\r
487 \r
488         return -1;\r
489     }\r
490 \r
491     /**\r
492      * DOCUMENT ME!\r
493      *\r
494      * @return DOCUMENT ME!\r
495      */\r
496     public int getHeight()\r
497     {\r
498         return sequences.size();\r
499     }\r
500 \r
501     /**\r
502      * DOCUMENT ME!\r
503      *\r
504      * @return DOCUMENT ME!\r
505      */\r
506     public int getWidth()\r
507     {\r
508         int maxLength = -1;\r
509 \r
510         for (int i = 0; i < sequences.size(); i++)\r
511         {\r
512             if (getSequenceAt(i).getLength() > maxLength)\r
513             {\r
514                 maxLength = getSequenceAt(i).getLength();\r
515             }\r
516         }\r
517 \r
518         return maxLength;\r
519     }\r
520 \r
521     /**\r
522      * DOCUMENT ME!\r
523      *\r
524      * @return DOCUMENT ME!\r
525      */\r
526     public int getMaxIdLength()\r
527     {\r
528         int max = 0;\r
529         int i = 0;\r
530 \r
531         while (i < sequences.size())\r
532         {\r
533             SequenceI seq = getSequenceAt(i);\r
534             String tmp = seq.getName() + "/" + seq.getStart() + "-" +\r
535                 seq.getEnd();\r
536 \r
537             if (tmp.length() > max)\r
538             {\r
539                 max = tmp.length();\r
540             }\r
541 \r
542             i++;\r
543         }\r
544 \r
545         return max;\r
546     }\r
547 \r
548     /**\r
549      * DOCUMENT ME!\r
550      *\r
551      * @param gc DOCUMENT ME!\r
552      */\r
553     public void setGapCharacter(char gc)\r
554     {\r
555         gapCharacter = gc;\r
556 \r
557         for (int i = 0; i < sequences.size(); i++)\r
558         {\r
559             Sequence seq = (Sequence) sequences.elementAt(i);\r
560             seq.sequence = seq.sequence.replace('.', gc);\r
561             seq.sequence = seq.sequence.replace('-', gc);\r
562             seq.sequence = seq.sequence.replace(' ', gc);\r
563         }\r
564     }\r
565 \r
566     /**\r
567      * DOCUMENT ME!\r
568      *\r
569      * @return DOCUMENT ME!\r
570      */\r
571     public char getGapCharacter()\r
572     {\r
573         return gapCharacter;\r
574     }\r
575 \r
576     /**\r
577      * DOCUMENT ME!\r
578      *\r
579      * @return DOCUMENT ME!\r
580      */\r
581     public Vector getAAFrequency()\r
582     {\r
583         return AAFrequency.calculate(sequences, 0, getWidth());\r
584     }\r
585 \r
586     /**\r
587      * DOCUMENT ME!\r
588      *\r
589      * @return DOCUMENT ME!\r
590      */\r
591     public boolean isAligned()\r
592     {\r
593         int width = getWidth();\r
594 \r
595         for (int i = 0; i < sequences.size(); i++)\r
596         {\r
597             if (getSequenceAt(i).getLength() != width)\r
598             {\r
599                 return false;\r
600             }\r
601         }\r
602 \r
603         return true;\r
604     }\r
605 \r
606     /**\r
607      * DOCUMENT ME!\r
608      *\r
609      * @param aa DOCUMENT ME!\r
610      */\r
611     public void deleteAnnotation(AlignmentAnnotation aa)\r
612     {\r
613         int aSize = 1;\r
614 \r
615         if (annotations != null)\r
616         {\r
617             aSize = annotations.length;\r
618         }\r
619 \r
620         AlignmentAnnotation[] temp = new AlignmentAnnotation[aSize - 1];\r
621 \r
622         int tIndex = 0;\r
623 \r
624         for (int i = 0; i < aSize; i++)\r
625         {\r
626             if (annotations[i] == aa)\r
627             {\r
628                 continue;\r
629             }\r
630 \r
631             temp[tIndex] = annotations[i];\r
632             tIndex++;\r
633         }\r
634 \r
635         annotations = temp;\r
636     }\r
637 \r
638     /**\r
639      * DOCUMENT ME!\r
640      *\r
641      * @param aa DOCUMENT ME!\r
642      */\r
643     public void addAnnotation(AlignmentAnnotation aa)\r
644     {\r
645         int aSize = 1;\r
646 \r
647         if (annotations != null)\r
648         {\r
649             aSize = annotations.length + 1;\r
650         }\r
651 \r
652 \r
653         AlignmentAnnotation[] temp = new AlignmentAnnotation[aSize];\r
654         int i = 0;\r
655 \r
656         if (aSize > 1)\r
657         {\r
658             for (i = 0; i < (aSize - 1); i++)\r
659             {\r
660                 temp[i] = annotations[i];\r
661             }\r
662         }\r
663 \r
664         temp[i] = aa;\r
665 \r
666         annotations = temp;\r
667     }\r
668 \r
669     /**\r
670      * DOCUMENT ME!\r
671      *\r
672      * @return DOCUMENT ME!\r
673      */\r
674     public AlignmentAnnotation[] getAlignmentAnnotation()\r
675     {\r
676         return annotations;\r
677     }\r
678 \r
679     public void setNucleotide(boolean b)\r
680     {\r
681       if(b)\r
682         type = NUCLEOTIDE;\r
683       else\r
684         type = PROTEIN;\r
685     }\r
686 \r
687     public boolean isNucleotide()\r
688     {\r
689       if(type==NUCLEOTIDE)\r
690         return true;\r
691       else\r
692         return false;\r
693     }\r
694 \r
695     public void setDataset(Alignment data)\r
696     {\r
697       if(dataset==null && data==null)\r
698       {\r
699         // Create a new dataset for this alignment.\r
700         // Can only be done once, if dataset is not null\r
701         // This will not be performed\r
702         Sequence[] seqs = new Sequence[getHeight()];\r
703         for (int i = 0; i < getHeight(); i++)\r
704         {\r
705 \r
706           seqs[i] = new Sequence(getSequenceAt(i).getDisplayId(true),\r
707                                  AlignSeq.extractGaps(\r
708                                      jalview.util.Comparison.GapChars,\r
709                                      getSequenceAt(i).getSequence()\r
710                                  ),\r
711                                  getSequenceAt(i).getStart(),\r
712                                  getSequenceAt(i).getEnd());\r
713 \r
714           getSequenceAt(i).setDatasetSequence(seqs[i]);\r
715         }\r
716 \r
717         dataset = new Alignment(seqs);\r
718       }\r
719       else if(dataset==null && data!=null)\r
720       {\r
721         dataset = data;\r
722       }\r
723     }\r
724 \r
725     public Alignment getDataset()\r
726     {\r
727       return dataset;\r
728     }\r
729 \r
730     public void setProvenance(Provenance prov)\r
731     {\r
732       provenance = prov;\r
733     }\r
734     public Provenance getProvenance()\r
735     {\r
736       return provenance;\r
737     }\r
738 }\r