X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fdatamodel%2FAlignmentAnnotation.java;h=56bfd74e604ae135c1b7ef5b0e9ba07bdd9fbed2;hb=136c0793b90b72b928c4d77dc109dd5c644e00d3;hp=1bbe81ebca4d393d217ddb39006ab94edcd99ac8;hpb=be32c14cd8e48fe0a207cd7030cb9cd46f894678;p=jalview.git diff --git a/src/jalview/datamodel/AlignmentAnnotation.java b/src/jalview/datamodel/AlignmentAnnotation.java index 1bbe81e..56bfd74 100755 --- a/src/jalview/datamodel/AlignmentAnnotation.java +++ b/src/jalview/datamodel/AlignmentAnnotation.java @@ -24,11 +24,11 @@ import jalview.analysis.Rna; import jalview.analysis.SecStrConsensus.SimpleBP; import jalview.analysis.WUSSParseException; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -40,6 +40,8 @@ import java.util.Map.Entry; */ public class AlignmentAnnotation { + private static final String ANNOTATION_ID_PREFIX = "ann"; + /* * Identifers for different types of profile data */ @@ -49,6 +51,8 @@ public class AlignmentAnnotation public static final int CDNA_PROFILE = 2; + private static long counter = 0; + /** * If true, this annotations is calculated every edit, eg consensus, quality * or conservation graphs @@ -75,7 +79,7 @@ public class AlignmentAnnotation /** Array of annotations placed in the current coordinate system */ public Annotation[] annotations; - public ArrayList bps = null; + public List bps = null; /** * RNA secondary structure contact positions @@ -92,14 +96,13 @@ public class AlignmentAnnotation * Updates the _rnasecstr field Determines the positions that base pair and * the positions of helices based on secondary structure from a Stockholm file * - * @param RNAannot + * @param rnaAnnotation */ - private void _updateRnaSecStr(CharSequence RNAannot) + private void _updateRnaSecStr(CharSequence rnaAnnotation) { try { - _rnasecstr = Rna.GetBasePairs(RNAannot); - bps = Rna.GetModeleBP(RNAannot); + _rnasecstr = Rna.getHelixMap(rnaAnnotation); invalidrnastruc = -1; } catch (WUSSParseException px) { @@ -110,8 +113,6 @@ public class AlignmentAnnotation { return; } - Rna.HelixMap(_rnasecstr); - // setRNAStruc(RNAannot); if (_rnasecstr != null && _rnasecstr.length > 0) { @@ -160,15 +161,20 @@ public class AlignmentAnnotation } setScore(mxval); } + /** * map of positions in the associated annotation */ private Map sequenceMapping; - /** DOCUMENT ME!! */ + /** + * lower range for quantitative data + */ public float graphMin; - /** DOCUMENT ME!! */ + /** + * Upper range for quantitative data + */ public float graphMax; /** @@ -240,6 +246,7 @@ public class AlignmentAnnotation * * @see java.lang.Object#finalize() */ + @Override protected void finalize() throws Throwable { sequenceRef = null; @@ -263,12 +270,6 @@ public class AlignmentAnnotation } } - // JBPNote: what does this do ? - public void ConcenStru(CharSequence RNAannot) throws WUSSParseException - { - bps = Rna.GetModeleBP(RNAannot); - } - /** * Creates a new AlignmentAnnotation object. * @@ -282,6 +283,7 @@ public class AlignmentAnnotation public AlignmentAnnotation(String label, String description, Annotation[] annotations) { + setAnnotationId(); // always editable? editable = true; this.label = label; @@ -458,8 +460,6 @@ public class AlignmentAnnotation _updateRnaSecStr(new AnnotCharSequence()); } } - - annotationId = this.hashCode() + ""; } /** @@ -480,7 +480,7 @@ public class AlignmentAnnotation this(0, annotations.length); } - public AnnotCharSequence(int start, int end) + AnnotCharSequence(int start, int end) { offset = start; max = end; @@ -502,9 +502,13 @@ public class AlignmentAnnotation public char charAt(int index) { return ((index + offset < 0) || (index + offset) >= max - || annotations[index + offset] == null || (annotations[index - + offset].secondaryStructure < ' ') ? ' ' - : annotations[index + offset].secondaryStructure); + || annotations[index + offset] == null + || (annotations[index + offset].secondaryStructure <= ' ') ? ' ' + : annotations[index + offset].displayCharacter == null + || annotations[index + offset].displayCharacter + .length() == 0 ? annotations[index + offset].secondaryStructure + : annotations[index + offset].displayCharacter + .charAt(0)); } @Override @@ -515,8 +519,10 @@ public class AlignmentAnnotation for (int i = offset; i < mx; i++) { - string[i] = (annotations[i] == null || (annotations[i].secondaryStructure < 32)) ? ' ' - : annotations[i].secondaryStructure; + string[i] = (annotations[i] == null || (annotations[i].secondaryStructure <= 32)) ? ' ' + : (annotations[i].displayCharacter == null + || annotations[i].displayCharacter.length() == 0 ? annotations[i].secondaryStructure + : annotations[i].displayCharacter.charAt(0)); } return new String(string); } @@ -559,6 +565,7 @@ public class AlignmentAnnotation public AlignmentAnnotation(String label, String description, Annotation[] annotations, float min, float max, int graphType) { + setAnnotationId(); // graphs are not editable editable = graphType == 0; @@ -581,6 +588,7 @@ public class AlignmentAnnotation if (annotations == null) { visible = false; // try to prevent renderer from displaying. + invalidrnastruc = -1; return; // this is a non-annotation row annotation - ie a sequence score. } @@ -644,7 +652,7 @@ public class AlignmentAnnotation { if (annotations[i] != null) { - annotations[i].displayCharacter = "X"; + annotations[i].displayCharacter = ""; } } } @@ -658,6 +666,7 @@ public class AlignmentAnnotation */ public AlignmentAnnotation(AlignmentAnnotation annotation) { + setAnnotationId(); this.label = new String(annotation.label); if (annotation.description != null) { @@ -681,10 +690,10 @@ public class AlignmentAnnotation this.scaleColLabel = annotation.scaleColLabel; this.showAllColLabels = annotation.showAllColLabels; this.calcId = annotation.calcId; - if (annotation.properties!=null) + if (annotation.properties != null) { - properties = new HashMap(); - for (Map.Entry val:annotation.properties.entrySet()) + properties = new HashMap(); + for (Map.Entry val : annotation.properties.entrySet()) { properties.put(val.getKey(), val.getValue()); } @@ -849,6 +858,10 @@ public class AlignmentAnnotation @Override public String toString() { + if (annotations == null) + { + return ""; + } StringBuilder buffer = new StringBuilder(256); for (int i = 0; i < annotations.length; i++) @@ -945,6 +958,12 @@ public class AlignmentAnnotation } + /** + * When positional annotation and a sequence reference is present, clears and + * resizes the annotations array to the current alignment width, and adds + * annotation according to aligned positions of the sequenceRef given by + * sequenceMapping. + */ public void adjustForAlignment() { if (sequenceRef == null) @@ -968,18 +987,20 @@ public class AlignmentAnnotation int position; Annotation[] temp = new Annotation[aSize]; Integer index; - - for (a = sequenceRef.getStart(); a <= sequenceRef.getEnd(); a++) + if (sequenceMapping != null) { - index = new Integer(a); - if (sequenceMapping.containsKey(index)) + for (a = sequenceRef.getStart(); a <= sequenceRef.getEnd(); a++) { - position = sequenceRef.findIndex(a) - 1; + index = new Integer(a); + Annotation annot = sequenceMapping.get(index); + if (annot != null) + { + position = sequenceRef.findIndex(a) - 1; - temp[position] = sequenceMapping.get(index); + temp[position] = annot; + } } } - annotations = temp; } @@ -1016,11 +1037,11 @@ public class AlignmentAnnotation } /** - * Associate this annotion with the aligned residues of a particular sequence. - * sequenceMapping will be updated in the following way: null sequenceI - - * existing mapping will be discarded but annotations left in mapped - * positions. valid sequenceI not equal to current sequenceRef: mapping is - * discarded and rebuilt assuming 1:1 correspondence TODO: overload with + * Associate this annotation with the aligned residues of a particular + * sequence. sequenceMapping will be updated in the following way: null + * sequenceI - existing mapping will be discarded but annotations left in + * mapped positions. valid sequenceI not equal to current sequenceRef: mapping + * is discarded and rebuilt assuming 1:1 correspondence TODO: overload with * parameter to specify correspondence between current and new sequenceRef * * @param sequenceI @@ -1031,7 +1052,8 @@ public class AlignmentAnnotation { if (sequenceRef != null) { - boolean rIsDs=sequenceRef.getDatasetSequence()==null,tIsDs=sequenceI.getDatasetSequence()==null; + boolean rIsDs = sequenceRef.getDatasetSequence() == null, tIsDs = sequenceI + .getDatasetSequence() == null; if (sequenceRef != sequenceI && (rIsDs && !tIsDs && sequenceRef != sequenceI .getDatasetSequence()) @@ -1119,14 +1141,14 @@ public class AlignmentAnnotation * @param colSel */ public AlignmentAnnotation(AlignmentAnnotation alignmentAnnotation, - ColumnSelection colSel) + HiddenColumns hidden) { this(alignmentAnnotation); if (annotations == null) { return; } - colSel.makeVisibleAnnotation(this); + hidden.makeVisibleAnnotation(this); } public void setPadGaps(boolean padgaps, char gapchar) @@ -1227,8 +1249,10 @@ public class AlignmentAnnotation { if (sp2sq.getMappedWidth() != sp2sq.getWidth()) { - // TODO: employ getWord/MappedWord to transfer annotation between cDNA and Protein reference frames - throw new Error("liftOver currently not implemented for transfer of annotation between different types of seqeunce"); + // TODO: employ getWord/MappedWord to transfer annotation between cDNA and + // Protein reference frames + throw new Error( + "liftOver currently not implemented for transfer of annotation between different types of seqeunce"); } boolean mapIsTo = (sp2sq != null) ? (sp2sq.getTo() == sq || sp2sq .getTo() == sq.getDatasetSequence()) : false; @@ -1281,15 +1305,15 @@ public class AlignmentAnnotation * @note caller should add the remapped annotation to newref if they have not * already */ - public void remap(SequenceI newref, int[][] mapping, int from, int to, - int idxoffset) + public void remap(SequenceI newref, HashMap mapping, + int from, int to, int idxoffset) { if (mapping != null) { Map old = sequenceMapping; Map remap = new HashMap(); int index = -1; - for (int mp[] : mapping) + for (int mp[] : mapping.values()) { if (index++ < 0) { @@ -1343,9 +1367,9 @@ public class AlignmentAnnotation public void setProperty(String property, String value) { - if (properties==null) + if (properties == null) { - properties = new HashMap(); + properties = new HashMap(); } properties.put(property, value); } @@ -1359,8 +1383,115 @@ public class AlignmentAnnotation { if (properties == null) { - return Collections.EMPTY_LIST; + return Collections.emptyList(); } return properties.keySet(); } + + /** + * Returns the Annotation for the given sequence position (base 1) if any, + * else null + * + * @param position + * @return + */ + public Annotation getAnnotationForPosition(int position) + { + return sequenceMapping == null ? null : sequenceMapping.get(position); + + } + + /** + * Set the id to "ann" followed by a counter that increments so as to be + * unique for the lifetime of the JVM + */ + protected final void setAnnotationId() + { + this.annotationId = ANNOTATION_ID_PREFIX + Long.toString(nextId()); + } + + /** + * Returns the match for the last unmatched opening RNA helix pair symbol + * preceding the given column, or '(' if nothing found to match. + * + * @param column + * @return + */ + public String getDefaultRnaHelixSymbol(int column) + { + String result = "("; + if (annotations == null) + { + return result; + } + + /* + * for each preceding column, if it contains an open bracket, + * count whether it is still unmatched at column, if so return its pair + * (likely faster than the fancy alternative using stacks) + */ + for (int col = column - 1; col >= 0; col--) + { + Annotation annotation = annotations[col]; + if (annotation == null) + { + continue; + } + String displayed = annotation.displayCharacter; + if (displayed == null || displayed.length() != 1) + { + continue; + } + char symbol = displayed.charAt(0); + if (!Rna.isOpeningParenthesis(symbol)) + { + continue; + } + + /* + * found an opening bracket symbol + * count (closing-opening) symbols of this type that follow it, + * up to and excluding the target column; if the count is less + * than 1, the opening bracket is unmatched, so return its match + */ + String closer = String.valueOf(Rna + .getMatchingClosingParenthesis(symbol)); + String opener = String.valueOf(symbol); + int count = 0; + for (int j = col + 1; j < column; j++) + { + if (annotations[j] != null) + { + String s = annotations[j].displayCharacter; + if (closer.equals(s)) + { + count++; + } + else if (opener.equals(s)) + { + count--; + } + } + } + if (count < 1) + { + return closer; + } + } + return result; + } + + protected static synchronized long nextId() + { + return counter++; + } + + /** + * + * @return true for rows that have a range of values in their annotation set + */ + public boolean isQuantitative() + { + return graphMin < graphMax; + } }