X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fio%2FAnnotationFile.java;h=2721fb28fe8cd3690e55f95511fefb7f54ceb33f;hb=10e588500da51e79f255e000a46e65065a49f8aa;hp=7f71df18f9bb06686b879766426cde6203dd9dec;hpb=67b2671b1ded591a6f8eb7f13d319e58f993df77;p=jalview.git diff --git a/src/jalview/io/AnnotationFile.java b/src/jalview/io/AnnotationFile.java index 7f71df1..2721fb2 100755 --- a/src/jalview/io/AnnotationFile.java +++ b/src/jalview/io/AnnotationFile.java @@ -1,20 +1,19 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1) - * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle + * Jalview - A Sequence Alignment Editor and Viewer (Version 2.5) + * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. + * This file is part of Jalview. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Jalview. If not, see . */ package jalview.io; @@ -60,8 +59,9 @@ public class AnnotationFile public ColumnSelection hiddencols; public Vector visibleGroups; + public Hashtable hiddenRepSeqs; - + public ViewDef(String viewname, HiddenSequences hidseqs, ColumnSelection hiddencols, Hashtable hiddenRepSeqs) { @@ -72,19 +72,32 @@ public class AnnotationFile } } + /** + * Prepare an annotation file given a set of annotations, groups, alignment + * properties and views. + * + * @param annotations + * @param groups + * @param properties + * @param views + * @return annotation file + */ public String printAnnotations(AlignmentAnnotation[] annotations, Vector groups, Hashtable properties, ViewDef[] views) { + // TODO: resolve views issue : annotationFile could contain visible region, + // or full data + hidden region specifications for a view. if (annotations != null) { boolean oneColour = true; AlignmentAnnotation row; String comma; SequenceI refSeq = null; + SequenceGroup refGroup = null; StringBuffer colours = new StringBuffer(); StringBuffer graphLine = new StringBuffer(); - + StringBuffer rowprops = new StringBuffer(); Hashtable graphGroup = new Hashtable(); java.awt.Color color; @@ -111,24 +124,71 @@ public class AnnotationFile refSeq = null; } - else if (refSeq == null || refSeq != row.sequenceRef) + else { - refSeq = row.sequenceRef; - text.append("\nSEQUENCE_REF\t" + refSeq.getName() + "\n"); + if (refSeq == null || refSeq != row.sequenceRef) + { + refSeq = row.sequenceRef; + text.append("\nSEQUENCE_REF\t" + refSeq.getName() + "\n"); + } + } + // mark any group references for the row + if (row.groupRef == null) + { + + if (refGroup != null) + { + text.append("\nGROUP_REF\tALIGNMENT\n"); + } + + refGroup = null; + } + else + { + if (refGroup == null || refGroup != row.groupRef) + { + refGroup = row.groupRef; + text.append("\nGROUP_REF\t" + refGroup.getName() + "\n"); + } + } + + boolean hasGlyphs = row.hasIcons, hasLabels = row.hasText, hasValues = row.hasScore, hasText = false; + // lookahead to check what the annotation row object actually contains. + for (int j = 0; row.annotations != null + && j < row.annotations.length + && (!hasGlyphs || !hasLabels || !hasValues); j++) + { + if (row.annotations[j] != null) + { + hasLabels |= (row.annotations[j].displayCharacter != null + && row.annotations[j].displayCharacter.length() > 0 && !row.annotations[j].displayCharacter + .equals(" ")); + hasGlyphs |= (row.annotations[j].secondaryStructure != 0 && row.annotations[j].secondaryStructure != ' '); + hasValues |= (row.annotations[j].value != Float.NaN); // NaNs can't + // be + // rendered.. + hasText |= (row.annotations[j].description != null && row.annotations[j].description + .length() > 0); + } } if (row.graph == AlignmentAnnotation.NO_GRAPH) { text.append("NO_GRAPH\t"); + hasValues = false; // only secondary structure + // hasLabels = false; // and annotation description string. } else { if (row.graph == AlignmentAnnotation.BAR_GRAPH) { text.append("BAR_GRAPH\t"); + hasGlyphs = false; // no secondary structure + } else if (row.graph == AlignmentAnnotation.LINE_GRAPH) { + hasGlyphs = false; // no secondary structure text.append("LINE_GRAPH\t"); } @@ -165,7 +225,6 @@ public class AnnotationFile { text.append(row.description + "\t"); } - for (int j = 0; row.annotations != null && j < row.annotations.length; j++) { @@ -178,33 +237,59 @@ public class AnnotationFile if (row.annotations[j] != null) { comma = ""; - if (row.annotations[j].secondaryStructure != ' ') + if (hasGlyphs) // could be also hasGlyphs || ... { - text.append(comma + row.annotations[j].secondaryStructure); + + text.append(comma); + if (row.annotations[j].secondaryStructure != ' ') + { + // only write out the field if its not whitespace. + text.append(row.annotations[j].secondaryStructure); + } comma = ","; } - if (row.annotations[j].displayCharacter != null - && row.annotations[j].displayCharacter.length() > 0 - && !row.annotations[j].displayCharacter.equals(" ")) + if (hasValues) { - text.append(comma + row.annotations[j].displayCharacter); + if (row.annotations[j].value != Float.NaN) + { + text.append(comma + row.annotations[j].value); + } + else + { + System.err.println("Skipping NaN - not valid value."); + text.append(comma + 0f);// row.annotations[j].value); + } comma = ","; } - - if (row.annotations[j] != null) + if (hasLabels) { - if (color != null && !color.equals(row.annotations[j].colour)) + // TODO: labels are emitted after values for bar graphs. + if // empty labels are allowed, so + (row.annotations[j].displayCharacter != null + && row.annotations[j].displayCharacter.length() > 0 + && !row.annotations[j].displayCharacter.equals(" ")) { - oneColour = false; + text.append(comma + row.annotations[j].displayCharacter); + comma = ","; } - - color = row.annotations[j].colour; - if (row.annotations[j].value != 0f - && row.annotations[j].value != Float.NaN) + } + if (hasText) + { + if (row.annotations[j].description != null + && row.annotations[j].description.length() > 0 + && !row.annotations[j].description + .equals(row.annotations[j].displayCharacter)) { - text.append(comma + row.annotations[j].value); + text.append(comma + row.annotations[j].description); + comma = ","; } } + if (color != null && !color.equals(row.annotations[j].colour)) + { + oneColour = false; + } + + color = row.annotations[j].colour; if (row.annotations[j].colour != null && row.annotations[j].colour != java.awt.Color.black) @@ -214,6 +299,7 @@ public class AnnotationFile + jalview.util.Format .getHexString(row.annotations[j].colour) + "]"); + comma = ","; } } text.append("|"); @@ -229,7 +315,15 @@ public class AnnotationFile colours.append("COLOUR\t" + row.label + "\t" + jalview.util.Format.getHexString(color) + "\n"); } - + if (row.scaleColLabel || row.showAllColLabels + || row.centreColLabels) + { + rowprops.append("ROWPROPERTIES\t" + row.label); + rowprops.append("\tscaletofit=" + row.scaleColLabel); + rowprops.append("\tshowalllabs=" + row.showAllColLabels); + rowprops.append("\tcentrelabs=" + row.centreColLabels); + rowprops.append("\n"); + } } text.append("\n"); @@ -245,6 +339,7 @@ public class AnnotationFile text.append(en.nextElement() + "\n"); } } + text.append(rowprops.toString()); } if (groups != null) @@ -271,22 +366,24 @@ public class AnnotationFile public void printGroups(Vector sequenceGroups) { SequenceGroup sg; - SequenceI seqrep=null; + SequenceI seqrep = null; for (int i = 0; i < sequenceGroups.size(); i++) { sg = (SequenceGroup) sequenceGroups.elementAt(i); if (!sg.hasSeqrep()) { text.append("SEQUENCE_GROUP\t" + sg.getName() + "\t" - + (sg.getStartRes() + 1) + "\t" + (sg.getEndRes() + 1) + "\t" - + "-1\t"); + + (sg.getStartRes() + 1) + "\t" + (sg.getEndRes() + 1) + + "\t" + "-1\t"); seqrep = null; - } else { + } + else + { seqrep = sg.getSeqrep(); - text.append("SEQUENCE_REF\t"+seqrep.getName()+"\n"); + text.append("SEQUENCE_REF\t" + seqrep.getName() + "\n"); text.append("SEQUENCE_GROUP\t" + sg.getName() + "\t" - + (seqrep.findPosition(sg.getStartRes())) + "\t" + (seqrep.findPosition(sg.getEndRes())) + "\t" - + "-1\t"); + + (seqrep.findPosition(sg.getStartRes())) + "\t" + + (seqrep.findPosition(sg.getEndRes())) + "\t" + "-1\t"); } for (int s = 0; s < sg.getSize(); s++) { @@ -319,7 +416,7 @@ public class AnnotationFile text.append("displayBoxes=" + sg.getDisplayBoxes() + "\t"); text.append("displayText=" + sg.getDisplayText() + "\t"); text.append("colourText=" + sg.getColourText() + "\t"); - text.append("showUnconserved="+sg.getShowunconserved()+"\t"); + text.append("showUnconserved=" + sg.getShowunconserved() + "\t"); if (sg.textColour != java.awt.Color.black) { text.append("textCol1=" @@ -332,7 +429,7 @@ public class AnnotationFile } if (sg.thresholdTextColour != 0) { - text.append("textColThreshold=" + sg.thresholdTextColour+"\t"); + text.append("textColThreshold=" + sg.thresholdTextColour + "\t"); } if (sg.idColour != null) { @@ -347,7 +444,7 @@ public class AnnotationFile { text.append("hidecols=true\t"); } - if (seqrep!=null) + if (seqrep != null) { // terminate the last line and clear the sequence ref for the group text.append("\nSEQUENCE_REF"); @@ -364,6 +461,10 @@ public class AnnotationFile public boolean readAnnotationFile(AlignmentI al, String file, String protocol) { + String groupRef = null; + Hashtable groupRefRows = new Hashtable(); + + Hashtable autoAnnots = new Hashtable(); try { BufferedReader in = null; @@ -393,9 +494,31 @@ public class AnnotationFile int graphStyle, index; int refSeqIndex = 1; int existingAnnotations = 0; + // when true - will add new rows regardless of whether they are duplicate + // auto-annotation like consensus or conservation graphs + boolean overrideAutoAnnot = false; if (al.getAlignmentAnnotation() != null) { existingAnnotations = al.getAlignmentAnnotation().length; + if (existingAnnotations > 0) + { + AlignmentAnnotation[] aa = al.getAlignmentAnnotation(); + for (int aai = 0; aai < aa.length; aai++) + { + if (aa[aai].autoCalculated) + { + // make a note of the name and description + autoAnnots.put(aa[aai].graph + + "\t" + + aa[aai].label + + "\t" + + aa[aai].description + + "\t" + + (aa[aai].sequenceRef != null ? aa[aai].sequenceRef + .getDisplayId(true) : ""), new Integer(1)); + } + } + } } int alWidth = al.getWidth(); @@ -449,7 +572,11 @@ public class AnnotationFile combineAnnotations(al, st); continue; } - + else if (token.equalsIgnoreCase("ROWPROPERTIES")) + { + addRowProperties(al, st); + continue; + } else if (token.equalsIgnoreCase("GRAPHLINE")) { addLine(al, st); @@ -486,7 +613,28 @@ public class AnnotationFile } continue; } - + else if (token.equalsIgnoreCase("GROUP_REF")) + { + // Group references could be forward or backwards, so they are + // resolved after the whole file is read in + groupRef = null; + if (st.hasMoreTokens()) + { + groupRef = st.nextToken(); + if (groupRef.length() < 1) + { + groupRef = null; // empty string + } + else + { + if (groupRefRows.get(groupRef) == null) + { + groupRefRows.put(groupRef, new Vector()); + } + } + } + continue; + } else if (token.equalsIgnoreCase("SEQUENCE_GROUP")) { addGroup(al, st); @@ -510,6 +658,7 @@ public class AnnotationFile continue; } + // Parse out the annotation row graphStyle = AlignmentAnnotation.getGraphValueFromString(token); label = st.nextToken(); @@ -566,7 +715,7 @@ public class AnnotationFile } else { - annotations[index++] = parseAnnotation(token); + annotations[index++] = parseAnnotation(token, graphStyle); emptyColumn = false; } } @@ -577,9 +726,24 @@ public class AnnotationFile (index == 0) ? null : annotations, 0, 0, graphStyle); annotation.score = score; - + if (!overrideAutoAnnot + && autoAnnots + .containsKey(annotation.graph + + "\t" + + annotation.label + + "\t" + + annotation.description + + "\t" + + (refSeq != null ? refSeq + .getDisplayId(true) : ""))) + { + // skip - we've already got an automatic annotation of this type. + continue; + } + // otherwise add it! if (refSeq != null) { + annotation.belowAlignment = false; // make a copy of refSeq so we can find other matches in the alignment SequenceI referedSeq = refSeq; @@ -589,13 +753,18 @@ public class AnnotationFile // TODO: verify that undo/redo with 1:many sequence associated // annotations can be undone correctly AlignmentAnnotation ann = new AlignmentAnnotation(annotation); - annotation.createSequenceMapping(referedSeq, refSeqIndex, false); + annotation + .createSequenceMapping(referedSeq, refSeqIndex, false); annotation.adjustForAlignment(); referedSeq.addAlignmentAnnotation(annotation); al.addAnnotation(annotation); al.setAnnotationIndex(annotation, al.getAlignmentAnnotation().length - existingAnnotations - 1); + if (groupRef != null) + { + ((Vector) groupRefRows.get(groupRef)).addElement(annotation); + } // and recover our virgin copy to use again if necessary. annotation = ann; @@ -608,9 +777,53 @@ public class AnnotationFile al.setAnnotationIndex(annotation, al.getAlignmentAnnotation().length - existingAnnotations - 1); + if (groupRef != null) + { + ((Vector) groupRefRows.get(groupRef)).addElement(annotation); + } } } + // Finally, resolve the groupRefs + Enumeration en = groupRefRows.keys(); + SequenceGroup theGroup = null; + while (en.hasMoreElements()) + { + groupRef = (String) en.nextElement(); + boolean matched = false; + // Resolve group: TODO: add a getGroupByName method to alignments + Vector grps = al.getGroups(); + for (int g = 0, gSize = grps.size(); g < gSize; g++) + { + theGroup = (SequenceGroup) grps.elementAt(g); + if (theGroup.getName().equals(groupRef)) + { + if (matched) + { + // TODO: specify and implement duplication of alignment annotation + // for multiple group references. + System.err + .println("Ignoring 1:many group reference mappings for group name '" + + groupRef + "'"); + } + else + { + matched = true; + Vector rowset = (Vector) groupRefRows.get(groupRef); + if (rowset != null && rowset.size() > 0) + { + AlignmentAnnotation alan = null; + for (int elm = 0, elmSize = rowset.size(); elm < elmSize; elm++) + { + alan = (AlignmentAnnotation) rowset.elementAt(elm); + alan.groupRef = theGroup; + } + } + } + } + } + ((Vector) groupRefRows.get(groupRef)).removeAllElements(); + } } catch (Exception ex) { ex.printStackTrace(); @@ -620,12 +833,21 @@ public class AnnotationFile return true; } - Annotation parseAnnotation(String string) + Annotation parseAnnotation(String string, int graphStyle) { + boolean hasSymbols = (graphStyle == AlignmentAnnotation.NO_GRAPH); // don't + // do the + // glyph + // test + // if we + // don't + // want + // secondary + // structure String desc = null, displayChar = null; char ss = ' '; // secondaryStructure float value = 0; - boolean parsedValue = false; + boolean parsedValue = false, dcset = false; // find colour here java.awt.Color colour = null; @@ -636,25 +858,44 @@ public class AnnotationFile UserColourScheme ucs = new UserColourScheme(); colour = ucs.getColourFromString(string.substring(i + 1, j)); - + if (i > 0 && string.charAt(i - 1) == ',') + { + // clip the preceding comma as well + i--; + } string = string.substring(0, i) + string.substring(j + 1); } - StringTokenizer st = new StringTokenizer(string, ","); + StringTokenizer st = new StringTokenizer(string, ",", true); String token; + boolean seenContent = false; + int pass = 0; while (st.hasMoreTokens()) { + pass++; token = st.nextToken().trim(); - if (token.length() == 0) + if (token.equals(",")) { + if (!seenContent && parsedValue && !dcset) + { + // allow the value below the bar/line to be empty + dcset = true; + displayChar = " "; + } + seenContent = false; continue; } + else + { + seenContent = true; + } if (!parsedValue) { try { displayChar = token; + // foo value = new Float(token).floatValue(); parsedValue = true; continue; @@ -662,8 +903,16 @@ public class AnnotationFile { } } - - if (token.equals("H") || token.equals("E")) + else + { + if (token.length() == 1) + { + displayChar = token; + } + } + if (hasSymbols + && (token.equals("H") || token.equals("E") || token + .equals(" "))) { // Either this character represents a helix or sheet // or an integer which can be displayed @@ -673,26 +922,34 @@ public class AnnotationFile displayChar = ""; } } - else if (desc == null) + else if (desc == null || (parsedValue && pass > 2)) { desc = token; } } - - if (displayChar != null && displayChar.length() > 1 && desc != null - && desc.length() == 1) + // if (!dcset && string.charAt(string.length() - 1) == ',') + // { + // displayChar = " "; // empty display char symbol. + // } + if (displayChar != null && desc != null && desc.length() == 1) { - String tmp = displayChar; - displayChar = desc; - desc = tmp; + if (displayChar.length() > 1) + { + // switch desc and displayChar - legacy support + String tmp = displayChar; + displayChar = desc; + desc = tmp; + } + else + { + if (displayChar.equals(desc)) + { + // duplicate label - hangover from the 'robust parser' above + desc = null; + } + } } - /* - * In principle, this code will ensure that the Annotation element generated - * is renderable by any of the applet or application rendering code but - * instead we check for null strings when the display character is rendered. - * if (displayChar==null) { displayChar=""; } - */ Annotation anot = new Annotation(displayChar, desc, ss, value); anot.colour = colour; @@ -725,45 +982,55 @@ public class AnnotationFile int graphGroup = -1; String group = st.nextToken(); // First make sure we are not overwriting the graphIndex - for (int i = 0; i < al.getAlignmentAnnotation().length; i++) - { - if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group)) - { - graphGroup = al.getAlignmentAnnotation()[i].graphGroup + 1; - al.getAlignmentAnnotation()[i].graphGroup = graphGroup; - break; - } - } - - // Now update groups - while (st.hasMoreTokens()) + if (al.getAlignmentAnnotation() != null) { - group = st.nextToken(); for (int i = 0; i < al.getAlignmentAnnotation().length; i++) { if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group)) { + graphGroup = al.getAlignmentAnnotation()[i].graphGroup + 1; al.getAlignmentAnnotation()[i].graphGroup = graphGroup; break; } } + + // Now update groups + while (st.hasMoreTokens()) + { + group = st.nextToken(); + for (int i = 0; i < al.getAlignmentAnnotation().length; i++) + { + if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group)) + { + al.getAlignmentAnnotation()[i].graphGroup = graphGroup; + break; + } + } + } + } + else + { + System.err + .println("Couldn't combine annotations. None are added to alignment yet!"); } } void addLine(AlignmentI al, StringTokenizer st) { String group = st.nextToken(); - AlignmentAnnotation annotation = null; - - for (int i = 0; i < al.getAlignmentAnnotation().length; i++) + AlignmentAnnotation annotation = null, alannot[] = al + .getAlignmentAnnotation(); + if (alannot != null) { - if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group)) + for (int i = 0; i < alannot.length; i++) { - annotation = al.getAlignmentAnnotation()[i]; - break; + if (alannot[i].label.equalsIgnoreCase(group)) + { + annotation = alannot[i]; + break; + } } } - if (annotation == null) { return; @@ -779,32 +1046,40 @@ public class AnnotationFile annotation.setThreshold(new GraphLine(value, label, colour)); } + void addGroup(AlignmentI al, StringTokenizer st) { SequenceGroup sg = new SequenceGroup(); sg.setName(st.nextToken()); - String rng =""; - try { + String rng = ""; + try + { rng = st.nextToken(); - if (rng.length()>0 && !rng.startsWith("*")) + if (rng.length() > 0 && !rng.startsWith("*")) { sg.setStartRes(Integer.parseInt(rng) - 1); - } else { + } + else + { sg.setStartRes(0); } rng = st.nextToken(); - if (rng.length()>0 && !rng.startsWith("*")) + if (rng.length() > 0 && !rng.startsWith("*")) { sg.setEndRes(Integer.parseInt(rng) - 1); - } else { - sg.setEndRes(al.getWidth()-1); + } + else + { + sg.setEndRes(al.getWidth() - 1); } } catch (Exception e) { - System.err.println("Couldn't parse Group Start or End Field as '*' or a valid column or sequence index: '"+rng+"' - assuming alignment width for group."); + System.err + .println("Couldn't parse Group Start or End Field as '*' or a valid column or sequence index: '" + + rng + "' - assuming alignment width for group."); // assume group is full width sg.setStartRes(0); - sg.setEndRes(al.getWidth()-1); + sg.setEndRes(al.getWidth() - 1); } String index = st.nextToken(); @@ -866,6 +1141,43 @@ public class AnnotationFile } } + void addRowProperties(AlignmentI al, StringTokenizer st) + { + String label = st.nextToken(), keyValue, key, value; + boolean scaletofit = false, centerlab = false, showalllabs = false; + while (st.hasMoreTokens()) + { + keyValue = st.nextToken(); + key = keyValue.substring(0, keyValue.indexOf("=")); + value = keyValue.substring(keyValue.indexOf("=") + 1); + if (key.equalsIgnoreCase("scaletofit")) + { + scaletofit = Boolean.valueOf(value).booleanValue(); + } + if (key.equalsIgnoreCase("showalllabs")) + { + showalllabs = Boolean.valueOf(value).booleanValue(); + } + if (key.equalsIgnoreCase("centrelabs")) + { + centerlab = Boolean.valueOf(value).booleanValue(); + } + AlignmentAnnotation[] alr = al.getAlignmentAnnotation(); + if (alr != null) + { + for (int i = 0; i < alr.length; i++) + { + if (alr[i].label.equalsIgnoreCase(label)) + { + alr[i].centreColLabels = centerlab; + alr[i].scaleColLabel = scaletofit; + alr[i].showAllColLabels = showalllabs; + } + } + } + } + } + void addProperties(AlignmentI al, StringTokenizer st) { @@ -991,19 +1303,35 @@ public class AnnotationFile void setBelowAlignment(AlignmentI al, StringTokenizer st) { String token; - AlignmentAnnotation aa; + AlignmentAnnotation aa, ala[] = al.getAlignmentAnnotation(); + if (ala == null) + { + System.err + .print("Warning - no annotation to set below for sequence associated annotation:"); + } while (st.hasMoreTokens()) { token = st.nextToken(); - for (int i = 0; i < al.getAlignmentAnnotation().length; i++) + if (ala == null) + { + System.err.print(" "+token); + } + else { - aa = al.getAlignmentAnnotation()[i]; - if (aa.sequenceRef == refSeq && aa.label.equals(token)) + for (int i = 0; i < al.getAlignmentAnnotation().length; i++) { - aa.belowAlignment = true; + aa = al.getAlignmentAnnotation()[i]; + if (aa.sequenceRef == refSeq && aa.label.equals(token)) + { + aa.belowAlignment = true; + } } } } + if (ala==null) + { + System.err.print("\n"); + } } void addAlignmentDetails(AlignmentI al, StringTokenizer st)