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