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