GRAPH_TYPE. The allowed values of GRAPH_TYPE and the format of their respective value fields (with the trailing "<strong>|</strong>" 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
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	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	<em>group_name</em></pre>
+Group association is turned off for subsequent annotation rows by
+<pre>GROUP_REF	<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
COMBINE	<em>graph_1_name</em>	<em>graph_2_name</em>
GRAPHLINE	<em>graph_name</em>	<em>value</em>	<em>label</em>	<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	<em>Row label</em>	<em>centrelabs=true( or false)</em>	<em>showalllabs=true(default is false)</em>	<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>
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>
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:
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
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
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
.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
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
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
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
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
}\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
continue;\r
}\r
\r
+ // Parse out the annotation row\r
graphStyle = AlignmentAnnotation.getGraphValueFromString(token);\r
label = st.nextToken();\r
\r
}\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
// 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
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
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
\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
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
\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
}\r
seenContent = false;\r
continue;\r
- } else {\r
+ }\r
+ else\r
+ {\r
seenContent = true;\r
}\r
\r
{\r
try\r
{\r
- displayChar = token; \r
+ displayChar = token;\r
// foo\r
value = new Float(token).floatValue();\r
parsedValue = true;\r
} 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
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
\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