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
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.
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.
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
19 package jalview.datamodel;
25 import jalview.analysis.*;
26 import jalview.schemes.*;
29 * Collects a set contiguous ranges on a set of sequences
34 public class SequenceGroup
40 Conservation conserve;
44 boolean displayBoxes = true;
46 boolean displayText = true;
48 boolean colourText = false;
50 * after Olivier's non-conserved only character display
52 boolean showUnconserved = false;
57 private Vector sequences = new Vector();
59 * representative sequence for this group (if any)
61 private SequenceI seqrep = null;
65 * Colourscheme applied to group if any */
66 public ColourSchemeI cs;
72 public Color outlineColour = Color.black;
74 public Color idColour = null;
76 public int thresholdTextColour = 0;
78 public Color textColour = Color.black;
80 public Color textColour2 = Color.white;
82 private boolean ignoreGapsInConsensusCalculation=true;
85 * Creates a new SequenceGroup object.
87 public SequenceGroup()
89 groupName = "JGroup:" + this.hashCode();
93 * Creates a new SequenceGroup object.
102 * first column of group
104 * last column of group
106 public SequenceGroup(Vector sequences, String groupName,
107 ColourSchemeI scheme, boolean displayBoxes, boolean displayText,
108 boolean colourText, int start, int end)
110 this.sequences = sequences;
111 this.groupName = groupName;
112 this.displayBoxes = displayBoxes;
113 this.displayText = displayText;
114 this.colourText = colourText;
118 recalcConservation();
124 public SequenceGroup(SequenceGroup seqsel)
128 sequences=new Vector();
129 Enumeration sq = seqsel.sequences.elements();
130 while (sq.hasMoreElements()) {
131 sequences.addElement(sq.nextElement());
133 if (seqsel.groupName!=null)
135 groupName = new String(seqsel.groupName);
137 displayBoxes = seqsel.displayBoxes;
138 displayText = seqsel.displayText;
139 colourText = seqsel.colourText;
140 startRes = seqsel.startRes;
141 endRes = seqsel.endRes;
143 if (seqsel.description!=null)
144 description = new String(seqsel.description);
145 hidecols = seqsel.hidecols;
146 hidereps = seqsel.hidereps;
147 idColour = seqsel.idColour;
148 outlineColour = seqsel.outlineColour;
149 seqrep = seqsel.seqrep;
150 textColour = seqsel.textColour;
151 textColour2 = seqsel.textColour2;
152 thresholdTextColour = seqsel.thresholdTextColour;
153 width = seqsel.width;
154 ignoreGapsInConsensusCalculation = seqsel.ignoreGapsInConsensusCalculation;
155 if (seqsel.conserve!=null)
157 recalcConservation(); // safer than
158 // aaFrequency = (Vector) seqsel.aaFrequency.clone(); // ??
163 public SequenceI[] getSelectionAsNewSequences(AlignmentI align)
165 int iSize = sequences.size();
166 SequenceI[] seqs = new SequenceI[iSize];
167 SequenceI[] inorder = getSequencesInOrder(align);
169 for (int i = 0, ipos = 0; i < inorder.length; i++)
171 SequenceI seq = inorder[i];
173 seqs[ipos] = seq.getSubSequence(startRes, endRes + 1);
174 if (seqs[ipos] != null)
176 seqs[ipos].setDescription(seq.getDescription());
177 seqs[ipos].setDBRef(seq.getDBRef());
178 seqs[ipos].setSequenceFeatures(seq.getSequenceFeatures());
179 if (seq.getDatasetSequence() != null)
181 seqs[ipos].setDatasetSequence(seq.getDatasetSequence());
184 if (seq.getAnnotation() != null)
186 AlignmentAnnotation[] alann = align.getAlignmentAnnotation();
187 // Only copy annotation that is either a score or referenced by the
188 // alignment's annotation vector
189 for (int a = 0; a < seq.getAnnotation().length; a++)
191 AlignmentAnnotation tocopy = seq.getAnnotation()[a];
194 boolean found = false;
195 for (int pos = 0; pos < alann.length; pos++)
197 if (alann[pos] == tocopy)
206 AlignmentAnnotation newannot = new AlignmentAnnotation(seq
207 .getAnnotation()[a]);
208 newannot.restrict(startRes, endRes);
209 newannot.setSequenceRef(seqs[ipos]);
210 newannot.adjustForAlignment();
211 seqs[ipos].addAlignmentAnnotation(newannot);
221 if (iSize != inorder.length)
223 SequenceI[] nseqs = new SequenceI[iSize];
224 System.arraycopy(seqs, 0, nseqs, 0, iSize);
232 * If sequence ends in gaps, the end residue can be correctly calculated here
238 public int findEndRes(SequenceI seq)
243 for (int j = 0; j < endRes + 1 && j < seq.getLength(); j++)
245 ch = seq.getCharAt(j);
246 if (!jalview.util.Comparison.isGap((ch)))
254 eres += seq.getStart() - 1;
260 public Vector getSequences(Hashtable hiddenReps)
262 if (hiddenReps == null)
268 Vector allSequences = new Vector();
270 for (int i = 0; i < sequences.size(); i++)
272 seq = (SequenceI) sequences.elementAt(i);
273 allSequences.addElement(seq);
274 if (hiddenReps.containsKey(seq))
276 SequenceGroup hsg = (SequenceGroup) hiddenReps.get(seq);
277 for (int h = 0; h < hsg.getSize(); h++)
279 seq2 = hsg.getSequenceAt(h);
280 if (seq2 != seq && !allSequences.contains(seq2))
282 allSequences.addElement(seq2);
292 public SequenceI[] getSequencesAsArray(Hashtable hiddenReps)
294 Vector tmp = getSequences(hiddenReps);
299 SequenceI[] result = new SequenceI[tmp.size()];
300 for (int i = 0; i < result.length; i++)
302 result[i] = (SequenceI) tmp.elementAt(i);
314 * @return DOCUMENT ME!
316 public boolean adjustForRemoveLeft(int col)
318 // return value is true if the group still exists
321 startRes = startRes - col;
326 endRes = endRes - col;
328 if (startRes > endRes)
335 // must delete this group!!
348 * @return DOCUMENT ME!
350 public boolean adjustForRemoveRight(int col)
369 * @return DOCUMENT ME!
371 public String getName()
376 public String getDescription()
387 public void setName(String name)
392 public void setDescription(String desc)
400 * @return DOCUMENT ME!
402 public Conservation getConservation()
413 public void setConservation(Conservation c)
419 * Add s to this sequence group
422 * alignment sequence to be added
424 * true means Group's conservation should be recalculated
426 public void addSequence(SequenceI s, boolean recalc)
428 if (s != null && !sequences.contains(s))
430 sequences.addElement(s);
435 recalcConservation();
440 * calculate residue conservation for group
442 public void recalcConservation()
444 if (cs == null && consensus == null && conservation == null)
451 Hashtable cnsns[] = AAFrequency.calculate(sequences, startRes, endRes + 1);
452 if (consensus != null)
454 _updateConsensusRow(cnsns);
458 cs.setConsensus(cnsns);
460 if (cs instanceof ClustalxColourScheme)
462 ((ClustalxColourScheme) cs).resetClustalX(sequences, getWidth());
466 if ((conservation!=null) || (cs!=null && cs.conservationApplied()))
468 Conservation c = new Conservation(groupName,
469 ResidueProperties.propHash, 3, sequences, startRes,
472 c.verdict(false, 25);
473 if (conservation!=null)
475 _updateConservationRow(c);
479 cs.setConservation(c);
481 if (cs instanceof ClustalxColourScheme)
483 ((ClustalxColourScheme) cs).resetClustalX(sequences, getWidth());
487 } catch (java.lang.OutOfMemoryError err)
490 System.out.println("Out of memory loading groups: " + err);
495 private void _updateConservationRow(Conservation c)
497 if (conservation==null)
501 // preserve width if already set
502 int aWidth = (conservation.annotations!=null) ? (endRes<conservation.annotations.length ? conservation.annotations.length : endRes+1) : endRes+1;
503 c.completeAnnotations(conservation,null, aWidth);
506 private void _updateConsensusRow(Hashtable[] cnsns)
512 // preserve width if already set
513 int aWidth = (consensus.annotations!=null) ? (endRes<consensus.annotations.length ? consensus.annotations.length : endRes+1) : endRes+1;
514 consensus.annotations = null;
515 consensus.annotations = new Annotation[aWidth]; // should be alignment width
517 AAFrequency.completeConsensus(consensus,cnsns,startRes,endRes,ignoreGapsInConsensusCalculation); // TODO: setting container for ignoreGapsInConsensusCalculation);
528 public void addOrRemove(SequenceI s, boolean recalc)
530 if (sequences.contains(s))
532 deleteSequence(s, recalc);
536 addSequence(s, recalc);
548 public void deleteSequence(SequenceI s, boolean recalc)
550 sequences.removeElement(s);
554 recalcConservation();
561 * @return DOCUMENT ME!
563 public int getStartRes()
571 * @return DOCUMENT ME!
573 public int getEndRes()
584 public void setStartRes(int i)
595 public void setEndRes(int i)
603 * @return DOCUMENT ME!
607 return sequences.size();
616 * @return DOCUMENT ME!
618 public SequenceI getSequenceAt(int i)
620 return (SequenceI) sequences.elementAt(i);
629 public void setColourText(boolean state)
637 * @return DOCUMENT ME!
639 public boolean getColourText()
650 public void setDisplayText(boolean state)
658 * @return DOCUMENT ME!
660 public boolean getDisplayText()
671 public void setDisplayBoxes(boolean state)
673 displayBoxes = state;
679 * @return DOCUMENT ME!
681 public boolean getDisplayBoxes()
689 * @return DOCUMENT ME!
691 public int getWidth()
693 // MC This needs to get reset when characters are inserted and deleted
694 if (sequences.size() > 0)
696 width = ((SequenceI) sequences.elementAt(0)).getLength();
699 for (int i = 1; i < sequences.size(); i++)
701 SequenceI seq = (SequenceI) sequences.elementAt(i);
703 if (seq.getLength() > width)
705 width = seq.getLength();
718 public void setOutlineColour(Color c)
726 * @return DOCUMENT ME!
728 public Color getOutlineColour()
730 return outlineColour;
735 * returns the sequences in the group ordered by the ordering given by al.
736 * this used to return an array with null entries regardless, new behaviour is below.
737 * TODO: verify that this does not affect use in applet or application
740 * @return SequenceI[] intersection of sequences in group with al, ordered by al, or null if group does not intersect with al
742 public SequenceI[] getSequencesInOrder(AlignmentI al)
744 int sSize = sequences.size();
745 int alHeight = al.getHeight();
747 SequenceI[] seqs = new SequenceI[sSize];
750 for (int i = 0; i < alHeight && index < sSize; i++)
752 if (sequences.contains(al.getSequenceAt(i)))
754 seqs[index++] = al.getSequenceAt(i);
761 if (index<seqs.length)
763 SequenceI[] dummy = seqs;
764 seqs = new SequenceI[index];
767 seqs[index] = dummy[index];
775 * @return the idColour
777 public Color getIdColour()
784 * the idColour to set
786 public void setIdColour(Color idColour)
788 this.idColour = idColour;
792 * @return the representative sequence for this group
794 public SequenceI getSeqrep()
800 * set the representative sequence for this group.
801 * Note - this affects the interpretation of the Hidereps attribute.
802 * @param seqrep the seqrep to set (null means no sequence representative)
804 public void setSeqrep(SequenceI seqrep)
806 this.seqrep = seqrep;
810 * @return true if group has a sequence representative
812 public boolean hasSeqrep()
814 return seqrep != null;
817 * visibility of rows or represented rows covered by group
819 private boolean hidereps=false;
821 * set visibility of sequences covered by (if no sequence representative is defined)
822 * or represented by this group.
825 public void setHidereps(boolean visibility)
827 hidereps = visibility;
831 * @return true if sequences represented (or covered) by this group should be hidden
833 public boolean isHidereps()
838 * visibility of columns intersecting this group
840 private boolean hidecols=false;
842 * set intended visibility of columns covered by this group
845 public void setHideCols(boolean visibility)
847 hidecols = visibility;
851 * @return true if columns covered by group should be hidden
853 public boolean isHideCols()
858 * create a new sequence group from the intersection of this group
859 * with an alignment Hashtable of hidden representatives
861 * @param alignment (may not be null)
862 * @param hashtable (may be null)
863 * @return new group containing sequences common to this group and alignment
865 public SequenceGroup intersect(AlignmentI alignment, Hashtable hashtable)
867 SequenceGroup sgroup = new SequenceGroup(this);
868 SequenceI[] insect=getSequencesInOrder(alignment);
869 sgroup.sequences = new Vector();
870 for (int s=0;insect!=null && s<insect.length;s++) {
871 if (hashtable==null || hashtable.containsKey(insect[s]))
873 sgroup.sequences.addElement(insect[s]); }
875 //Enumeration en =getSequences(hashtable).elements();
876 //while (en.hasMoreElements())
878 // SequenceI elem = (SequenceI) en.nextElement();
879 // if (alignment.getSequences().contains(elem))
881 // sgroup.addSequence(elem, false);
888 * @return the showUnconserved
890 public boolean getShowunconserved()
892 return showUnconserved;
896 * @param showUnconserved the showUnconserved to set
898 public void setShowunconserved(boolean displayNonconserved)
900 this.showUnconserved = displayNonconserved;
902 AlignmentAnnotation consensus=null,conservation=null;
905 * @return automatically calculated consensus row
907 public AlignmentAnnotation getConsensus()
909 // TODO get or calculate and get consensus annotation row for this group
910 int aWidth = this.getWidth();
920 consensus = new AlignmentAnnotation("Consensus for "+getName(), "PID",
921 new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
922 consensus.hasText = true;
923 consensus.autoCalculated = true;
924 consensus.groupRef = this;
929 * get the conservation annotation row for this group
930 * @return autoCalculated annotation row
932 public AlignmentAnnotation getConservationRow() {
933 int ConsPercGaps = 25;
934 if (conservation == null) {
935 conservation = new AlignmentAnnotation("Conservation",
936 "Conservation of total alignment less than " + ConsPercGaps
937 + "% gaps", new Annotation[1], 0f, 11f,
938 AlignmentAnnotation.BAR_GRAPH);
939 conservation.hasText = true;
940 conservation.autoCalculated = true;
941 conservation.groupRef = this;
949 * @return true if annotation rows have been instantiated for this group
951 public boolean hasAnnotationRows()
953 return consensus!=null || conservation!=null;
956 public SequenceI getConsensusSeq()
959 StringBuffer seqs = new StringBuffer();
960 for (int i = 0; i < consensus.annotations.length; i++)
962 if (consensus.annotations[i] != null)
964 if (consensus.annotations[i].description.charAt(0) == '[')
966 seqs.append(consensus.annotations[i].description.charAt(1));
970 seqs.append(consensus.annotations[i].displayCharacter);
975 SequenceI sq = new Sequence("Group"+getName()+" Consensus", seqs.toString());
976 sq.setDescription("Percentage Identity Consensus "
977 + ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
981 public void setIgnoreGapsConsensus(boolean state)
983 if (this.ignoreGapsInConsensusCalculation!=state && consensus!=null)
985 ignoreGapsInConsensusCalculation = state;
986 recalcConservation();
988 ignoreGapsInConsensusCalculation = state;