group/annotation association
authorjprocter <Jim Procter>
Wed, 28 Apr 2010 10:16:32 +0000 (10:16 +0000)
committerjprocter <Jim Procter>
Wed, 28 Apr 2010 10:16:32 +0000 (10:16 +0000)
help/html/features/annotationsFormat.html
src/jalview/io/AnnotationFile.java

index fcec5c0..fc0d4c4 100755 (executable)
@@ -33,13 +33,13 @@ separated value fields. Each value field is itself a comma separated list of fie
 GRAPH_TYPE. The allowed values of GRAPH_TYPE and the format of their respective value fields (with the trailing &quot;<strong>|</strong>&quot; symbol) are shown below:<ul>
        <li>BAR_GRAPH<br>
        Plots a histogram with labels below each bar.<br>
-       <em>number</em>,<em>text character</em></li>
+       <em>number</em>,<em>text character</em>,<em>Tooltip text</em></li>
        <li>LINE_GRAPH<br>
        Draws a line between values on the annotation row.<br>
        <em>number</em></li>
        <li>NO_GRAPH<br>
        For a row consisting of text labels and/or secondary structure symbols.<br>
-       <em>{Secondary Structure Symbol}</em>,<em>text label</em><br>
+       <em>{Secondary Structure Symbol}</em>,<em>text label</em>,<em>Tooltip text</em><br>
        Currently supported secondary structure structure symbols are <em>H</em> (for   helix) and <em>E</em> (for strand)</li>
 </ul>
 Any or all value fields may be left empty, as well as the BAR_GRAPH's
@@ -55,11 +55,17 @@ associated with that sequence, and the first field in the Value field
 list will (optionally) be placed at the <em>startIndex</em>'th column.</p>
 <ul><em>New in Jalview 2.4</em>: the tooltip displayed when the mouse is moved over the row 
 label for sequence associated annotation  gives the associated 
-sequence's name followed by the annotation row's description.</ul> 
+sequence's name followed by the annotation row's description.<br/>
+<em>New in Jalview 2.5</em>: Clicking on a sequence or group associated annotation row's label will highlight the sequence or sequence group in the alignment, and double clicking the annotation row label will select the associated sequence or group.</ul> 
 <p>Sequence associations are turned off for subsequent annotation
 definitions by: 
 <pre>SEQUENCE_REF&#9;ALIGNMENT</pre>
 </p>
+<p>Since version 2.5, Jalview allows annotation rows to be associated with a group defined on the alignment, by preceding the annotation row with the line:
+<pre>GROUP_REF&#9;<em>group_name</em></pre>
+Group association is turned off for subsequent annotation rows by 
+<pre>GROUP_REF&#9;<em>ALIGNMENT</em></pre>
+Annotations may be associated with both a sequence and a group, however - group annotations are still experimental and unexpected behaviour may be observed when editing alignments containing both group and sequence associated annotation rows.</p>
 <p><em>LINE_GRAPH</em> type annotations can be given a colour
 (specified as 24 bit RGB triplet in hexadecimal or comma separated
 values), combined onto the same vertical axis, and have ordinate lines
@@ -69,13 +75,13 @@ following commands (respectively):
 COMBINE&#9;<em>graph_1_name</em>&#9;<em>graph_2_name</em>
 GRAPHLINE&#9;<em>graph_name</em>&#9;<em>value</em>&#9;<em>label</em>&#9;<em>colour</em><strong><em>
 </em></strong></pre>
-<h3><font face="Arial, Helvetica, sans-serif">(Since Jalview 2.4.1) ROWPROPERTIES</font></h3>
+<h3><font face="Arial, Helvetica, sans-serif">(Since Jalview 2.5) ROWPROPERTIES</font></h3>
 <p>The visual display properties for a set of annotation rows can be modified using the following tab-delimited line:</p>
 <pre>ROWPROPERTIES&#9;<em>Row label</em>&#9;<em>centrelabs=true( or false)</em>&#9;<em>showalllabs=true(default is false)</em>&#9;<em>scaletofit=true (default is false)</em></pre>
 <p>This sets the visual display properties according to the given values for all the annotation rows with labels matching <em>Row label</em>. The properties mostly affect the display of multi-character column labels, and are as follows:
 <ul><li><em>centrelabs</em> Centre each label on its column.</li>
 <li><em>showalllabs</em> Show every column label rather than only the first of a run of identical labels (setting this to true can have a drastic effect on secondary structure rows).</li>
