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