3bdb65fa0a2cdd616127813eb0d0abaa690a15ca
[jalview.git] / src / jalview / datamodel / SequenceGroup.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)
3  * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.datamodel;
20
21 import java.util.*;
22
23 import java.awt.*;
24
25 import jalview.analysis.*;
26 import jalview.schemes.*;
27
28 /**
29  * Collects a set contiguous ranges on a set of sequences
30  * 
31  * @author $author$
32  * @version $Revision$
33  */
34 public class SequenceGroup
35 {
36   String groupName;
37
38   String description;
39
40   Conservation conserve;
41
42   Vector aaFrequency;
43
44   boolean displayBoxes = true;
45
46   boolean displayText = true;
47
48   boolean colourText = false;
49   /**
50    * after Olivier's non-conserved only character display
51    */
52   boolean showUnconserved = false;
53   
54   /**
55    * group members
56    */
57   private Vector sequences = new Vector();
58   /**
59    * representative sequence for this group (if any)
60    */
61   private SequenceI seqrep = null;
62   int width = -1;
63
64   /**
65    * Colourscheme applied to group if any */
66   public ColourSchemeI cs;
67
68   int startRes = 0;
69
70   int endRes = 0;
71
72   public Color outlineColour = Color.black;
73
74   public Color idColour = null;
75
76   public int thresholdTextColour = 0;
77
78   public Color textColour = Color.black;
79
80   public Color textColour2 = Color.white;
81
82   /**
83    * consensus calculation property
84    */
85   private boolean ignoreGapsInConsensus=true;
86   /**
87    * consensus calculation property
88    */
89   private boolean includeAllConsSymbols=false;
90
91   /**
92    * @return the includeAllConsSymbols
93    */
94   public boolean isIncludeAllConsSymbols()
95   {
96     return includeAllConsSymbols;
97   }
98
99
100   /**
101    * Creates a new SequenceGroup object.
102    */
103   public SequenceGroup()
104   {
105     groupName = "JGroup:" + this.hashCode();
106   }
107
108   /**
109    * Creates a new SequenceGroup object.
110    * 
111    * @param sequences
112    * @param groupName
113    * @param scheme
114    * @param displayBoxes
115    * @param displayText
116    * @param colourText
117    * @param start
118    *                first column of group
119    * @param end
120    *                last column of group
121    */
122   public SequenceGroup(Vector sequences, String groupName,
123           ColourSchemeI scheme, boolean displayBoxes, boolean displayText,
124           boolean colourText, int start, int end)
125   {
126     this.sequences = sequences;
127     this.groupName = groupName;
128     this.displayBoxes = displayBoxes;
129     this.displayText = displayText;
130     this.colourText = colourText;
131     this.cs = scheme;
132     startRes = start;
133     endRes = end;
134     recalcConservation();
135   }
136   /**
137    * copy constructor
138    * @param seqsel
139    */
140   public SequenceGroup(SequenceGroup seqsel)
141   {
142     if (seqsel!=null)
143     {
144       sequences=new Vector();
145       Enumeration sq = seqsel.sequences.elements();
146       while (sq.hasMoreElements()) { 
147         sequences.addElement(sq.nextElement()); 
148       };
149       if (seqsel.groupName!=null)
150       {
151         groupName = new String(seqsel.groupName);
152       }
153       displayBoxes = seqsel.displayBoxes;
154       displayText = seqsel.displayText;
155       colourText = seqsel.colourText;
156       startRes = seqsel.startRes;
157       endRes = seqsel.endRes;
158       cs =seqsel.cs;
159       if (seqsel.description!=null)
160         description = new String(seqsel.description);
161       hidecols = seqsel.hidecols;
162       hidereps = seqsel.hidereps;
163       idColour = seqsel.idColour;
164       outlineColour = seqsel.outlineColour;
165       seqrep = seqsel.seqrep;
166       textColour = seqsel.textColour;
167       textColour2 = seqsel.textColour2;
168       thresholdTextColour = seqsel.thresholdTextColour;
169       width = seqsel.width;
170       ignoreGapsInConsensus = seqsel.ignoreGapsInConsensus;
171       if (seqsel.conserve!=null)
172       {
173         recalcConservation(); // safer than 
174         // aaFrequency = (Vector) seqsel.aaFrequency.clone(); // ??
175       }
176     }
177   }
178
179   public SequenceI[] getSelectionAsNewSequences(AlignmentI align)
180   {
181     int iSize = sequences.size();
182     SequenceI[] seqs = new SequenceI[iSize];
183     SequenceI[] inorder = getSequencesInOrder(align);
184
185     for (int i = 0, ipos = 0; i < inorder.length; i++)
186     {
187       SequenceI seq = inorder[i];
188
189       seqs[ipos] = seq.getSubSequence(startRes, endRes + 1);
190       if (seqs[ipos] != null)
191       {
192         seqs[ipos].setDescription(seq.getDescription());
193         seqs[ipos].setDBRef(seq.getDBRef());
194         seqs[ipos].setSequenceFeatures(seq.getSequenceFeatures());
195         if (seq.getDatasetSequence() != null)
196         {
197           seqs[ipos].setDatasetSequence(seq.getDatasetSequence());
198         }
199
200         if (seq.getAnnotation() != null)
201         {
202           AlignmentAnnotation[] alann = align.getAlignmentAnnotation();
203           // Only copy annotation that is either a score or referenced by the
204           // alignment's annotation vector
205           for (int a = 0; a < seq.getAnnotation().length; a++)
206           {
207             AlignmentAnnotation tocopy = seq.getAnnotation()[a];
208             if (alann != null)
209             {
210               boolean found = false;
211               for (int pos = 0; pos < alann.length; pos++)
212               {
213                 if (alann[pos] == tocopy)
214                 {
215                   found = true;
216                   break;
217                 }
218               }
219               if (!found)
220                 continue;
221             }
222             AlignmentAnnotation newannot = new AlignmentAnnotation(seq
223                     .getAnnotation()[a]);
224             newannot.restrict(startRes, endRes);
225             newannot.setSequenceRef(seqs[ipos]);
226             newannot.adjustForAlignment();
227             seqs[ipos].addAlignmentAnnotation(newannot);
228           }
229         }
230         ipos++;
231       }
232       else
233       {
234         iSize--;
235       }
236     }
237     if (iSize != inorder.length)
238     {
239       SequenceI[] nseqs = new SequenceI[iSize];
240       System.arraycopy(seqs, 0, nseqs, 0, iSize);
241       seqs = nseqs;
242     }
243     return seqs;
244
245   }
246
247   /**
248    * If sequence ends in gaps, the end residue can be correctly calculated here
249    * 
250    * @param seq
251    *                SequenceI
252    * @return int
253    */
254   public int findEndRes(SequenceI seq)
255   {
256     int eres = 0;
257     char ch;
258
259     for (int j = 0; j < endRes + 1 && j < seq.getLength(); j++)
260     {
261       ch = seq.getCharAt(j);
262       if (!jalview.util.Comparison.isGap((ch)))
263       {
264         eres++;
265       }
266     }
267
268     if (eres > 0)
269     {
270       eres += seq.getStart() - 1;
271     }
272
273     return eres;
274   }
275
276   public Vector getSequences(Hashtable hiddenReps)
277   {
278     if (hiddenReps == null)
279     {
280       return sequences;
281     }
282     else
283     {
284       Vector allSequences = new Vector();
285       SequenceI seq, seq2;
286       for (int i = 0; i < sequences.size(); i++)
287       {
288         seq = (SequenceI) sequences.elementAt(i);
289         allSequences.addElement(seq);
290         if (hiddenReps.containsKey(seq))
291         {
292           SequenceGroup hsg = (SequenceGroup) hiddenReps.get(seq);
293           for (int h = 0; h < hsg.getSize(); h++)
294           {
295             seq2 = hsg.getSequenceAt(h);
296             if (seq2 != seq && !allSequences.contains(seq2))
297             {
298               allSequences.addElement(seq2);
299             }
300           }
301         }
302       }
303
304       return allSequences;
305     }
306   }
307
308   public SequenceI[] getSequencesAsArray(Hashtable hiddenReps)
309   {
310     Vector tmp = getSequences(hiddenReps);
311     if (tmp == null)
312     {
313       return null;
314     }
315     SequenceI[] result = new SequenceI[tmp.size()];
316     for (int i = 0; i < result.length; i++)
317     {
318       result[i] = (SequenceI) tmp.elementAt(i);
319     }
320
321     return result;
322   }
323
324   /**
325    * DOCUMENT ME!
326    * 
327    * @param col
328    *                DOCUMENT ME!
329    * 
330    * @return DOCUMENT ME!
331    */
332   public boolean adjustForRemoveLeft(int col)
333   {
334     // return value is true if the group still exists
335     if (startRes >= col)
336     {
337       startRes = startRes - col;
338     }
339
340     if (endRes >= col)
341     {
342       endRes = endRes - col;
343
344       if (startRes > endRes)
345       {
346         startRes = 0;
347       }
348     }
349     else
350     {
351       // must delete this group!!
352       return false;
353     }
354
355     return true;
356   }
357
358   /**
359    * DOCUMENT ME!
360    * 
361    * @param col
362    *                DOCUMENT ME!
363    * 
364    * @return DOCUMENT ME!
365    */
366   public boolean adjustForRemoveRight(int col)
367   {
368     if (startRes > col)
369     {
370       // delete this group
371       return false;
372     }
373
374     if (endRes >= col)
375     {
376       endRes = col;
377     }
378
379     return true;
380   }
381
382   /**
383    * DOCUMENT ME!
384    * 
385    * @return DOCUMENT ME!
386    */
387   public String getName()
388   {
389     return groupName;
390   }
391
392   public String getDescription()
393   {
394     return description;
395   }
396
397   /**
398    * DOCUMENT ME!
399    * 
400    * @param name
401    *                DOCUMENT ME!
402    */
403   public void setName(String name)
404   {
405     groupName = name;
406     // TODO: URGENT: update dependent objects (annotation row)
407   }
408
409   public void setDescription(String desc)
410   {
411     description = desc;
412   }
413
414   /**
415    * DOCUMENT ME!
416    * 
417    * @return DOCUMENT ME!
418    */
419   public Conservation getConservation()
420   {
421     return conserve;
422   }
423
424   /**
425    * DOCUMENT ME!
426    * 
427    * @param c
428    *                DOCUMENT ME!
429    */
430   public void setConservation(Conservation c)
431   {
432     conserve = c;
433   }
434
435   /**
436    * Add s to this sequence group
437    * 
438    * @param s
439    *                alignment sequence to be added
440    * @param recalc
441    *                true means Group's conservation should be recalculated
442    */
443   public void addSequence(SequenceI s, boolean recalc)
444   {
445     if (s != null && !sequences.contains(s))
446     {
447       sequences.addElement(s);
448     }
449
450     if (recalc)
451     {
452       recalcConservation();
453     }
454   }
455
456   /**
457    * calculate residue conservation for group - but only if necessary.
458    */
459   public void recalcConservation()
460   {
461     if (cs == null && consensus == null && conservation == null)
462     {
463       return;
464     }
465     
466     try
467     {
468       Hashtable cnsns[] = AAFrequency.calculate(sequences, startRes, endRes + 1, includeAllConsSymbols);
469       if (consensus != null)
470       {
471         _updateConsensusRow(cnsns);
472       }
473       if (cs!=null)
474       {
475         cs.setConsensus(cnsns);
476       
477       if (cs instanceof ClustalxColourScheme)
478       {
479         ((ClustalxColourScheme) cs).resetClustalX(sequences, getWidth());
480       }
481       }
482
483       if ((conservation!=null) || (cs!=null && cs.conservationApplied()))
484       {
485         Conservation c = new Conservation(groupName,
486                 ResidueProperties.propHash, 3, sequences, startRes,
487                 endRes + 1);
488         c.calculate();
489         c.verdict(false, 25);
490         if (conservation!=null)
491         {
492           _updateConservationRow(c);
493         }
494         if (cs!=null)
495         {
496           cs.setConservation(c);
497         
498         if (cs instanceof ClustalxColourScheme)
499         {
500           ((ClustalxColourScheme) cs).resetClustalX(sequences, getWidth());
501         }
502         }
503       }
504     } catch (java.lang.OutOfMemoryError err)
505     {
506       // TODO: catch OOM
507       System.out.println("Out of memory loading groups: " + err);
508     }
509
510   }
511
512   private void _updateConservationRow(Conservation c)
513   {
514     if (conservation==null)
515     {
516       getConservation();
517     }
518     // preserve width if already set
519     int aWidth = (conservation.annotations!=null) ? (endRes<conservation.annotations.length ? conservation.annotations.length : endRes+1) : endRes+1;
520     conservation.annotations = null;
521     conservation.annotations = new Annotation[aWidth]; // should be alignment width
522     c.completeAnnotations(conservation,null, startRes, endRes+1);
523   }
524   public Hashtable[] consensusData = null;
525   private void _updateConsensusRow(Hashtable[] cnsns)
526   {
527     if (consensus==null)
528     {
529       getConsensus();
530     }
531     consensusData = cnsns;
532     // preserve width if already set
533     int aWidth = (consensus.annotations!=null) ? (endRes<consensus.annotations.length ? consensus.annotations.length : endRes+1) : endRes+1;
534     consensus.annotations = null;
535     consensus.annotations = new Annotation[aWidth]; // should be alignment width
536
537     AAFrequency.completeConsensus(consensus,cnsns,startRes,endRes+1,ignoreGapsInConsensus, includeAllConsSymbols); // TODO: setting container for ignoreGapsInConsensusCalculation);
538   }
539
540   /**
541    * @param s sequence to either add or remove from group
542    * @param recalc flag passed to delete/addSequence to indicate if group properties should be recalculated
543    */
544   public void addOrRemove(SequenceI s, boolean recalc)
545   {
546     if (sequences.contains(s))
547     {
548       deleteSequence(s, recalc);
549     }
550     else
551     {
552       addSequence(s, recalc);
553     }
554   }
555
556   /**
557    * DOCUMENT ME!
558    * 
559    * @param s
560    *                DOCUMENT ME!
561    * @param recalc
562    *                DOCUMENT ME!
563    */
564   public void deleteSequence(SequenceI s, boolean recalc)
565   {
566     sequences.removeElement(s);
567
568     if (recalc)
569     {
570       recalcConservation();
571     }
572   }
573
574   /**
575    * DOCUMENT ME!
576    * 
577    * @return DOCUMENT ME!
578    */
579   public int getStartRes()
580   {
581     return startRes;
582   }
583
584   /**
585    * DOCUMENT ME!
586    * 
587    * @return DOCUMENT ME!
588    */
589   public int getEndRes()
590   {
591     return endRes;
592   }
593
594   /**
595    * DOCUMENT ME!
596    * 
597    * @param i
598    *                DOCUMENT ME!
599    */
600   public void setStartRes(int i)
601   {
602     startRes = i;
603   }
604
605   /**
606    * DOCUMENT ME!
607    * 
608    * @param i
609    *                DOCUMENT ME!
610    */
611   public void setEndRes(int i)
612   {
613     endRes = i;
614   }
615
616   /**
617    * DOCUMENT ME!
618    * 
619    * @return DOCUMENT ME!
620    */
621   public int getSize()
622   {
623     return sequences.size();
624   }
625
626   /**
627    * DOCUMENT ME!
628    * 
629    * @param i
630    *                DOCUMENT ME!
631    * 
632    * @return DOCUMENT ME!
633    */
634   public SequenceI getSequenceAt(int i)
635   {
636     return (SequenceI) sequences.elementAt(i);
637   }
638
639   /**
640    * DOCUMENT ME!
641    * 
642    * @param state
643    *                DOCUMENT ME!
644    */
645   public void setColourText(boolean state)
646   {
647     colourText = state;
648   }
649
650   /**
651    * DOCUMENT ME!
652    * 
653    * @return DOCUMENT ME!
654    */
655   public boolean getColourText()
656   {
657     return colourText;
658   }
659
660   /**
661    * DOCUMENT ME!
662    * 
663    * @param state
664    *                DOCUMENT ME!
665    */
666   public void setDisplayText(boolean state)
667   {
668     displayText = state;
669   }
670
671   /**
672    * DOCUMENT ME!
673    * 
674    * @return DOCUMENT ME!
675    */
676   public boolean getDisplayText()
677   {
678     return displayText;
679   }
680
681   /**
682    * DOCUMENT ME!
683    * 
684    * @param state
685    *                DOCUMENT ME!
686    */
687   public void setDisplayBoxes(boolean state)
688   {
689     displayBoxes = state;
690   }
691
692   /**
693    * DOCUMENT ME!
694    * 
695    * @return DOCUMENT ME!
696    */
697   public boolean getDisplayBoxes()
698   {
699     return displayBoxes;
700   }
701
702   /**
703    * DOCUMENT ME!
704    * 
705    * @return DOCUMENT ME!
706    */
707   public int getWidth()
708   {
709     // MC This needs to get reset when characters are inserted and deleted
710     if (sequences.size() > 0)
711     {
712       width = ((SequenceI) sequences.elementAt(0)).getLength();
713     }
714
715     for (int i = 1; i < sequences.size(); i++)
716     {
717       SequenceI seq = (SequenceI) sequences.elementAt(i);
718
719       if (seq.getLength() > width)
720       {
721         width = seq.getLength();
722       }
723     }
724
725     return width;
726   }
727
728   /**
729    * DOCUMENT ME!
730    * 
731    * @param c
732    *                DOCUMENT ME!
733    */
734   public void setOutlineColour(Color c)
735   {
736     outlineColour = c;
737   }
738
739   /**
740    * DOCUMENT ME!
741    * 
742    * @return DOCUMENT ME!
743    */
744   public Color getOutlineColour()
745   {
746     return outlineColour;
747   }
748
749   /**
750    * 
751    * returns the sequences in the group ordered by the ordering given by al.
752    * this used to return an array with null entries regardless, new behaviour is below.
753    * TODO: verify that this does not affect use in applet or application
754    * @param al
755    *                Alignment
756    * @return SequenceI[] intersection of sequences in group with al, ordered by al, or null if group does not intersect with al
757    */
758   public SequenceI[] getSequencesInOrder(AlignmentI al)
759   {
760     int sSize = sequences.size();
761     int alHeight = al.getHeight();
762
763     SequenceI[] seqs = new SequenceI[sSize];
764
765     int index = 0;
766     for (int i = 0; i < alHeight && index < sSize; i++)
767     {
768       if (sequences.contains(al.getSequenceAt(i)))
769       {
770         seqs[index++] = al.getSequenceAt(i);
771       }
772     }
773     if (index==0)
774     {
775       return null;
776     }
777     if (index<seqs.length)
778     {
779       SequenceI[] dummy = seqs;
780       seqs = new SequenceI[index];
781       while (--index>=0)
782       {
783         seqs[index] = dummy[index];
784         dummy[index] = null;
785       }
786     }
787     return seqs;
788   }
789
790   /**
791    * @return the idColour
792    */
793   public Color getIdColour()
794   {
795     return idColour;
796   }
797
798   /**
799    * @param idColour
800    *                the idColour to set
801    */
802   public void setIdColour(Color idColour)
803   {
804     this.idColour = idColour;
805   }
806
807   /**
808    * @return the representative sequence for this group
809    */
810   public SequenceI getSeqrep()
811   {
812     return seqrep;
813   }
814
815   /**
816    * set the representative sequence for this group.
817    * Note - this affects the interpretation of the Hidereps attribute.
818    * @param seqrep the seqrep to set (null means no sequence representative)
819    */
820   public void setSeqrep(SequenceI seqrep)
821   {
822     this.seqrep = seqrep;
823   }
824   /**
825    * 
826    * @return true if group has a sequence representative
827    */
828   public boolean hasSeqrep()
829   {
830     return seqrep != null;
831   }
832   /**
833    * visibility of rows or represented rows covered by group
834    */
835   private boolean hidereps=false;
836   /**
837    * set visibility of sequences covered by (if no sequence representative is defined) 
838    * or represented by this group.
839    * @param visibility
840    */
841   public void setHidereps(boolean visibility)
842   {
843     hidereps = visibility;
844   }
845   /**
846    * 
847    * @return true if sequences represented (or covered) by this group should be hidden
848    */
849   public boolean isHidereps()
850   {
851     return hidereps;
852   }
853   /**
854    * visibility of columns intersecting this group
855    */
856   private boolean hidecols=false;
857   /**
858    * set intended visibility of columns covered by this group
859    * @param visibility
860    */
861   public void setHideCols(boolean visibility)
862   {
863     hidecols = visibility;
864   }
865   /**
866    * 
867    * @return true if columns covered by group should be hidden
868    */
869   public boolean isHideCols()
870   {
871     return hidecols;
872   }
873   /**
874    * create a new sequence group from the intersection of this group
875    * with an alignment Hashtable of hidden representatives
876    * 
877    * @param alignment (may not be null)
878    * @param hashtable (may be null)
879    * @return new group containing sequences common to this group and alignment
880    */
881   public SequenceGroup intersect(AlignmentI alignment, Hashtable hashtable)
882   {
883     SequenceGroup sgroup = new SequenceGroup(this);
884     SequenceI[] insect=getSequencesInOrder(alignment);
885     sgroup.sequences = new Vector();
886     for (int s=0;insect!=null && s<insect.length;s++) { 
887       if (hashtable==null || hashtable.containsKey(insect[s]))
888               {
889       sgroup.sequences.addElement(insect[s]); }
890     }
891     //Enumeration en =getSequences(hashtable).elements();
892     //while (en.hasMoreElements())
893    // {
894    //   SequenceI elem = (SequenceI) en.nextElement();
895    //   if (alignment.getSequences().contains(elem))
896    //   {
897    //     sgroup.addSequence(elem, false);
898    //   }
899    // }
900     return sgroup;
901   }
902
903   /**
904    * @return the showUnconserved
905    */
906   public boolean getShowunconserved()
907   {
908     return showUnconserved;
909   }
910
911   /**
912    * @param showUnconserved the showUnconserved to set
913    */
914   public void setShowunconserved(boolean displayNonconserved)
915   {
916     this.showUnconserved = displayNonconserved;
917   }
918   AlignmentAnnotation consensus=null,conservation=null;
919   /**
920    * 
921    * @return automatically calculated consensus row
922    */
923   public AlignmentAnnotation getConsensus()
924   {
925     // TODO get or calculate and get consensus annotation row for this group
926     int aWidth = this.getWidth();
927     // pointer
928     // possibility
929     // here.
930     if (aWidth < 0)
931     {
932       return null;
933     }
934     if (consensus==null)
935     {
936        consensus = new AlignmentAnnotation("Consensus for "+getName(), "PID",
937               new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
938       consensus.hasText = true;
939       consensus.autoCalculated = true;
940       consensus.groupRef = this;
941     }
942     return consensus;
943   }
944     /**
945    * get the conservation annotation row for this group
946    * @return autoCalculated annotation row
947    */
948   public AlignmentAnnotation getConservationRow() {
949     int ConsPercGaps = 25;
950     if (conservation == null) {
951       conservation = new AlignmentAnnotation("Conservation for "+getName(),
952             "Conservation for group "+getName()+" less than " + ConsPercGaps
953                     + "% gaps", new Annotation[1], 0f, 11f,
954             AlignmentAnnotation.BAR_GRAPH);
955     conservation.hasText = true;
956     conservation.autoCalculated = true;
957     conservation.groupRef = this;
958       }
959     
960     return conservation;
961   }
962
963   /**
964    * 
965    * @return true if annotation rows have been instantiated for this group
966    */
967     public boolean hasAnnotationRows()
968     {
969       return consensus!=null || conservation!=null;
970     }
971
972   public SequenceI getConsensusSeq()
973   {
974     getConsensus();
975     StringBuffer seqs = new StringBuffer();
976     for (int i = 0; i < consensus.annotations.length; i++)
977     {
978       if (consensus.annotations[i] != null)
979       {
980         if (consensus.annotations[i].description.charAt(0) == '[')
981         {
982           seqs.append(consensus.annotations[i].description.charAt(1));
983         }
984         else
985         {
986           seqs.append(consensus.annotations[i].displayCharacter);
987         }
988       }
989     }
990
991     SequenceI sq = new Sequence("Group"+getName()+" Consensus", seqs.toString());
992     sq.setDescription("Percentage Identity Consensus "
993             + ((ignoreGapsInConsensus) ? " without gaps" : ""));
994     return sq;    
995   }
996
997   public void setIgnoreGapsConsensus(boolean state)
998   {
999     if (this.ignoreGapsInConsensus!=state && consensus!=null)
1000     {
1001       ignoreGapsInConsensus = state;
1002       recalcConservation();
1003     }
1004     ignoreGapsInConsensus = state;
1005   }
1006   public boolean getIgnoreGapsConsensus()
1007   {
1008     return ignoreGapsInConsensus;
1009   }
1010   /**
1011    * @param includeAllConsSymbols the includeAllConsSymbols to set
1012    */
1013   public void setIncludeAllConsSymbols(boolean includeAllConsSymbols)
1014   {
1015     if (this.includeAllConsSymbols!=includeAllConsSymbols && consensus!=null) {
1016       this.includeAllConsSymbols = includeAllConsSymbols;
1017       recalcConservation();
1018     }
1019     this.includeAllConsSymbols = includeAllConsSymbols;
1020   }
1021 }