-<li><em>scaletofit</em> Shrink each label's font size so that the label fits within the column. Useful when annotating an alignment with a specific column numbering system.</li>
+<li><em>scaletofit</em> Shrink each label's font size so that the label fits within the column. Useful when annotating an alignment with a specific column numbering system. (<em>Not available in Jalview applet due to AWT 1.1 limitations</em>)</li>
 </ul></p>
 <h3><font face="Arial, Helvetica, sans-serif">(Since Jalview 2.2.1) SEQUENCE_GROUP</font></h3>
 <p>Groups of sequences can be defined using the tab delimited line</p>
@@ -108,8 +114,9 @@ GRAPHLINE&#9;<em>graph_name</em>&#9;<em>value</em>&#9;<em>label</em>&#9;<em>colo
   textCol2=black<br>
   textColThreshold=0<br>
   idColour=ff3322<br>
+ <!-- Not yet implemented in 2.5 release 
   hide=false<br>
-  hidecols=false<br>
+  hidecols=false<br> -->
   showunconserved=false</p>
 <ul><li><em>New Features in 2.4:</em><br>if the <strong>idColour</strong> property
 is given without specifying a colour scheme with the <strong>colour</strong>
@@ -118,12 +125,12 @@ property, then the idColour will also be used to colour the sequence.</li>
  or a single colour specification (either a colour name like 'red' or an RGB
  triplet like 'ff0066'). If a single colour is specified, then the group
  will be coloured with that colour.</li>
- <li><em>New Features in 2.4.1</em></li>
- <li>hide and hidecols instruct jalview to hide the sequences or columns covered by the group.</li>
+ <!--  <li><em>New Features in 2.5</em></li>
+ <li>hide and hidecols instruct jalview to hide the sequences or columns covered by the group.</li> -->
   <li>Sequence associated Groups<br>If a group is defined after a valid
  <em>SEQUENCE_REF</em> sequence reference statement, the sequence representative
- for the group will be set to the referenced sequence.<br><strong>Note:</strong> if the <em>hide</em> 
- property is set then only the representative sequence for the group will be shown in the alignment.</li>
+ for the group will be set to the referenced sequence.<!-- <br><strong>Note:</strong> if the <em>hide</em> 
+ property is set then only the representative sequence for the group will be shown in the alignment.--></li>
 </ul>
 <p> </p>
 <p>An example Annotation file is given below:
index aac48eb..01daf39 100755 (executable)
@@ -72,8 +72,11 @@ public class AnnotationFile
       this.hiddenRepSeqs = hiddenRepSeqs;\r
     }\r
   }\r
+\r
   /**\r
-   * Prepare an annotation file given a set of annotations, groups, alignment properties and views. \r
+   * Prepare an annotation file given a set of annotations, groups, alignment\r
+   * properties and views.\r
+   * \r
    * @param annotations\r
    * @param groups\r
    * @param properties\r
@@ -83,13 +86,15 @@ public class AnnotationFile
   public String printAnnotations(AlignmentAnnotation[] annotations,\r
           Vector groups, Hashtable properties, ViewDef[] views)\r
   {\r
-    // TODO: resolve views issue : annotationFile could contain visible region, or full data + hidden region specifications for a view.\r
+    // TODO: resolve views issue : annotationFile could contain visible region,\r
+    // or full data + hidden region specifications for a view.\r
     if (annotations != null)\r
     {\r
       boolean oneColour = true;\r
       AlignmentAnnotation row;\r
       String comma;\r
       SequenceI refSeq = null;\r
+      SequenceGroup refGroup = null;\r
 \r
       StringBuffer colours = new StringBuffer();\r
       StringBuffer graphLine = new StringBuffer();\r
@@ -120,11 +125,34 @@ public class AnnotationFile
           refSeq = null;\r
         }\r
 \r
-        else if (refSeq == null || refSeq != row.sequenceRef)\r
+        else\r
+        {\r
+          if (refSeq == null || refSeq != row.sequenceRef)\r
+          {\r
+            refSeq = row.sequenceRef;\r
+            text.append("\nSEQUENCE_REF\t" + refSeq.getName() + "\n");\r
+          }\r
+        }\r
+        // mark any group references for the row\r
+        if (row.groupRef == null)\r
+        {\r
+\r
+          if (refGroup != null)\r
+          {\r
+            text.append("\nGROUP_REF\tALIGNMENT\n");\r
+          }\r
+\r
+          refGroup = null;\r
+        }\r
+        else\r
         {\r
-          refSeq = row.sequenceRef;\r
-          text.append("\nSEQUENCE_REF\t" + refSeq.getName() + "\n");\r
+          if (refGroup == null || refGroup != row.groupRef)\r
+          {\r
+            refGroup = row.groupRef;\r
+            text.append("\nGROUP_REF\t" + refGroup.getName() + "\n");\r
+          }\r
         }\r
+\r
         boolean hasGlyphs = row.hasIcons, hasLabels = row.hasText, hasValues = row.hasScore, hasText = false;\r
         // lookahead to check what the annotation row object actually contains.\r
         for (int j = 0; row.annotations != null\r
@@ -138,8 +166,8 @@ public class AnnotationFile
                     .equals(" "));\r
             hasGlyphs |= (row.annotations[j].secondaryStructure != 0 && row.annotations[j].secondaryStructure != ' ');\r
             hasValues |= (row.annotations[j].value != Float.NaN); // NaNs can't\r
-                                                                  // be\r
-                                                                  // rendered..\r
+            // be\r
+            // rendered..\r
             hasText |= (row.annotations[j].description != null && row.annotations[j].description\r
                     .length() > 0);\r
           }\r
@@ -210,7 +238,7 @@ public class AnnotationFile
           if (row.annotations[j] != null)\r
           {\r
             comma = "";\r
-            if (hasGlyphs) // could be also hasGlyphs || ... \r
+            if (hasGlyphs) // could be also hasGlyphs || ...\r
             {\r
 \r
               text.append(comma);\r
@@ -288,12 +316,13 @@ public class AnnotationFile
           colours.append("COLOUR\t" + row.label + "\t"\r
                   + jalview.util.Format.getHexString(color) + "\n");\r
         }\r
-        if (row.scaleColLabel || row.showAllColLabels || row.centreColLabels)\r
+        if (row.scaleColLabel || row.showAllColLabels\r
+                || row.centreColLabels)\r
         {\r
-          rowprops.append("ROWPROPERTIES\t"+row.label);\r
-          rowprops.append("\tscaletofit="+row.scaleColLabel);\r
-          rowprops.append("\tshowalllabs="+row.showAllColLabels);\r
-          rowprops.append("\tcentrelabs="+row.centreColLabels);\r
+          rowprops.append("ROWPROPERTIES\t" + row.label);\r
+          rowprops.append("\tscaletofit=" + row.scaleColLabel);\r
+          rowprops.append("\tshowalllabs=" + row.showAllColLabels);\r
+          rowprops.append("\tcentrelabs=" + row.centreColLabels);\r
           rowprops.append("\n");\r
         }\r
       }\r
@@ -433,7 +462,10 @@ public class AnnotationFile
   public boolean readAnnotationFile(AlignmentI al, String file,\r
           String protocol)\r
   {\r
-    Hashtable autoAnnots=new Hashtable();\r
+    String groupRef = null;\r
+    Hashtable groupRefRows = new Hashtable();\r
+\r
+    Hashtable autoAnnots = new Hashtable();\r
     try\r
     {\r
       BufferedReader in = null;\r
@@ -463,21 +495,28 @@ public class AnnotationFile
       int graphStyle, index;\r
       int refSeqIndex = 1;\r
       int existingAnnotations = 0;\r
-      // when true - will add new rows regardless of whether they are duplicate auto-annotation like consensus or conservation graphs\r
-      boolean overrideAutoAnnot=false; \r
+      // when true - will add new rows regardless of whether they are duplicate\r
+      // auto-annotation like consensus or conservation graphs\r
+      boolean overrideAutoAnnot = false;\r
       if (al.getAlignmentAnnotation() != null)\r
       {\r
         existingAnnotations = al.getAlignmentAnnotation().length;\r
-        if (existingAnnotations>0)\r
+        if (existingAnnotations > 0)\r
         {\r
           AlignmentAnnotation[] aa = al.getAlignmentAnnotation();\r
-          for (int aai=0;aai<aa.length;aai++)\r
+          for (int aai = 0; aai < aa.length; aai++)\r
           {\r
             if (aa[aai].autoCalculated)\r
             {\r
               // make a note of the name and description\r
-              autoAnnots.put(aa[aai].graph+"\t"+aa[aai].label+"\t"+aa[aai].description+"\t"+(aa[aai].sequenceRef!=null ? aa[aai].sequenceRef.getDisplayId(true) : "")\r
-                      ,new Integer(1));\r
+              autoAnnots.put(aa[aai].graph\r
+                      + "\t"\r
+                      + aa[aai].label\r
+                      + "\t"\r
+                      + aa[aai].description\r
+                      + "\t"\r
+                      + (aa[aai].sequenceRef != null ? aa[aai].sequenceRef\r
+                              .getDisplayId(true) : ""), new Integer(1));\r
             }\r
           }\r
         }\r
@@ -575,7 +614,28 @@ public class AnnotationFile
           }\r
           continue;\r
         }\r
-\r
+        else if (token.equalsIgnoreCase("GROUP_REF"))\r
+        {\r
+          // Group references could be forward or backwards, so they are\r
+          // resolved after the whole file is read in\r
+          groupRef = null;\r
+          if (st.hasMoreTokens())\r
+          {\r
+            groupRef = st.nextToken();\r
+            if (groupRef.length() < 1)\r
+            {\r
+              groupRef = null; // empty string\r
+            }\r
+            else\r
+            {\r
+              if (groupRefRows.get(groupRef) == null)\r
+              {\r
+                groupRefRows.put(groupRef, new Vector());\r
+              }\r
+            }\r
+          }\r
+          continue;\r
+        }\r
         else if (token.equalsIgnoreCase("SEQUENCE_GROUP"))\r
         {\r
           addGroup(al, st);\r
@@ -599,6 +659,7 @@ public class AnnotationFile
           continue;\r
         }\r
 \r
+        // Parse out the annotation row\r
         graphStyle = AlignmentAnnotation.getGraphValueFromString(token);\r
         label = st.nextToken();\r
 \r
@@ -661,12 +722,21 @@ public class AnnotationFile
           }\r
 \r
         }\r
-        \r
+\r
         annotation = new AlignmentAnnotation(label, description,\r
                 (index == 0) ? null : annotations, 0, 0, graphStyle);\r
 \r
         annotation.score = score;\r
-        if (!overrideAutoAnnot && autoAnnots.containsKey(annotation.graph+"\t"+annotation.label+"\t"+annotation.description+"\t"+(refSeq!=null ? refSeq.getDisplayId(true) : "")))\r
+        if (!overrideAutoAnnot\r
+                && autoAnnots\r
+                        .containsKey(annotation.graph\r
+                                + "\t"\r
+                                + annotation.label\r
+                                + "\t"\r
+                                + annotation.description\r
+                                + "\t"\r
+                                + (refSeq != null ? refSeq\r
+                                        .getDisplayId(true) : "")))\r
         {\r
           // skip - we've already got an automatic annotation of this type.\r
           continue;\r
@@ -674,7 +744,7 @@ public class AnnotationFile
         // otherwise add it!\r
         if (refSeq != null)\r
         {\r
-          \r
+\r
           annotation.belowAlignment = false;\r
           // make a copy of refSeq so we can find other matches in the alignment\r
           SequenceI referedSeq = refSeq;\r
@@ -692,6 +762,10 @@ public class AnnotationFile
             al.setAnnotationIndex(annotation,\r
                     al.getAlignmentAnnotation().length\r
                             - existingAnnotations - 1);\r
+            if (groupRef != null)\r
+            {\r
+              ((Vector) groupRefRows.get(groupRef)).addElement(annotation);\r
+            }\r
             // and recover our virgin copy to use again if necessary.\r
             annotation = ann;\r
 \r
@@ -704,9 +778,52 @@ public class AnnotationFile
           al.setAnnotationIndex(annotation,\r
                   al.getAlignmentAnnotation().length - existingAnnotations\r
                           - 1);\r
+          if (groupRef != null)\r
+          {\r
+            ((Vector) groupRefRows.get(groupRef)).addElement(annotation);\r
+          }\r
         }\r
       }\r
+      // Finally, resolve the groupRefs\r
+      Enumeration en = groupRefRows.keys();\r
+      SequenceGroup theGroup = null;\r
 \r
+      while (en.hasMoreElements())\r
+      {\r
+        groupRef = (String) en.nextElement();\r
+        boolean matched = false;\r
+        // Resolve group: TODO: add a getGroupByName method to alignments\r
+        Vector grps = al.getGroups();\r
+        for (int g = 0, gSize = grps.size(); g < gSize; g++)\r
+        {\r
+          theGroup = (SequenceGroup) grps.elementAt(g);\r
+          if (theGroup.getName().equals(groupRef))\r
+          {\r
+            if (matched)\r
+            {\r
+              // TODO: specify and implement duplication of alignment annotation for multiple group references.\r
+              System.err\r
+                      .println("Ignoring 1:many group reference mappings for group name '"\r
+                              + groupRef+"'");\r
+            }\r
+            else\r
+            {\r
+              matched = true;\r
+              Vector rowset = (Vector) groupRefRows.get(groupRef);\r
+              if (rowset != null && rowset.size() > 0)\r
+              {\r
+                AlignmentAnnotation alan = null;\r
+                for (int elm = 0, elmSize = rowset.size(); elm < elmSize; elm++)\r
+                {\r
+                  alan = (AlignmentAnnotation) rowset.elementAt(elm);\r
+                  alan.groupRef = theGroup;\r
+                }\r
+              }\r
+            }\r
+          }\r
+        }\r
+        ((Vector) groupRefRows.get(groupRef)).removeAllElements();\r
+      }\r
     } catch (Exception ex)\r
     {\r
       ex.printStackTrace();\r
@@ -718,7 +835,15 @@ public class AnnotationFile
 \r
   Annotation parseAnnotation(String string, int graphStyle)\r
   {\r
-    boolean hasSymbols = (graphStyle == AlignmentAnnotation.NO_GRAPH); // don't do the glyph test if we don't want secondary structure\r
+    boolean hasSymbols = (graphStyle == AlignmentAnnotation.NO_GRAPH); // don't\r
+                                                                       // do the\r
+                                                                       // glyph\r
+                                                                       // test\r
+                                                                       // if we\r
+                                                                       // don't\r
+                                                                       // want\r
+                                                                       // secondary\r
+                                                                       // structure\r
     String desc = null, displayChar = null;\r
     char ss = ' '; // secondaryStructure\r
     float value = 0;\r
@@ -733,7 +858,7 @@ public class AnnotationFile
       UserColourScheme ucs = new UserColourScheme();\r
 \r
       colour = ucs.getColourFromString(string.substring(i + 1, j));\r
-      if ( i>0 && string.charAt(i-1)==',')\r
+      if (i > 0 && string.charAt(i - 1) == ',')\r
       {\r
         // clip the preceding comma as well\r
         i--;\r
@@ -743,8 +868,8 @@ public class AnnotationFile
 \r
     StringTokenizer st = new StringTokenizer(string, ",", true);\r
     String token;\r
-    boolean seenContent=false;\r
-    int pass=0;\r
+    boolean seenContent = false;\r
+    int pass = 0;\r
     while (st.hasMoreTokens())\r
     {\r
       pass++;\r
@@ -759,7 +884,9 @@ public class AnnotationFile
         }\r
         seenContent = false;\r
         continue;\r
-      } else {\r
+      }\r
+      else\r
+      {\r
         seenContent = true;\r
       }\r
 \r
@@ -767,7 +894,7 @@ public class AnnotationFile
       {\r
         try\r
         {\r
-          displayChar = token; \r
+          displayChar = token;\r
           // foo\r
           value = new Float(token).floatValue();\r
           parsedValue = true;\r
@@ -775,13 +902,17 @@ public class AnnotationFile
         } catch (NumberFormatException ex)\r
         {\r
         }\r
-      } else {\r
-        if (token.length()==1)\r
+      }\r
+      else\r
+      {\r
+        if (token.length() == 1)\r
         {\r
           displayChar = token;\r
         }\r
       }\r
-      if (hasSymbols && (token.equals("H") || token.equals("E") || token.equals(" ")))\r
+      if (hasSymbols\r
+              && (token.equals("H") || token.equals("E") || token\r
+                      .equals(" ")))\r
       {\r
         // Either this character represents a helix or sheet\r
         // or an integer which can be displayed\r
@@ -791,26 +922,29 @@ public class AnnotationFile
           displayChar = "";\r
         }\r
       }\r
-      else if (desc == null || (parsedValue && pass>2))\r
+      else if (desc == null || (parsedValue && pass > 2))\r
       {\r
         desc = token;\r
       }\r
 \r
     }\r
-//    if (!dcset && string.charAt(string.length() - 1) == ',')\r
-//    {\r
-//      displayChar = " "; // empty display char symbol.\r
-//    }\r
-    if (displayChar != null && desc!=null && desc.length()==1) \r
+    // if (!dcset && string.charAt(string.length() - 1) == ',')\r
+    // {\r
+    // displayChar = " "; // empty display char symbol.\r
+    // }\r
+    if (displayChar != null && desc != null && desc.length() == 1)\r
     {\r
       if (displayChar.length() > 1)\r
       {\r
-        // switch desc and displayChar - legacy support  \r
+        // switch desc and displayChar - legacy support\r
         String tmp = displayChar;\r
         displayChar = desc;\r
         desc = tmp;\r
-      } else {\r
-        if (displayChar.equals(desc)) {\r
+      }\r
+      else\r
+      {\r
+        if (displayChar.equals(desc))\r
+        {\r
           // duplicate label - hangover from the 'robust parser' above\r
           desc = null;\r
         }\r
@@ -999,33 +1133,38 @@ public class AnnotationFile
 \r
   void addRowProperties(AlignmentI al, StringTokenizer st)\r
   {\r
-    String label = st.nextToken(),keyValue,key,value;\r
-    boolean scaletofit=false,centerlab=false,showalllabs=false;\r
-    while (st.hasMoreTokens()) {\r
-      keyValue=st.nextToken();\r
+    String label = st.nextToken(), keyValue, key, value;\r
+    boolean scaletofit = false, centerlab = false, showalllabs = false;\r
+    while (st.hasMoreTokens())\r
+    {\r
+      keyValue = st.nextToken();\r
       key = keyValue.substring(0, keyValue.indexOf("="));\r
       value = keyValue.substring(keyValue.indexOf("=") + 1);\r
-      if (key.equalsIgnoreCase("scaletofit")) {\r
+      if (key.equalsIgnoreCase("scaletofit"))\r
+      {\r
         scaletofit = Boolean.valueOf(value).booleanValue();\r
       }\r
-        if (key.equalsIgnoreCase("showalllabs")) {\r
-          showalllabs = Boolean.valueOf(value).booleanValue();\r
-        }\r
-        if (key.equalsIgnoreCase("centrelabs")) {\r
-          centerlab = Boolean.valueOf(value).booleanValue();\r
-    }\r
-        AlignmentAnnotation[] alr = al.getAlignmentAnnotation(); \r
-        for (int i = 0; i < alr.length; i++)\r
+      if (key.equalsIgnoreCase("showalllabs"))\r
+      {\r
+        showalllabs = Boolean.valueOf(value).booleanValue();\r
+      }\r
+      if (key.equalsIgnoreCase("centrelabs"))\r
+      {\r
+        centerlab = Boolean.valueOf(value).booleanValue();\r
+      }\r
+      AlignmentAnnotation[] alr = al.getAlignmentAnnotation();\r
+      for (int i = 0; i < alr.length; i++)\r
+      {\r
+        if (alr[i].label.equalsIgnoreCase(label))\r
         {\r
-          if (alr[i].label.equalsIgnoreCase(label))\r
-          {\r
-            alr[i].centreColLabels = centerlab;\r
-            alr[i].scaleColLabel = scaletofit;\r
-            alr[i].showAllColLabels = showalllabs;\r
-          }\r
+          alr[i].centreColLabels = centerlab;\r
+          alr[i].scaleColLabel = scaletofit;\r
+          alr[i].showAllColLabels = showalllabs;\r
         }\r
+      }\r
     }\r
   }\r
+\r
   void addProperties(AlignmentI al, StringTokenizer st)\r
   {\r
 \r