+++ /dev/null
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- *
- * This file is part of Jalview.
- *
- * 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.
- *
- * 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 <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-
-import jalview.workers.FeatureCounterI;
-import jalview.workers.AlignmentAnnotationFactory;
-
-/*
- * Example script that registers two alignment annotation calculators
- * - one that counts residues in a column with Pfam annotation
- * - one that counts only charged residues with Pfam annotation
- *
- * To try:
- * 1. load uniref50.fa from the examples folder
- * 2. load features onto it from from examples/exampleFeatures.txt
- * 3. Open this script in the Groovy console.
- * 4. Either execute this script from the console, or via Calculate->Run Groovy Script
-
- * To explore further, try changing this script to count other kinds of occurrences of
- * residue and sequence features at columns in an alignment.
- */
-
-/*
- * A closure that returns true for any Charged residue
- */
-def isCharged = { residue ->
- switch(residue) {
- case ['D', 'd', 'E', 'e', 'H', 'h', 'K', 'k', 'R', 'r']:
- return true
- }
- false
-}
-
-/*
- * A closure that returns 1 if sequence features include type 'Pfam', else 0
- * Argument should be a list of SequenceFeature
- */
-def hasPfam = { features ->
- for (sf in features)
- {
- /*
- * Here we inspect the type of the sequence feature.
- * You can also test sf.description, sf.score, sf.featureGroup,
- * sf.strand, sf.phase, sf.begin, sf.end
- * or sf.getValue(attributeName) for GFF 'column 9' properties
- */
- if ("Pfam".equals(sf.type))
- {
- return true
- }
- }
- false
-}
-
-/*
- * Closure that computes an annotation based on
- * presence of particular residues and features
- * Parameters are
- * - the name (label) for the alignment annotation
- * - the description (tooltip) for the annotation
- * - a closure (groovy function) that tests whether to include a residue
- * - a closure that tests whether to increment count based on sequence features
- */
-def getColumnCounter = { name, desc, acceptResidue, acceptFeatures ->
- [
- getName: { name },
- getDescription: { desc },
- getMinColour: { [0, 255, 255] }, // cyan
- getMaxColour: { [0, 0, 255] }, // blue
- count:
- { res, feats ->
- def c = 0
- if (acceptResidue.call(res))
- {
- if (acceptFeatures.call(feats))
- {
- c++
- }
- }
- c
- }
- ] as FeatureCounterI
-}
-
-/*
- * Define an annotation row that counts any residue with Pfam domain annotation
- */
-def pfamAnnotation = getColumnCounter("Pfam", "Count of residues with Pfam domain annotation", {true}, hasPfam)
-
-/*
- * Define an annotation row that counts charged residues with Pfam domain annotation
- */
-def chargedPfamAnnotation = getColumnCounter("Pfam charged", "Count of charged residues with Pfam domain annotation", isCharged, hasPfam)
-
-/*
- * Register the annotations
- */
-AlignmentAnnotationFactory.newCalculator(pfamAnnotation)
-AlignmentAnnotationFactory.newCalculator(chargedPfamAnnotation)
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * 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.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+
+import jalview.workers.AlignmentAnnotationFactory;
+import jalview.workers.FeatureSetCounterI;
+
+/*
+ * Example script to compute two alignment annotations
+ * - count of Phosphorylation features
+ * - count of Turn features
+ * To try this, first load example file uniref50.fa and load on features file
+ * exampleFeatures.txt, before running this script
+ *
+ * The script only needs to be run once - it will be registered by Jalview
+ * and recalculated automatically when the alignment changes.
+ *
+ * Note: The feature api provided by 2.10.2 is not compatible with scripts
+ * that worked with earlier Jalview versions. Apologies for the inconvenience.
+ */
+
+def annotator =
+ [
+ getNames: { ['Phosphorylation', 'Turn'] as String[] },
+ getDescriptions: { ['Count of Phosphorylation features', 'Count of Turn features'] as String[] },
+ getMinColour: { [0, 255, 255] as int[] }, // cyan
+ getMaxColour: { [0, 0, 255] as int[] }, // blue
+ count:
+ { res, feats ->
+ int phos
+ int turn
+ for (sf in feats)
+ {
+ /*
+ * Here we inspect the type of the sequence feature.
+ * You can also test sf.description, sf.score, sf.featureGroup,
+ * sf.strand, sf.phase, sf.begin, sf.end
+ * or sf.getValue(attributeName) for GFF 'column 9' properties
+ */
+ if (sf.type.contains('TURN'))
+ {
+ turn++
+ }
+ if (sf.type.contains('PHOSPHORYLATION'))
+ {
+ phos++
+ }
+ }
+ [phos, turn] as int[]
+ }
+ ] as FeatureSetCounterI
+
+/*
+ * Register the annotation calculator with Jalview
+ */
+AlignmentAnnotationFactory.newCalculator(annotator)
+++ /dev/null
-import jalview.workers.AlignmentAnnotationFactory;
-import jalview.workers.AnnotationProviderI;
-import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.Annotation;
-import jalview.util.ColorUtils;
-import jalview.util.Comparison;
-import java.awt.Color;
-
-/*
- * Example script to compute two alignment annotations
- * - count of Phosphorylation features
- * - count of Turn features
- * To try this, first load example file uniref50.fa and load on features file
- * exampleFeatures.txt, before running this script
- *
- * The script only needs to be run once - it will be registered by Jalview
- * and recalculated automatically when the alignment changes.
- */
-
-/*
- * A closure that returns true if value includes "PHOSPHORYLATION"
- */
-def phosCounter = { type -> type.contains("PHOSPHORYLATION") }
-
-/*
- * A closure that returns true if value includes "TURN"
- */
-def turnCounter = { type -> type.contains("TURN") }
-
-/*
- * A closure that computes and returns an array of Annotation values,
- * one for each column of the alignment
- */
-def getAnnotations(al, fr, counter)
-{
- def width = al.width
- def counts = new int[width]
- def max = 0
-
- /*
- * count features in each column, record the maximum value
- */
- for (col = 0 ; col < width ; col++)
- {
- def count = 0
- for (row = 0 ; row < al.height ; row++)
- {
- seq = al.getSequenceAt(row)
- if (seq != null && col < seq.getLength())
- {
- def res = seq.getCharAt(col)
- if (!Comparison.isGap(res))
- {
- pos = seq.findPosition(col)
- features = fr.findFeaturesAtRes(seq, pos)
- for (feature in features)
- {
- if (counter.call(feature.type))
- {
- count++
- }
- }
- }
- }
- }
- counts[col] = count
- if (count > max)
- {
- max = count
- }
- }
-
- /*
- * make the Annotation objects, with a graduated colour scale
- * (from min value to max value) for the histogram bars
- */
- def zero = '0' as char
- def anns = new Annotation[width]
- for (col = 0 ; col < width ; col++)
- {
- def c = counts[col]
- if (c > 0)
- {
- Color color = ColorUtils.getGraduatedColour(c, 0, Color.cyan,
- max, Color.blue)
- anns[col] = AlignmentAnnotationFactory.newAnnotation(String.valueOf(c),
- String.valueOf(c), zero, c, color)
- }
- }
- anns
-}
-
-/*
- * Define the method that performs the calculations, and builds two
- * AlignmentAnnotation objects
- */
-def annotator =
- [ calculateAnnotation: { al, fr ->
- def phosAnns = getAnnotations(al, fr, phosCounter)
- def ann1 = AlignmentAnnotationFactory.newAlignmentAnnotation("Phosphorylation", "Count of Phosphorylation features", phosAnns)
- def turnAnns = getAnnotations(al, fr, turnCounter)
- def ann2 = AlignmentAnnotationFactory.newAlignmentAnnotation("Turn", "Count of Turn features", turnAnns)
- return [ann1, ann2]
- }
- ] as AnnotationProviderI
-
-/*
- * Register the annotation calculator with Jalview
- */
-AlignmentAnnotationFactory.newCalculator(annotator)
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * 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.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+import jalview.bin.Jalview
+import jalview.workers.FeatureSetCounterI
+import jalview.workers.AlignmentAnnotationFactory
+
+/*
+ * Demonstration of FeatureSetCounterI
+ * compute annotation tracks counting number of displayed
+ * features of each type in each column
+ */
+
+/*
+ * discover features on the current view
+ */
+
+def featuresDisp=Jalview.currentAlignFrame.currentView.featuresDisplayed
+if (featuresDisp == null) {
+ print 'Need at least one feature visible on alignment'
+}
+def visibleFeatures=featuresDisp.visibleFeatures.toList()
+assert 'java.util.ArrayList' == visibleFeatures.class.name
+
+/*
+ * A closure that returns an array of features present
+ * for each feature type in visibleFeatures
+ * Argument 'features' will be a list of SequenceFeature
+ */
+def getCounts =
+ { features ->
+ int[] obs = new int[visibleFeatures.size]
+ for (sf in features)
+ {
+ /*
+ * Here we inspect the type of the sequence feature.
+ * You can also test sf.description, sf.score, sf.featureGroup,
+ * sf.strand, sf.phase, sf.begin, sf.end
+ * or sf.getValue(attributeName) for GFF 'column 9' properties
+ */
+ int pos = 0
+ for (type in visibleFeatures)
+ {
+ if (type.equals(sf.type))
+ {
+ obs[pos]++
+ }
+ pos++
+ }
+ }
+ obs
+}
+
+/*
+ * Define something that counts each visible feature type
+ */
+def columnSetCounter =
+ [
+ getNames: { visibleFeatures as String[] },
+ getDescriptions: { visibleFeatures as String[] },
+ getMinColour: { [0, 255, 255] as int[] }, // cyan
+ getMaxColour: { [0, 0, 255] as int[] }, // blue
+ count:
+ { res, feats ->
+ getCounts.call(feats)
+ }
+ ] as FeatureSetCounterI
+
+/*
+ * and register the counter
+ */
+AlignmentAnnotationFactory.newCalculator(columnSetCounter)
<mapID target="memory" url="html/memory.html" />
<mapID target="groovy" url="html/features/groovy.html" />
- <mapID target="groovy.featurecounter" url="html/groovy/featureCounter.html" />
+ <mapID target="groovy.featurescounter" url="html/groovy/featuresCounter.html" />
<mapID target="privacy" url="html/privacy.html" />
<mapID target="vamsas" url="html/vamsas/index.html"/>
<mapID target="aminoAcids" url="html/misc/aminoAcids.html" />
<tocitem text="Jalview Documentation" target="home" expand="true">
<tocitem text="What's new" target="new" expand="true">
<tocitem text="Latest Release Notes" target="release"/>
+ <tocitem text="Groovy Features Counter example" target="groovy.featurescounter"/>
<tocitem text="Omit hidden regions in Overview" target="overview"/>
</tocitem>
<tocitem text="Preferences" target="preferences" />
<tocitem text="Memory Settings" target="memory" expand="false"/>
<tocitem text="Scripting with Groovy" target="groovy">
- <tocitem text="Groovy Feature Counter example" target="groovy.featurecounter"/>
+ <tocitem text="Groovy Features Counter example" target="groovy.featurescounter"/>
</tocitem>
<tocitem text="Command Line" target="commandline" expand="false">
<tocitem text="Command Line Arguments" target="clarguments" />
simplified the alignment analysis programming interface in Jalview
2.10 to make it easy for you to add your own dynamic annotation
tracks with Groovy. Have a look at the <a
- href="../groovy/featureCounter.html">featureCounter.groovy</a>
+ href="../groovy/featuresCounter.html">featuresCounter.groovy</a>
example for more information.
</p>
+++ /dev/null
-<html>
-<!--
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- *
- * This file is part of Jalview.
- *
- * 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.
- *
- * 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 <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- -->
-<head>
-<title>Extending Jalview with Groovy - Feature Counter Example</title>
-</head>
-<body>
- <p>
- <strong>Extending Jalview with Groovy - A customisable
- feature counter</strong><br /> <br />The groovy script below shows how to
- add a new calculation track to a Jalview alignment window.
- </p>
- <p>As currently written, it will add two tracks to a protein
- alignment view which count Pfam features in each column, and ones
- where a charge residue also occur.</p>
- <p>To try it for yourself:</p>
- <ol>
- <li>Copy and paste it into the groovy script console</li>
- <li>Load the example Feredoxin project (the one that opens by
- default when you first launched Jalview)</li>
- <li>Select <strong>Calculations→Execute Groovy
- Script</strong> from the alignment window's menu bar to run the script on
- the current view.
- </li>
- </ol>
- <em><a
- href="http://www.jalview.org/examples/groovy/featureCounter.groovy">http://www.jalview.org/examples/groovy/featureCounter.groovy</a>
- - rendered with <a href="http://hilite.me">hilite.me</a></em>
- <!-- HTML generated using hilite.me -->
- <div
- style="background: #ffffff; overflow: auto; width: auto; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;">
- <pre style="margin: 0; line-height: 125%">
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * Jalview - A Sequence Alignment Editor and Viewer (Version 2.10)</span>
-<span style="color: #888888"> * Copyright (C) 2016 The Jalview Authors</span>
-<span style="color: #888888"> * </span>
-<span style="color: #888888"> * This file is part of Jalview.</span>
-<span style="color: #888888"> * </span>
-<span style="color: #888888"> * Jalview is free software: you can redistribute it and/or</span>
-<span style="color: #888888"> * modify it under the terms of the GNU General Public License </span>
-<span style="color: #888888"> * as published by the Free Software Foundation, either version 3</span>
-<span style="color: #888888"> * of the License, or (at your option) any later version.</span>
-<span style="color: #888888"> * </span>
-<span style="color: #888888"> * Jalview is distributed in the hope that it will be useful, but </span>
-<span style="color: #888888"> * WITHOUT ANY WARRANTY; without even the implied warranty </span>
-<span style="color: #888888"> * of MERCHANTABILITY or FITNESS FOR A PARTICULAR </span>
-<span style="color: #888888"> * PURPOSE. See the GNU General Public License for more details.</span>
-<span style="color: #888888"> * </span>
-<span style="color: #888888"> * You should have received a copy of the GNU General Public License</span>
-<span style="color: #888888"> * along with Jalview. If not, see <http://www.gnu.org/licenses/>.</span>
-<span style="color: #888888"> * The Jalview Authors are detailed in the 'AUTHORS' file.</span>
-<span style="color: #888888"> */</span>
-
-<span style="color: #008800; font-weight: bold">import</span> <span
- style="color: #0e84b5; font-weight: bold">jalview.workers.FeatureCounterI</span><span
- style="color: #333333">;</span>
-<span style="color: #008800; font-weight: bold">import</span> <span
- style="color: #0e84b5; font-weight: bold">jalview.workers.AlignmentAnnotationFactory</span><span
- style="color: #333333">;</span>
-
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * Example script that registers two alignment annotation calculators</span>
-<span style="color: #888888"> * - one that counts residues in a column with Pfam annotation</span>
-<span style="color: #888888"> * - one that counts only charged residues with Pfam annotation</span>
-<span style="color: #888888"> *</span>
-<span style="color: #888888"> * To try:</span>
-<span style="color: #888888"> * 1. load uniref50.fa from the examples folder</span>
-<span style="color: #888888"> * 2. load features onto it from from examples/exampleFeatures.txt</span>
-<span style="color: #888888"> * 3. Open this script in the Groovy console.</span>
-<span style="color: #888888"> * 4. Either execute this script from the console, or via Calculate->Run Groovy Script</span>
-<span style="color: #888888"> </span>
-<span style="color: #888888"> * To explore further, try changing this script to count other kinds of occurrences of </span>
-<span style="color: #888888"> * residue and sequence features at columns in an alignment.</span>
-<span style="color: #888888"> */</span>
-
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * A closure that returns true for any Charged residue</span>
-<span style="color: #888888"> */</span>
-<span style="color: #333399; font-weight: bold">def</span> isCharged <span
- style="color: #333333">=</span> <span style="color: #333333">{</span> residue <span
- style="color: #333333">-></span>
- <span style="color: #008800; font-weight: bold">switch</span><span
- style="color: #333333">(</span>residue<span
- style="color: #333333">)</span> <span style="color: #333333">{</span>
- <span style="color: #008800; font-weight: bold">case</span> <span
- style="color: #333333">[</span><span
- style="background-color: #fff0f0">'D'</span><span
- style="color: #333333">,</span> <span
- style="background-color: #fff0f0">'d'</span><span
- style="color: #333333">,</span> <span
- style="background-color: #fff0f0">'E'</span><span
- style="color: #333333">,</span> <span
- style="background-color: #fff0f0">'e'</span><span
- style="color: #333333">,</span> <span
- style="background-color: #fff0f0">'H'</span><span
- style="color: #333333">,</span> <span
- style="background-color: #fff0f0">'h'</span><span
- style="color: #333333">,</span> <span
- style="background-color: #fff0f0">'K'</span><span
- style="color: #333333">,</span> <span
- style="background-color: #fff0f0">'k'</span><span
- style="color: #333333">,</span> <span
- style="background-color: #fff0f0">'R'</span><span
- style="color: #333333">,</span> <span
- style="background-color: #fff0f0">'r'</span><span
- style="color: #333333">]:</span>
- <span style="color: #008800; font-weight: bold">return</span> <span
- style="color: #008800; font-weight: bold">true</span>
- <span style="color: #333333">}</span>
- <span style="color: #008800; font-weight: bold">false</span>
-<span style="color: #333333">}</span>
-
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * A closure that returns 1 if sequence features include type 'Pfam', else 0</span>
-<span style="color: #888888"> * Argument should be a list of SequenceFeature </span>
-<span style="color: #888888"> */</span>
-<span style="color: #333399; font-weight: bold">def</span> hasPfam <span
- style="color: #333333">=</span> <span style="color: #333333">{</span> features <span
- style="color: #333333">-></span>
- <span style="color: #008800; font-weight: bold">for</span> <span
- style="color: #333333">(</span>sf <span
- style="color: #008800; font-weight: bold">in</span> features<span
- style="color: #333333">)</span>
- <span style="color: #333333">{</span>
- <span style="color: #888888">/*</span>
-<span style="color: #888888"> * Here we inspect the type of the sequence feature.</span>
-<span style="color: #888888"> * You can also test sf.description, sf.score, sf.featureGroup,</span>
-<span style="color: #888888"> * sf.strand, sf.phase, sf.begin, sf.end</span>
-<span style="color: #888888"> * or sf.getValue(attributeName) for GFF 'column 9' properties</span>
-<span style="color: #888888"> */</span>
- <span style="color: #008800; font-weight: bold">if</span> <span
- style="color: #333333">(</span><span
- style="background-color: #fff0f0">"Pfam"</span><span
- style="color: #333333">.</span><span style="color: #0000CC">equals</span><span
- style="color: #333333">(</span>sf<span style="color: #333333">.</span><span
- style="color: #0000CC">type</span><span style="color: #333333">))</span>
- <span style="color: #333333">{</span>
- <span style="color: #008800; font-weight: bold">return</span> <span
- style="color: #008800; font-weight: bold">true</span>
- <span style="color: #333333">}</span>
- <span style="color: #333333">}</span>
- <span style="color: #008800; font-weight: bold">false</span>
-<span style="color: #333333">}</span>
-
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * Closure that computes an annotation based on </span>
-<span style="color: #888888"> * presence of particular residues and features</span>
-<span style="color: #888888"> * Parameters are</span>
-<span style="color: #888888"> * - the name (label) for the alignment annotation</span>
-<span style="color: #888888"> * - the description (tooltip) for the annotation</span>
-<span style="color: #888888"> * - a closure (groovy function) that tests whether to include a residue</span>
-<span style="color: #888888"> * - a closure that tests whether to increment count based on sequence features </span>
-<span style="color: #888888"> */</span>
-<span style="color: #333399; font-weight: bold">def</span> getColumnCounter <span
- style="color: #333333">=</span> <span style="color: #333333">{</span> name<span
- style="color: #333333">,</span> desc<span style="color: #333333">,</span> acceptResidue<span
- style="color: #333333">,</span> acceptFeatures <span
- style="color: #333333">-></span>
- <span style="color: #333333">[</span>
- <span style="color: #997700; font-weight: bold">getName:</span> <span
- style="color: #333333">{</span> name <span
- style="color: #333333">},</span>
- <span style="color: #997700; font-weight: bold">getDescription:</span> <span
- style="color: #333333">{</span> desc <span
- style="color: #333333">},</span>
- <span style="color: #997700; font-weight: bold">getMinColour:</span> <span
- style="color: #333333">{</span> <span style="color: #333333">[</span><span
- style="color: #0000DD; font-weight: bold">0</span><span
- style="color: #333333">,</span> <span
- style="color: #0000DD; font-weight: bold">255</span><span
- style="color: #333333">,</span> <span
- style="color: #0000DD; font-weight: bold">255</span><span
- style="color: #333333">]</span> <span style="color: #333333">},</span> <span
- style="color: #888888">// cyan</span>
- <span style="color: #997700; font-weight: bold">getMaxColour:</span> <span
- style="color: #333333">{</span> <span style="color: #333333">[</span><span
- style="color: #0000DD; font-weight: bold">0</span><span
- style="color: #333333">,</span> <span
- style="color: #0000DD; font-weight: bold">0</span><span
- style="color: #333333">,</span> <span
- style="color: #0000DD; font-weight: bold">255</span><span
- style="color: #333333">]</span> <span style="color: #333333">},</span> <span
- style="color: #888888">// blue</span>
- <span style="color: #997700; font-weight: bold">count:</span>
- <span style="color: #333333">{</span> res<span
- style="color: #333333">,</span> feats <span
- style="color: #333333">-></span>
- <span style="color: #333399; font-weight: bold">def</span> c <span
- style="color: #333333">=</span> <span
- style="color: #0000DD; font-weight: bold">0</span>
- <span style="color: #008800; font-weight: bold">if</span> <span
- style="color: #333333">(</span>acceptResidue<span
- style="color: #333333">.</span><span style="color: #0000CC">call</span><span
- style="color: #333333">(</span>res<span style="color: #333333">))</span>
- <span style="color: #333333">{</span>
- <span style="color: #008800; font-weight: bold">if</span> <span
- style="color: #333333">(</span>acceptFeatures<span
- style="color: #333333">.</span><span style="color: #0000CC">call</span><span
- style="color: #333333">(</span>feats<span style="color: #333333">))</span>
- <span style="color: #333333">{</span>
- c<span style="color: #333333">++</span>
- <span style="color: #333333">}</span>
- <span style="color: #333333">}</span>
- c
- <span style="color: #333333">}</span>
- <span style="color: #333333">]</span> <span
- style="color: #008800; font-weight: bold">as</span> FeatureCounterI
-<span style="color: #333333">}</span>
-
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * Define an annotation row that counts any residue with Pfam domain annotation</span>
-<span style="color: #888888"> */</span>
-<span style="color: #333399; font-weight: bold">def</span> pfamAnnotation <span
- style="color: #333333">=</span> getColumnCounter<span
- style="color: #333333">(</span><span
- style="background-color: #fff0f0">"Pfam"</span><span
- style="color: #333333">,</span> <span
- style="background-color: #fff0f0">"Count of residues with Pfam domain annotation"</span><span
- style="color: #333333">,</span> <span style="color: #333333">{</span><span
- style="color: #008800; font-weight: bold">true</span><span
- style="color: #333333">},</span> hasPfam<span
- style="color: #333333">)</span>
-
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * Define an annotation row that counts charged residues with Pfam domain annotation</span>
-<span style="color: #888888"> */</span>
-<span style="color: #333399; font-weight: bold">def</span> chargedPfamAnnotation <span
- style="color: #333333">=</span> getColumnCounter<span
- style="color: #333333">(</span><span
- style="background-color: #fff0f0">"Pfam charged"</span><span
- style="color: #333333">,</span> <span
- style="background-color: #fff0f0">"Count of charged residues with Pfam domain annotation"</span><span
- style="color: #333333">,</span> isCharged<span
- style="color: #333333">,</span> hasPfam<span
- style="color: #333333">)</span>
-
-<span style="color: #888888">/*</span>
-<span style="color: #888888"> * Register the annotations</span>
-<span style="color: #888888"> */</span>
-AlignmentAnnotationFactory<span style="color: #333333">.</span><span
- style="color: #0000CC">newCalculator</span><span
- style="color: #333333">(</span>pfamAnnotation<span
- style="color: #333333">)</span>
-AlignmentAnnotationFactory<span style="color: #333333">.</span><span
- style="color: #0000CC">newCalculator</span><span
- style="color: #333333">(</span>chargedPfamAnnotation<span
- style="color: #333333">)</span>
-</pre>
- </div>
-</body>
-</html>
--- /dev/null
+<html>
+<!--
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * 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.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ -->
+<head>
+<title>Extending Jalview with Groovy - Feature Counter Example</title>
+</head>
+<body>
+ <p>
+ <strong>Extending Jalview with Groovy - A customisable
+ feature counter</strong><br /> <br />The groovy script below shows how to
+ add a new calculation track to a Jalview alignment window.
+ </p>
+ <p>As currently written, it will add two tracks to a protein
+ alignment view which count Pfam features in each column, and ones
+ where a charge residue also occur.</p>
+ <p>To try it for yourself:</p>
+ <ol>
+ <li>Copy and paste it into the groovy script console</li>
+ <li>Load the example Feredoxin project (the one that opens by
+ default when you first launched Jalview)</li>
+ <li>Select <strong>Calculations→Execute Groovy
+ Script</strong> from the alignment window's menu bar to run the script on
+ the current view.
+ </li>
+ </ol>
+ <strong>Please note: The 2.10.2 feature counting interface is not compatible with earlier versions.</strong><br/><br/>
+ <em><a
+ href="http://www.jalview.org/examples/groovy/featuresCounter.groovy">http://www.jalview.org/examples/groovy/featuresCounter.groovy</a>
+ - rendered with <a href="http://hilite.me">hilite.me</a></em>
+ <!-- HTML generated using hilite.me --><div style="background: #f8f8f8; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #408080; font-style: italic">/*</span>
+<span style="color: #408080; font-style: italic"> * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)</span>
+<span style="color: #408080; font-style: italic"> * Copyright (C) $$Year-Rel$$ The Jalview Authors</span>
+<span style="color: #408080; font-style: italic"> * </span>
+<span style="color: #408080; font-style: italic"> * This file is part of Jalview.</span>
+<span style="color: #408080; font-style: italic"> * </span>
+<span style="color: #408080; font-style: italic"> * Jalview is free software: you can redistribute it and/or</span>
+<span style="color: #408080; font-style: italic"> * modify it under the terms of the GNU General Public License </span>
+<span style="color: #408080; font-style: italic"> * as published by the Free Software Foundation, either version 3</span>
+<span style="color: #408080; font-style: italic"> * of the License, or (at your option) any later version.</span>
+<span style="color: #408080; font-style: italic"> * </span>
+<span style="color: #408080; font-style: italic"> * Jalview is distributed in the hope that it will be useful, but </span>
+<span style="color: #408080; font-style: italic"> * WITHOUT ANY WARRANTY; without even the implied warranty </span>
+<span style="color: #408080; font-style: italic"> * of MERCHANTABILITY or FITNESS FOR A PARTICULAR </span>
+<span style="color: #408080; font-style: italic"> * PURPOSE. See the GNU General Public License for more details.</span>
+<span style="color: #408080; font-style: italic"> * </span>
+<span style="color: #408080; font-style: italic"> * You should have received a copy of the GNU General Public License</span>
+<span style="color: #408080; font-style: italic"> * along with Jalview. If not, see <http://www.gnu.org/licenses/>.</span>
+<span style="color: #408080; font-style: italic"> * The Jalview Authors are detailed in the 'AUTHORS' file.</span>
+<span style="color: #408080; font-style: italic"> */</span>
+
+<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">jalview.workers.AlignmentAnnotationFactory</span><span style="color: #666666">;</span>
+<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">jalview.workers.FeatureSetCounterI</span><span style="color: #666666">;</span>
+
+<span style="color: #408080; font-style: italic">/*</span>
+<span style="color: #408080; font-style: italic"> * Example script to compute two alignment annotations</span>
+<span style="color: #408080; font-style: italic"> * - count of Phosphorylation features</span>
+<span style="color: #408080; font-style: italic"> * - count of Turn features</span>
+<span style="color: #408080; font-style: italic"> * To try this, first load example file uniref50.fa and load on features file</span>
+<span style="color: #408080; font-style: italic"> * exampleFeatures.txt, before running this script</span>
+<span style="color: #408080; font-style: italic"> *</span>
+<span style="color: #408080; font-style: italic"> * The script only needs to be run once - it will be registered by Jalview</span>
+<span style="color: #408080; font-style: italic"> * and recalculated automatically when the alignment changes.</span>
+<span style="color: #408080; font-style: italic"> * </span>
+<span style="color: #408080; font-style: italic"> * Note: The feature api provided by 2.10.2 is not compatible with scripts</span>
+<span style="color: #408080; font-style: italic"> * that worked with earlier Jalview versions. Apologies for the inconvenience.</span>
+<span style="color: #408080; font-style: italic"> */</span>
+
+<span style="color: #B00040">def</span> annotator <span style="color: #666666">=</span>
+ <span style="color: #666666">[</span>
+ <span style="color: #A0A000">getNames:</span> <span style="color: #666666">{</span> <span style="color: #666666">[</span><span style="color: #BA2121">'Phosphorylation'</span><span style="color: #666666">,</span> <span style="color: #BA2121">'Turn'</span><span style="color: #666666">]</span> <span style="color: #008000; font-weight: bold">as</span> String<span style="color: #666666">[]</span> <span style="color: #666666">},</span>
+ <span style="color: #A0A000">getDescriptions:</span> <span style="color: #666666">{</span> <span style="color: #666666">[</span><span style="color: #BA2121">'Count of Phosphorylation features'</span><span style="color: #666666">,</span> <span style="color: #BA2121">'Count of Turn features'</span><span style="color: #666666">]</span> <span style="color: #008000; font-weight: bold">as</span> String<span style="color: #666666">[]</span> <span style="color: #666666">},</span>
+ <span style="color: #A0A000">getMinColour:</span> <span style="color: #666666">{</span> <span style="color: #666666">[0,</span> <span style="color: #666666">255,</span> <span style="color: #666666">255]</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #B00040">int</span><span style="color: #666666">[]</span> <span style="color: #666666">},</span> <span style="color: #408080; font-style: italic">// cyan</span>
+ <span style="color: #A0A000">getMaxColour:</span> <span style="color: #666666">{</span> <span style="color: #666666">[0,</span> <span style="color: #666666">0,</span> <span style="color: #666666">255]</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #B00040">int</span><span style="color: #666666">[]</span> <span style="color: #666666">},</span> <span style="color: #408080; font-style: italic">// blue</span>
+ <span style="color: #A0A000">count:</span>
+ <span style="color: #666666">{</span> res<span style="color: #666666">,</span> feats <span style="color: #666666">-></span>
+ <span style="color: #B00040">int</span> phos
+ <span style="color: #B00040">int</span> turn
+ <span style="color: #0000FF">for</span> <span style="color: #666666">(</span>sf <span style="color: #008000; font-weight: bold">in</span> feats<span style="color: #666666">)</span>
+ <span style="color: #666666">{</span>
+ <span style="color: #408080; font-style: italic">/*</span>
+<span style="color: #408080; font-style: italic"> * Here we inspect the type of the sequence feature.</span>
+<span style="color: #408080; font-style: italic"> * You can also test sf.description, sf.score, sf.featureGroup,</span>
+<span style="color: #408080; font-style: italic"> * sf.strand, sf.phase, sf.begin, sf.end</span>
+<span style="color: #408080; font-style: italic"> * or sf.getValue(attributeName) for GFF 'column 9' properties</span>
+<span style="color: #408080; font-style: italic"> */</span>
+ <span style="color: #008000; font-weight: bold">if</span> <span style="color: #666666">(</span>sf<span style="color: #666666">.</span><span style="color: #7D9029">type</span><span style="color: #666666">.</span><span style="color: #7D9029">contains</span><span style="color: #666666">(</span><span style="color: #BA2121">'TURN'</span><span style="color: #666666">))</span>
+ <span style="color: #666666">{</span>
+ turn<span style="color: #666666">++</span>
+ <span style="color: #666666">}</span>
+ <span style="color: #008000; font-weight: bold">if</span> <span style="color: #666666">(</span>sf<span style="color: #666666">.</span><span style="color: #7D9029">type</span><span style="color: #666666">.</span><span style="color: #7D9029">contains</span><span style="color: #666666">(</span><span style="color: #BA2121">'PHOSPHORYLATION'</span><span style="color: #666666">))</span>
+ <span style="color: #666666">{</span>
+ phos<span style="color: #666666">++</span>
+ <span style="color: #666666">}</span>
+ <span style="color: #666666">}</span>
+ <span style="color: #666666">[</span>phos<span style="color: #666666">,</span> turn<span style="color: #666666">]</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #B00040">int</span><span style="color: #666666">[]</span>
+ <span style="color: #666666">}</span>
+ <span style="color: #666666">]</span> <span style="color: #008000; font-weight: bold">as</span> FeatureSetCounterI
+
+<span style="color: #408080; font-style: italic">/*</span>
+<span style="color: #408080; font-style: italic"> * Register the annotation calculator with Jalview</span>
+<span style="color: #408080; font-style: italic"> */</span>
+AlignmentAnnotationFactory<span style="color: #666666">.</span><span style="color: #7D9029">newCalculator</span><span style="color: #666666">(</span>annotator<span style="color: #666666">)</span>
+</pre></div>
+</body>
+</html>
label.remove_user_defined_colour = Remove user defined colour
label.you_must_select_least_two_sequences = You must select at least 2 sequences.
label.invalid_selection = Invalid Selection
-label.principal_component_analysis_must_take_least_four_input_sequences = Principal component analysis must take\nat least 4 input sequences.
label.sequence_selection_insufficient = Sequence selection insufficient
-label.you_need_more_two_sequences_selected_build_tree = You need to have more than two sequences selected to build a tree!
-label.you_need_more_than_n_sequences = You need to have more than {0} sequences
+label.you_need_at_least_n_sequences = You need to select at least {0} sequences
label.not_enough_sequences = Not enough sequences
label.selected_region_to_tree_may_only_contain_residues_or_gaps = The selected region to create a tree may\nonly contain residues or gaps.\nTry using the Pad function in the edit menu,\nor one of the multiple sequence alignment web services.
label.sequences_selection_not_aligned = Sequences in selection are not aligned
label.score_model_blosum62 = BLOSUM62
label.score_model_pam250 = PAM 250
label.score_model_smithwatermanscore = Puntuación entre secuencias alineadas por Smith-Waterman con matriz por defecto proteica / nucleotÃdica
-label.score_model_sequencefeaturesimilarity = Medida de distancia por cuenta promedia de caracterÃsticas no compartidas at sequence positions
+label.score_model_sequencefeaturesimilarity = Medida de distancia por cuenta promedia de caracterÃsticas no compartidas en posiciones de secuencia
label.score_model_conservation = Conservación de las propiedades fÃsico-quÃmicas
label.score_model_enhconservation = Conservación de las propiedades fÃsico-quÃmicas
label.status_bar = Barra de estado
label.remove_user_defined_colour = Eliminar el color definido por el usuario
label.you_must_select_least_two_sequences = Debes seleccionar al menos 2 secuencias.
label.invalid_selection = Selección inválida
-label.principal_component_analysis_must_take_least_four_input_sequences = El an\u00E1lisis de la componente principal debe tomar\nal menos 4 secuencias de entrada.
label.sequence_selection_insufficient = Selección de secuencias insuficiente
-label.you_need_more_two_sequences_selected_build_tree = necesitas seleccionar más de dos secuencias para construir un árbol!
+label.you_need_at_least_n_sequences = Necesitas seleccionar al menos {0} secuencias
label.not_enough_sequences = No suficientes secuencias
label.selected_region_to_tree_may_only_contain_residues_or_gaps = La regi\u00F3n seleccionada para construir un \u00E1rbol puede\ncontener s\u00F3lo residuos o espacios.\nPrueba usando la funci\u00F3n Pad en el men\u00FA de edici\u00F3n,\n o uno de los m\u00FAltiples servicios web de alineamiento de secuencias.
label.sequences_selection_not_aligned = Las secuencias seleccionadas no están alineadas
label.invalid_name = Nombre inválido !
label.output_seq_details = Seleccionar Detalles de la secuencia para ver todas
label.urllinks = Enlaces
-label.togglehidden = Show hidden regions
\ No newline at end of file
+label.quality_descr = Calidad de alineamiento basándose en puntuación Blosum62
+label.conservation_descr = Conservación del alineamiento total menos de {0}% huecos
+label.consensus_descr = % Identidad
+label.complement_consensus_descr = % Identidad para cDNA
+label.strucconsensus_descr = % Identidad para pares de bases
+label.occupancy_descr = Número de posiciones alineadas
+label.togglehidden = Show hidden regions
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
String id = sq.getName();
// get the default url with the sequence details filled in
+ if (urlProvider == null)
+ {
+ return;
+ }
String url = urlProvider.getPrimaryUrl(id);
String target = urlProvider.getPrimaryTarget(id);
try
// build a new links menu based on the current links + any non-positional
// features
- List<String> nlinks = urlProvider.getLinksForMenu();
-
+ List<String> nlinks;
+ if (urlProvider != null)
+ {
+ nlinks = urlProvider.getLinksForMenu();
+ }
+ else
+ {
+ nlinks = new ArrayList<String>();
+ }
SequenceFeature sf[] = sq == null ? null : sq.getSequenceFeatures();
for (int sl = 0; sf != null && sl < sf.length; sl++)
{
void getBoxColour(ResidueShaderI shader, SequenceI seq, int i)
{
- if (shader != null)
+ if (shader.getColourScheme() != null)
{
resBoxColour = shader.findColour(seq.getCharAt(i), i, seq);
}
*/
public class Annotation
{
+ /**
+ * the empty annotation - proxy for null entries in annotation row
+ */
+ public static final Annotation EMPTY_ANNOTATION = new Annotation("", "",
+ ' ', 0f);
+
/** Character label - also shown below histogram */
public String displayCharacter = "";
}
return sb.toString();
}
+
+ /**
+ * @return true if annot is 'whitespace' annotation (zero score, whitespace or
+ * zero length display character, label, description
+ */
+ public boolean isWhitespace()
+ {
+ return ((value == 0f)
+ && ((description == null) || (description.trim()
+ .length() == 0))
+ && ((displayCharacter == null) || (displayCharacter
+ .trim().length() == 0))
+ && (secondaryStructure == '\0' || (secondaryStructure == ' ')) && colour == null);
+ }
}
if (viewport.getSelectionGroup() != null
&& viewport.getSelectionGroup().getSize() > 0)
{
- if (viewport.getSelectionGroup().getSize() < 3)
- {
- JvOptionPane
- .showMessageDialog(
- Desktop.desktop,
- MessageManager
- .getString("label.you_need_more_two_sequences_selected_build_tree"),
- MessageManager
- .getString("label.not_enough_sequences"),
- JvOptionPane.WARNING_MESSAGE);
- return;
- }
-
SequenceGroup sg = viewport.getSelectionGroup();
/* Decide if the selection is a column region */
import jalview.analysis.scoremodels.SimilarityParams;
import jalview.api.analysis.ScoreModelI;
import jalview.api.analysis.SimilarityParamsI;
+import jalview.datamodel.SequenceGroup;
import jalview.util.MessageManager;
import java.awt.BorderLayout;
private static final Font VERDANA_11PT = new Font("Verdana", 0, 11);
+ private static final int MIN_TREE_SELECTION = 3;
+
+ private static final int MIN_PCA_SELECTION = 4;
+
AlignFrame af;
JRadioButton pca;
JComboBox<String> modelNames;
- JButton ok;
+ JButton calculate;
private JInternalFrame frame;
private JCheckBox shorterSequence;
+ final ComboBoxTooltipRenderer renderer = new ComboBoxTooltipRenderer();
+
+ List<String> tips = new ArrayList<String>();
+
/**
* Constructor
*
pca.setOpaque(false);
neighbourJoining = new JRadioButton(
MessageManager.getString("label.tree_calc_nj"));
+ neighbourJoining.setSelected(true);
averageDistance = new JRadioButton(
MessageManager.getString("label.tree_calc_av"));
neighbourJoining.setOpaque(false);
pcaBorderless.add(pca, FlowLayout.LEFT);
calcChoicePanel.add(pcaBorderless, FlowLayout.LEFT);
-
treePanel.add(neighbourJoining);
treePanel.add(averageDistance);
pca.addActionListener(calcChanged);
neighbourJoining.addActionListener(calcChanged);
averageDistance.addActionListener(calcChanged);
+
/*
* score models drop-down - with added tooltips!
*/
/*
* OK / Cancel buttons
*/
- ok = new JButton(MessageManager.getString("action.calculate"));
- ok.setFont(VERDANA_11PT);
- ok.addActionListener(new java.awt.event.ActionListener()
+ calculate = new JButton(MessageManager.getString("action.calculate"));
+ calculate.setFont(VERDANA_11PT);
+ calculate.addActionListener(new java.awt.event.ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
- ok_actionPerformed();
+ calculate_actionPerformed();
}
});
- JButton cancel = new JButton(MessageManager.getString("action.close"));
- cancel.setFont(VERDANA_11PT);
- cancel.addActionListener(new java.awt.event.ActionListener()
+ JButton close = new JButton(MessageManager.getString("action.close"));
+ close.setFont(VERDANA_11PT);
+ close.addActionListener(new java.awt.event.ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
- cancel_actionPerformed(e);
+ close_actionPerformed();
}
});
JPanel actionPanel = new JPanel();
actionPanel.setOpaque(false);
- actionPanel.add(ok);
- actionPanel.add(cancel);
+ actionPanel.add(calculate);
+ actionPanel.add(close);
boolean includeParams = false;
this.add(calcChoicePanel, BorderLayout.CENTER);
title = title + " (" + af.getViewport().viewName + ")";
}
- Desktop.addInternalFrame(frame,
- title, width,
- height, false);
+ Desktop.addInternalFrame(frame, title, width, height, false);
calcChoicePanel.doLayout();
revalidate();
/*
{
size = af.getViewport().getSelectionGroup().getSize();
}
- if (!(checkEnabled(pca, size, 4)
- | checkEnabled(neighbourJoining, size, 3) | checkEnabled(
- averageDistance, size, 3)))
+
+ /*
+ * disable calc options for which there is insufficient input data
+ * return value of true means enabled and selected
+ */
+ boolean checkPca = checkEnabled(pca, size, MIN_PCA_SELECTION);
+ boolean checkNeighbourJoining = checkEnabled(neighbourJoining, size,
+ MIN_TREE_SELECTION);
+ boolean checkAverageDistance = checkEnabled(averageDistance, size,
+ MIN_TREE_SELECTION);
+
+ if (checkPca || checkNeighbourJoining || checkAverageDistance)
{
- ok.setToolTipText(null);
- ok.setEnabled(true);
+ calculate.setToolTipText(null);
+ calculate.setEnabled(true);
}
else
{
- ok.setEnabled(false);
+ calculate.setEnabled(false);
}
- updateScoreModels(comboBox, tips);
+ updateScoreModels(modelNames, tips);
}
/**
* - size of input to calculation
* @param minsize
* - minimum size for calculation
- * @return true if size < minsize *and* calc.isSelected
+ * @return true if size >= minsize and calc.isSelected
*/
private boolean checkEnabled(JRadioButton calc, int size, int minsize)
{
String ttip = MessageManager.formatMessage(
- "label.you_need_more_than_n_sequences", minsize);
+ "label.you_need_at_least_n_sequences", minsize);
calc.setEnabled(size >= minsize);
if (!calc.isEnabled())
if (calc.isSelected())
{
modelNames.setEnabled(calc.isEnabled());
- if (!calc.isEnabled())
+ if (calc.isEnabled())
{
- ok.setEnabled(false);
- ok.setToolTipText(ttip);
return true;
}
+ else
+ {
+ calculate.setToolTipText(ttip);
+ }
}
return false;
}
- final JComboBox<String> comboBox = new JComboBox<String>();
-
- final ComboBoxTooltipRenderer renderer = new ComboBoxTooltipRenderer();
-
- List<String> tips = new ArrayList<String>();
-
/**
* A rather elaborate helper method (blame Swing, not me) that builds a
* drop-down list of score models (by name) with descriptions as tooltips.
*/
protected JComboBox<String> buildModelOptionsList()
{
- comboBox.setRenderer(renderer);
+ final JComboBox<String> scoreModelsCombo = new JComboBox<String>();
+ scoreModelsCombo.setRenderer(renderer);
/*
* show tooltip on mouse over the combobox
@Override
public void mouseEntered(MouseEvent e)
{
- comboBox.setToolTipText(tips.get(comboBox.getSelectedIndex()));
+ scoreModelsCombo.setToolTipText(tips.get(scoreModelsCombo.getSelectedIndex()));
}
@Override
public void mouseExited(MouseEvent e)
{
- comboBox.setToolTipText(null);
+ scoreModelsCombo.setToolTipText(null);
}
};
- for (Component c : comboBox.getComponents())
+ for (Component c : scoreModelsCombo.getComponents())
{
c.addMouseListener(mouseListener);
}
- updateScoreModels(comboBox, tips);
+ updateScoreModels(scoreModelsCombo, tips);
/*
* set the list of tooltips on the combobox's renderer
*/
renderer.setTooltips(tips);
- return comboBox;
+ return scoreModelsCombo;
}
- private void updateScoreModels(JComboBox comboBox, List<String> tips)
+ private void updateScoreModels(JComboBox<String> comboBox,
+ List<String> toolTips)
{
Object curSel = comboBox.getSelectedItem();
- tips.clear();
- DefaultComboBoxModel model = new DefaultComboBoxModel();
+ toolTips.clear();
+ DefaultComboBoxModel<String> model = new DefaultComboBoxModel<String>();
/*
* now we can actually add entries to the combobox,
tooltip = MessageManager.getStringOrReturn("label.score_model_",
sm.getName());
}
- tips.add(tooltip);
+ toolTips.add(tooltip);
}
}
if (selectedIsPresent)
/**
* Open and calculate the selected tree or PCA on 'OK'
*/
- protected void ok_actionPerformed()
+ protected void calculate_actionPerformed()
{
boolean doPCA = pca.isSelected();
String modelName = modelNames.getSelectedItem().toString();
*/
protected void openTreePanel(String modelName, SimilarityParamsI params)
{
+ /*
+ * gui validation shouldn't allow insufficient sequences here, but leave
+ * this check in in case this method gets exposed programmatically in future
+ */
+ AlignViewport viewport = af.getViewport();
+ SequenceGroup sg = viewport.getSelectionGroup();
+ if (sg != null && sg.getSize() < MIN_TREE_SELECTION)
+ {
+ JvOptionPane
+ .showMessageDialog(
+ Desktop.desktop,
+ MessageManager
+ .formatMessage("label.you_need_at_least_n_sequences",
+ MIN_TREE_SELECTION),
+ MessageManager
+ .getString("label.not_enough_sequences"),
+ JvOptionPane.WARNING_MESSAGE);
+ return;
+ }
+
String treeType = neighbourJoining.isSelected() ? TreeBuilder.NEIGHBOUR_JOINING
: TreeBuilder.AVERAGE_DISTANCE;
af.newTreePanel(treeType, modelName, params);
protected void openPcaPanel(String modelName, SimilarityParamsI params)
{
AlignViewport viewport = af.getViewport();
+
+ /*
+ * gui validation shouldn't allow insufficient sequences here, but leave
+ * this check in in case this method gets exposed programmatically in future
+ */
if (((viewport.getSelectionGroup() != null)
- && (viewport.getSelectionGroup().getSize() < 4) && (viewport
+ && (viewport.getSelectionGroup().getSize() < MIN_PCA_SELECTION) && (viewport
.getSelectionGroup().getSize() > 0))
- || (viewport.getAlignment().getHeight() < 4))
+ || (viewport.getAlignment().getHeight() < MIN_PCA_SELECTION))
{
- JvOptionPane
- .showInternalMessageDialog(
- this,
- MessageManager
- .getString("label.principal_component_analysis_must_take_least_four_input_sequences"),
- MessageManager
- .getString("label.sequence_selection_insufficient"),
- JvOptionPane.WARNING_MESSAGE);
+ JvOptionPane.showInternalMessageDialog(this, MessageManager
+ .formatMessage("label.you_need_at_least_n_sequences",
+ MIN_PCA_SELECTION), MessageManager
+ .getString("label.sequence_selection_insufficient"),
+ JvOptionPane.WARNING_MESSAGE);
return;
}
new PCAPanel(af.alignPanel, modelName, params);
}
/**
- * Closes dialog on cancel
- *
- * @param e
+ * Closes dialog on Close button press
*/
- protected void cancel_actionPerformed(ActionEvent e)
+ protected void close_actionPerformed()
{
try
{
{
ap.scrollUp(true);
}
- while (seqCanvas.cursorY + 1 > av.getRanges().getEndSeq())
+ while (seqCanvas.cursorY > av.getRanges().getEndSeq())
{
ap.scrollUp(false);
}
*/
void getBoxColour(ResidueShaderI shader, SequenceI seq, int i)
{
- if (shader != null)
+ if (shader.getColourScheme() != null)
{
resBoxColour = shader.findColour(seq.getCharAt(i),
i, seq);
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.StringTokenizer;
import java.util.Vector;
import com.stevesoft.pat.Regex;
private static final Regex CLOSE_PAREN = new Regex("(>|\\])", ")");
- private static final Regex DETECT_BRACKETS = new Regex(
- "(<|>|\\[|\\]|\\(|\\))");
+ public static final Regex DETECT_BRACKETS = new Regex(
+ "(<|>|\\[|\\]|\\(|\\)|\\{|\\})");
StringBuffer out; // output buffer
// add alignment annotation for this feature
String key = type2id(type);
+
+ /*
+ * have we added annotation rows for this type ?
+ */
+ boolean annotsAdded = false;
if (key != null)
{
if (accAnnotations != null
Vector vv = (Vector) accAnnotations.get(key);
for (int ii = 0; ii < vv.size(); ii++)
{
+ annotsAdded = true;
AlignmentAnnotation an = (AlignmentAnnotation) vv
.elementAt(ii);
seqO.addAlignmentAnnotation(an);
while (j.hasMoreElements())
{
String desc = j.nextElement().toString();
+ if ("annotations".equals(desc) && annotsAdded)
+ {
+ // don't add features if we already added an annotation row
+ continue;
+ }
String ns = content.get(desc).toString();
char[] byChar = ns.toCharArray();
for (int k = 0; k < byChar.length; k++)
{
String acc = s.stringMatched(1);
String type = s.stringMatched(2);
- String seq = new String(s.stringMatched(3));
- String description = null;
- // Check for additional information about the current annotation
- // We use a simple string tokenizer here for speed
- StringTokenizer sep = new StringTokenizer(seq, " \t");
- description = sep.nextToken();
- if (sep.hasMoreTokens())
- {
- seq = sep.nextToken();
- }
- else
- {
- seq = description;
- description = new String();
- }
- // sequence id with from-to fields
+ String oseq = s.stringMatched(3);
+ /*
+ * copy of annotation field that may be processed into whitespace chunks
+ */
+ String seq = new String(oseq);
Hashtable ann;
// Get an object with all the annotations for this sequence
ann = new Hashtable();
seqAnn.put(acc, ann);
}
+
+ // // start of block for appending annotation lines for wrapped
+ // stokchholm file
// TODO test structure, call parseAnnotationRow with vector from
// hashtable for specific sequence
+
Hashtable features;
// Get an object with all the content for an annotation
if (ann.containsKey("features"))
content = new Hashtable();
features.put(this.id2type(type), content);
}
- String ns = (String) content.get(description);
+ String ns = (String) content.get("annotation");
+
if (ns == null)
{
ns = "";
}
+ // finally, append the annotation line
ns += seq;
- content.put(description, ns);
+ content.put("annotation", ns);
+ // // end of wrapped annotation block.
+ // // Now a new row is created with the current set of data
- // if(type.equals("SS")){
Hashtable strucAnn;
if (seqAnn.containsKey(acc))
{
{
alan.visible = false;
}
- // annotations.addAll(newStruc);
+ // new annotation overwrites any existing annotation...
+
strucAnn.put(type, newStruc);
seqAnn.put(acc, strucAnn);
}
if (DETECT_BRACKETS.search(pos))
{
ann.secondaryStructure = Rna.getRNASecStrucState(pos).charAt(0);
+ ann.displayCharacter = "" + pos.charAt(0);
}
else
{
ann.secondaryStructure = ResidueProperties.getDssp3state(pos)
.charAt(0);
- }
if (ann.secondaryStructure == pos.charAt(0))
{
{
ann.displayCharacter = " " + ann.displayCharacter;
}
+ }
}
}
// output annotations
while (i < s.length && s[i] != null)
{
- if (s[i].getDatasetSequence() != null)
+ AlignmentAnnotation[] alAnot = s[i].getAnnotation();
+ if (alAnot != null)
{
- SequenceI ds = s[i].getDatasetSequence();
- AlignmentAnnotation[] alAnot;
Annotation[] ann;
- Annotation annot;
- alAnot = s[i].getAnnotation();
- String feature = "";
- if (alAnot != null)
+ for (int j = 0; j < alAnot.length; j++)
{
- for (int j = 0; j < alAnot.length; j++)
- {
- String key = type2id(alAnot[j].label);
- boolean isrna = alAnot[j].isValidStruc();
+ String key = type2id(alAnot[j].label);
+ boolean isrna = alAnot[j].isValidStruc();
- if (isrna)
- {
- // hardwire to secondary structure if there is RNA secondary
- // structure on the annotation
- key = "SS";
- }
- if (key == null)
- {
+ if (isrna)
+ {
+ // hardwire to secondary structure if there is RNA secondary
+ // structure on the annotation
+ key = "SS";
+ }
+ if (key == null)
+ {
- continue;
- }
+ continue;
+ }
- // out.append("#=GR ");
- out.append(new Format("%-" + maxid + "s").form("#=GR "
- + printId(s[i], jvSuffix) + " " + key + " "));
- ann = alAnot[j].annotations;
- String seq = "";
- for (int k = 0; k < ann.length; k++)
- {
- seq += outputCharacter(key, k, isrna, ann, s[i]);
- }
- out.append(seq);
- out.append(newline);
+ // out.append("#=GR ");
+ out.append(new Format("%-" + maxid + "s").form("#=GR "
+ + printId(s[i], jvSuffix) + " " + key + " "));
+ ann = alAnot[j].annotations;
+ String seq = "";
+ for (int k = 0; k < ann.length; k++)
+ {
+ seq += outputCharacter(key, k, isrna, ann, s[i]);
}
+ out.append(seq);
+ out.append(newline);
}
}
{
if (annot == null)
{
- // sensible gap character if one is available or make one up
- return sequenceI == null ? '-' : sequenceI.getCharAt(k);
+ // sensible gap character
+ return ' ';
}
else
{
* @param counter
* provider of feature counts per alignment position
*/
- public static void newCalculator(FeatureCounterI counter)
+ public static void newCalculator(FeatureSetCounterI counter)
{
- // TODO need an interface for AlignFrame by which to access
- // its AlignViewportI and AlignmentViewPanel
AlignmentViewPanel currentAlignFrame = Jalview.getCurrentAlignFrame().alignPanel;
- if (currentAlignFrame != null)
- {
- newCalculator(currentAlignFrame.getAlignViewport(),
- currentAlignFrame, counter);
- }
- else
+ if (currentAlignFrame == null)
{
System.err
.println("Can't register calculator as no alignment window has focus");
+ return;
}
- }
-
- /**
- * Constructs and registers a new alignment annotation worker
- *
- * @param viewport
- * @param panel
- * @param counter
- * provider of feature counts per alignment position
- */
- public static void newCalculator(AlignViewportI viewport,
- AlignmentViewPanel panel, FeatureCounterI counter)
- {
- new ColumnCounterWorker(viewport, panel, counter);
+ new ColumnCounterSetWorker(currentAlignFrame.getAlignViewport(),
+ currentAlignFrame, counter);
}
/**
AlignFrame currentAlignFrame = Jalview.getCurrentAlignFrame();
if (currentAlignFrame != null)
{
- newCalculator(currentAlignFrame.getViewport(), currentAlignFrame
- .getAlignPanels().get(0), calculator);
+ new AnnotationWorker(currentAlignFrame.getViewport(),
+ currentAlignFrame.getAlignPanels().get(0), calculator);
}
else
{
import java.util.List;
/**
- * A class to compute an alignment annotation with column counts of any
- * properties of interest of positions in an alignment. <br>
+ * A class to compute alignment annotations with column counts for a set of
+ * properties of interest on positions in an alignment. <br>
* This is designed to be extensible, by supplying to the constructor an object
- * that computes a count for each residue position, based on the residue value
- * and any sequence features at that position.
+ * that computes a vector of counts for each residue position, based on the
+ * residue and and sequence features at that position.
*
*/
-class ColumnCounterWorker extends AlignCalcWorker
+class ColumnCounterSetWorker extends AlignCalcWorker
{
- FeatureCounterI counter;
+ FeatureSetCounterI counter;
/**
* Constructor registers the annotation for the given alignment frame
* @param af
* @param counter
*/
- public ColumnCounterWorker(AlignViewportI viewport,
- AlignmentViewPanel panel, FeatureCounterI counter)
+ public ColumnCounterSetWorker(AlignViewportI viewport,
+ AlignmentViewPanel panel, FeatureSetCounterI counter)
{
super(viewport, panel);
ourAnnots = new ArrayList<AlignmentAnnotation>();
@Override
public void run()
{
+ boolean annotationAdded = false;
try
{
calcMan.notifyStart(this);
{
try
{
- computeAnnotations();
+ annotationAdded = computeAnnotations();
} catch (IndexOutOfBoundsException x)
{
// probable race condition. just finish and return without any fuss.
if (ap != null)
{
- ap.adjustAnnotationHeight();
+ if (annotationAdded)
+ {
+ ap.adjustAnnotationHeight();
+ }
ap.paintAlignment(true);
}
/**
* Scan each column of the alignment to calculate a count by feature type. Set
* the count as the value of the alignment annotation for that feature type.
+ *
+ * @return
*/
- void computeAnnotations()
+ boolean computeAnnotations()
{
FeatureRenderer fr = new FeatureRenderer(alignViewport);
// TODO use the commented out code once JAL-2075 is fixed
// AlignmentView alignmentView = alignViewport.getAlignmentView(false);
// AlignmentI alignment = alignmentView.getVisibleAlignment(' ');
- // int width = alignmentView.getWidth();
+ int rows = counter.getNames().length;
+
int width = alignment.getWidth();
int height = alignment.getHeight();
- int[] counts = new int[width];
- int max = 0;
+ int[][] counts = new int[width][rows];
+ int max[] = new int[rows];
+ for (int crow = 0; crow < rows; crow++)
+ {
+ max[crow] = 0;
+ }
+
+ int[] minC = counter.getMinColour();
+ int[] maxC = counter.getMaxColour();
+ Color minColour = new Color(minC[0], minC[1], minC[2]);
+ Color maxColour = new Color(maxC[0], maxC[1], maxC[2]);
for (int col = 0; col < width; col++)
{
- int count = 0;
+ int[] count = counts[col];
+ for (int crow = 0; crow < rows; crow++)
+ {
+ count[crow] = 0;
+ }
for (int row = 0; row < height; row++)
{
- count += countFeaturesAt(alignment, col, row, fr);
+ int[] colcount = countFeaturesAt(alignment, col, row, fr);
+ if (colcount != null)
+ {
+ for (int crow = 0; crow < rows; crow++)
+ {
+ count[crow] += colcount[crow];
+ }
+ }
}
counts[col] = count;
- max = Math.max(count, max);
+ for (int crow = 0; crow < rows; crow++)
+ {
+ max[crow] = Math.max(count[crow], max[crow]);
+ }
}
- Annotation[] anns = new Annotation[width];
- /*
- * add non-zero counts as annotations
- */
- for (int i = 0; i < counts.length; i++)
+ boolean annotationAdded = false;
+
+ for (int anrow = 0; anrow < rows; anrow++)
{
- int count = counts[i];
- if (count > 0)
+ Annotation[] anns = new Annotation[width];
+ /*
+ * add non-zero counts as annotations
+ */
+ for (int i = 0; i < counts.length; i++)
{
- Color color = ColorUtils.getGraduatedColour(count, 0, Color.cyan,
- max, Color.blue);
- String str = String.valueOf(count);
- anns[i] = new Annotation(str, str, '0', count, color);
+ int count = counts[i][anrow];
+ if (count > 0)
+ {
+ Color color = ColorUtils.getGraduatedColour(count, 0, minColour,
+ max[anrow], maxColour);
+ String str = String.valueOf(count);
+ anns[i] = new Annotation(str, str, '0', count, color);
+ }
}
- }
- /*
- * construct or update the annotation
- */
- AlignmentAnnotation ann = alignViewport.getAlignment()
- .findOrCreateAnnotation(counter.getName(),
- counter.getDescription(), false, null, null);
- ann.description = counter.getDescription();
- ann.showAllColLabels = true;
- ann.scaleColLabel = true;
- ann.graph = AlignmentAnnotation.BAR_GRAPH;
- ann.annotations = anns;
- setGraphMinMax(ann, anns);
- ann.validateRangeAndDisplay();
- if (!ourAnnots.contains(ann))
- {
- ourAnnots.add(ann);
+ /*
+ * construct or update the annotation
+ */
+ String description = counter.getDescriptions()[anrow];
+ if (!alignment.findAnnotation(description).iterator().hasNext())
+ {
+ annotationAdded = true;
+ }
+ AlignmentAnnotation ann = alignment.findOrCreateAnnotation(
+ counter.getNames()[anrow], description, false, null, null);
+ ann.description = description;
+ ann.showAllColLabels = true;
+ ann.scaleColLabel = true;
+ ann.graph = AlignmentAnnotation.BAR_GRAPH;
+ ann.annotations = anns;
+ setGraphMinMax(ann, anns);
+ ann.validateRangeAndDisplay();
+ if (!ourAnnots.contains(ann))
+ {
+ ourAnnots.add(ann);
+ }
}
+ return annotationAdded;
}
/**
* @param row
* @param fr
*/
- int countFeaturesAt(AlignmentI alignment, int col, int row,
+ int[] countFeaturesAt(AlignmentI alignment, int col, int row,
FeatureRenderer fr)
{
SequenceI seq = alignment.getSequenceAt(row);
if (seq == null)
{
- return 0;
+ return null;
}
if (col >= seq.getLength())
{
- return 0;// sequence doesn't extend this far
+ return null;// sequence doesn't extend this far
}
char res = seq.getCharAt(col);
if (Comparison.isGap(res))
{
- return 0;
+ return null;
}
int pos = seq.findPosition(col);
// NB have to adjust pos if using AlignmentView.getVisibleAlignment
// see JAL-2075
List<SequenceFeature> features = fr.findFeaturesAtRes(seq, pos);
- int count = this.counter.count(String.valueOf(res), features);
+ int[] count = this.counter.count(String.valueOf(res), features);
return count;
}
* along with Jalview. If not, see <http://www.gnu.org/licenses/>.
* The Jalview Authors are detailed in the 'AUTHORS' file.
*/
+
package jalview.workers;
import jalview.datamodel.SequenceFeature;
import java.util.List;
/**
- * An interface for a type that returns counts of any value of interest at a
- * sequence position that can be determined from the sequence character and any
- * features present at that position
+ * An interface for a type that returns counts (per computed annotation type) of
+ * any value of interest at a sequence position that can be determined from the
+ * sequence character and any features present at that position
*
*/
-public interface FeatureCounterI
+public interface FeatureSetCounterI
{
/**
- * Returns a count of some property of interest, for example
+ * Returns counts (per annotation type) of some properties of interest, for
+ * example
* <ul>
* <li>the number of variant features at the position</li>
* <li>the number of Cath features of status 'True Positive'</li>
* @param a
* list of any sequence features which include the position
*/
- int count(String residue, List<SequenceFeature> features);
+ int[] count(String residue, List<SequenceFeature> features);
/**
- * Returns a name for the annotation that this is counting, for use as the
- * displayed label
+ * Returns names for the annotations that this is counting, for use as the
+ * displayed labels
*
* @return
*/
- String getName();
+ String[] getNames();
/**
- * Returns a description for the annotation, for display as a tooltip
+ * Returns descriptions for the annotations, for display as tooltips
*
* @return
*/
- String getDescription();
+ String[] getDescriptions();
/**
* Returns the colour (as [red, green, blue] values in the range 0-255) to use
assertEquals(Color.magenta, sr.getResidueBoxColour(seq, 5)); // G
assertEquals(Color.orange, sr.getResidueBoxColour(seq, 12)); // F
}
+
+ @Test(groups = { "Functional" })
+ public void testGetResidueBoxColour_none()
+ {
+ SequenceI seq = new Sequence("name", "MA--TVLGSPRAPAFF");
+ AlignmentI al = new Alignment(new SequenceI[] { seq });
+ final AlignViewport av = new AlignViewport(al);
+ SequenceRenderer sr = new SequenceRenderer(av);
+
+ assertEquals(Color.white, sr.getResidueBoxColour(seq, 0));
+ assertEquals(Color.white, sr.getResidueBoxColour(seq, 2));
+
+ // set for overview
+ sr.forOverview = true;
+ assertEquals(Color.lightGray, sr.getResidueBoxColour(seq, 0));
+ assertEquals(Color.white, sr.getResidueBoxColour(seq, 2));
+ }
+
// TODO more tests for getResidueBoxColour covering groups, feature rendering,
// gaps, overview...
import jalview.gui.JvOptionPane;
import java.io.File;
+import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public static void testAlignmentEquivalence(AlignmentI al,
AlignmentI al_input, boolean ignoreFeatures)
{
+ testAlignmentEquivalence(al, al_input, ignoreFeatures, false, false);
}
/**
- * assert alignment equivalence
+ * assert alignment equivalence - uses special comparators for RNA structure
+ * annotation rows.
*
* @param al
* 'original'
* @param ignoreRowVisibility
* when true, do not fail if there are differences in the visibility
* of annotation rows
+ * @param allowNullAnnotation
+ * when true, positions in alignment annotation that are null will be
+ * considered equal to positions containing annotation where
+ * Annotation.isWhitespace() returns true.
+ *
*/
public static void testAlignmentEquivalence(AlignmentI al,
AlignmentI al_input, boolean ignoreFeatures,
- boolean ignoreRowVisibility)
+ boolean ignoreRowVisibility, boolean allowNullAnnotation)
{
assertNotNull("Original alignment was null", al);
assertNotNull("Generated alignment was null", al_input);
{
assertEqualSecondaryStructure(
"Different alignment annotation at position " + i,
- aa_original[i], aa_new[i]);
+ aa_original[i], aa_new[i], allowNullAnnotation);
// compare graphGroup or graph properties - needed to verify JAL-1299
assertEquals("Graph type not identical.", aa_original[i].graph,
aa_new[i].graph);
annot_new = al_input.getSequenceAt(in).getAnnotation()[j];
assertEqualSecondaryStructure(
"Different annotation elements", annot_original,
- annot_new);
+ annot_new, allowNullAnnotation);
}
}
}
}
}
+ /**
+ * compare two annotation rows, with special support for secondary structure
+ * comparison. With RNA, only the value and the secondaryStructure symbols are
+ * compared, displayCharacter and description are ignored. Annotations where
+ * Annotation.isWhitespace() is true are always considered equal.
+ *
+ * @param message
+ * - not actually used yet..
+ * @param annot_or
+ * - the original annotation
+ * @param annot_new
+ * - the one compared to the original annotation
+ * @param allowNullEquivalence
+ * when true, positions in alignment annotation that are null will be
+ * considered equal to non-null positions for which
+ * Annotation.isWhitespace() is true.
+ */
private static void assertEqualSecondaryStructure(String message,
- AlignmentAnnotation annot_or,
- AlignmentAnnotation annot_new)
+ AlignmentAnnotation annot_or, AlignmentAnnotation annot_new,
+ boolean allowNullEqivalence)
{
// TODO: test to cover this assert behaves correctly for all allowed
// variations of secondary structure annotation row equivalence
if (isRna)
{
if (an_or.secondaryStructure != an_new.secondaryStructure
- || an_or.value != an_new.value)
+ || ((Float.isNaN(an_or.value) != Float
+ .isNaN(an_new.value)) || an_or.value != an_new.value))
{
fail("Different RNA secondary structure at column " + i
+ " expected: [" + annot_or.annotations[i].toString()
else
{
// not RNA secondary structure, so expect all elements to match...
- if (!an_or.displayCharacter.trim().equals(
+ if ((an_or.isWhitespace() != an_new.isWhitespace())
+ || !an_or.displayCharacter.trim().equals(
an_new.displayCharacter.trim())
|| !("" + an_or.secondaryStructure).trim().equals(
("" + an_new.secondaryStructure).trim())
.trim().length() == 0)
|| (an_new.description == null && an_or.description
.trim().length() == 0) || an_or.description
- .trim().equals(an_new.description.trim()))))
+ .trim().equals(an_new.description.trim())))
+ || !((Float.isNaN(an_or.value) && Float
+ .isNaN(an_new.value)) || an_or.value == an_new.value))
{
fail("Annotation Element Mismatch\nElement " + i
+ " in original: " + annot_or.annotations[i].toString()
}
else
{
- fail("Annotation Element Mismatch\nElement "
- + i
- + " in original: "
- + (annot_or.annotations[i] == null ? "is null"
- : annot_or.annotations[i].toString())
- + "\nElement "
- + i
- + " in new: "
- + (annot_new.annotations[i] == null ? "is null"
- : annot_new.annotations[i].toString()));
+ if (allowNullEqivalence)
+ {
+ if (an_or != null && an_or.isWhitespace())
+
+ {
+ continue;
+ }
+ if (an_new != null && an_new.isWhitespace())
+ {
+ continue;
+ }
+ }
+ // need also to test for null in one, non-SS annotation in other...
+ fail("Annotation Element Mismatch\nElement " + i + " in original: "
+ + (an_or == null ? "is null" : an_or.toString())
+ + "\nElement " + i + " in new: "
+ + (an_new == null ? "is null" : an_new.toString()));
+ }
+ }
+ }
+
+ /**
+ * @see assertEqualSecondaryStructure - test if two secondary structure
+ * annotations are not equal
+ * @param message
+ * @param an_orig
+ * @param an_new
+ * @param allowNullEquivalence
+ */
+ public static void assertNotEqualSecondaryStructure(String message,
+ AlignmentAnnotation an_orig, AlignmentAnnotation an_new,
+ boolean allowNullEquivalence)
+ {
+ boolean thrown = false;
+ try
+ {
+ assertEqualSecondaryStructure("", an_orig, an_new,
+ allowNullEquivalence);
+ } catch (AssertionError af)
+ {
+ thrown = true;
+ }
+ if (!thrown)
+ {
+ fail("Expected difference for [" + an_orig + "] and [" + an_new + "]");
+ }
+ }
+ private AlignmentAnnotation makeAnnot(Annotation ae)
+ {
+ return new AlignmentAnnotation("label", "description", new Annotation[]
+ { ae });
+ }
+
+ @Test(groups={"Functional"})
+ public void testAnnotationEquivalence()
+ {
+ AlignmentAnnotation one = makeAnnot(new Annotation("", "", ' ', 1));
+ AlignmentAnnotation anotherOne = makeAnnot(new Annotation("", "", ' ',
+ 1));
+ AlignmentAnnotation sheet = makeAnnot(new Annotation("","",'E',0f));
+ AlignmentAnnotation anotherSheet = makeAnnot(new Annotation("","",'E',0f));
+ AlignmentAnnotation sheetWithLabel = makeAnnot(new Annotation("1", "",
+ 'E', 0f));
+ AlignmentAnnotation anotherSheetWithLabel = makeAnnot(new Annotation(
+ "1", "", 'E', 0f));
+ AlignmentAnnotation rnaNoDC = makeAnnot(new Annotation("","",'<',0f));
+ AlignmentAnnotation anotherRnaNoDC = makeAnnot(new Annotation("","",'<',0f));
+ AlignmentAnnotation rnaWithDC = makeAnnot(new Annotation("B", "", '<',
+ 0f));
+ AlignmentAnnotation anotherRnaWithDC = makeAnnot(new Annotation("B",
+ "", '<', 0f));
+
+ // check self equivalence
+ for (boolean allowNull : new boolean[] { true, false })
+ {
+ assertEqualSecondaryStructure("Should be equal", one, anotherOne,
+ allowNull);
+ assertEqualSecondaryStructure("Should be equal", sheet, anotherSheet,
+ allowNull);
+ assertEqualSecondaryStructure("Should be equal", sheetWithLabel,
+ anotherSheetWithLabel, allowNull);
+ assertEqualSecondaryStructure("Should be equal", rnaNoDC,
+ anotherRnaNoDC, allowNull);
+ assertEqualSecondaryStructure("Should be equal", rnaWithDC,
+ anotherRnaWithDC, allowNull);
+ // display character doesn't matter for RNA structure (for 2.10.2)
+ assertEqualSecondaryStructure("Should be equal", rnaWithDC, rnaNoDC,
+ allowNull);
+ assertEqualSecondaryStructure("Should be equal", rnaNoDC, rnaWithDC,
+ allowNull);
+ }
+
+ // verify others are different
+ List<AlignmentAnnotation> aaSet = Arrays.asList(one, sheet,
+ sheetWithLabel, rnaWithDC);
+ for (int p = 0; p < aaSet.size(); p++)
+ {
+ for (int q = 0; q < aaSet.size(); q++)
+ {
+ if (p != q)
+ {
+ assertNotEqualSecondaryStructure("Should be different",
+ aaSet.get(p), aaSet.get(q), false);
+ }
+ else
+ {
+ assertEqualSecondaryStructure("Should be same", aaSet.get(p),
+ aaSet.get(q), false);
+ assertEqualSecondaryStructure("Should be same", aaSet.get(p),
+ aaSet.get(q), true);
+ assertNotEqualSecondaryStructure(
+ "Should be different to empty anot", aaSet.get(p),
+ makeAnnot(Annotation.EMPTY_ANNOTATION), false);
+ assertNotEqualSecondaryStructure(
+ "Should be different to empty annot",
+ makeAnnot(Annotation.EMPTY_ANNOTATION), aaSet.get(q),
+ true);
+ assertNotEqualSecondaryStructure("Should be different to null",
+ aaSet.get(p), makeAnnot(null), false);
+ assertNotEqualSecondaryStructure("Should be different to null",
+ makeAnnot(null), aaSet.get(q), true);
+ }
}
}
+
+ // test null
+
+ }
+
+ String aliFile = ">Dm\nAAACCCUUUUACACACGGGAAAGGG";
+ String annFile = "JALVIEW_ANNOTATION\n# Created: Thu May 04 11:16:52 BST 2017\n\n"
+ + "SEQUENCE_REF\tDm\nNO_GRAPH\tsecondary structure\tsecondary structure\t"
+ + "(|(|(|(|, .|, .|, .|, .|)|)|)|)|\t0.0\nROWPROPERTIES\t"
+ + "secondary structure\tscaletofit=true\tshowalllabs=true\tcentrelabs=false";
+
+ String annFileCurlyWuss = "JALVIEW_ANNOTATION\n# Created: Thu May 04 11:16:52 BST 2017\n\n"
+ + "SEQUENCE_REF\tDm\nNO_GRAPH\tsecondary structure\tsecondary structure\t"
+ + "(|(|(|(||{|{||{|{||)|)|)|)||}|}|}|}|\t0.0\nROWPROPERTIES\t"
+ + "secondary structure\tscaletofit=true\tshowalllabs=true\tcentrelabs=false";
+ String annFileFullWuss = "JALVIEW_ANNOTATION\n# Created: Thu May 04 11:16:52 BST 2017\n\n"
+ + "SEQUENCE_REF\tDm\nNO_GRAPH\tsecondary structure\tsecondary structure\t"
+ + "(|(|(|(||{|{||[|[||)|)|)|)||}|}|]|]|\t0.0\nROWPROPERTIES\t"
+ + "secondary structure\tscaletofit=true\tshowalllabs=true\tcentrelabs=false";
+
+ @Test(groups = { "Functional" })
+ public void secondaryStructureForRNASequence() throws Exception
+ {
+ roundTripSSForRNA(aliFile, annFile);
+ }
+
+ @Test(groups = { "Functional" })
+ public void curlyWUSSsecondaryStructureForRNASequence() throws Exception
+ {
+ roundTripSSForRNA(aliFile, annFileCurlyWuss);
+ }
+
+ @Test(groups = { "Functional" })
+ public void fullWUSSsecondaryStructureForRNASequence() throws Exception
+ {
+ roundTripSSForRNA(aliFile, annFileFullWuss);
+ }
+
+ @Test(groups = { "Functional" })
+ public void detectWussBrackets()
+ {
+ for (char ch : new char[] { '{', '}', '[', ']', '(', ')', '<', '>' })
+ {
+ Assert.assertTrue(StockholmFile.DETECT_BRACKETS.matchAt("" + ch, 0),
+ "Didn't recognise " + ch + " as a WUSS bracket");
+ }
+ for (char ch : new char[] { '@', '!', 'V', 'Q', '*', ' ', '-', '.' })
+ {
+ Assert.assertFalse(StockholmFile.DETECT_BRACKETS.matchAt("" + ch, 0),
+ "Shouldn't recognise " + ch + " as a WUSS bracket");
+ }
+ }
+ private static void roundTripSSForRNA(String aliFile, String annFile)
+ throws Exception
+ {
+ AlignmentI al = new AppletFormatAdapter().readFile(aliFile,
+ DataSourceType.PASTE, jalview.io.FileFormat.Fasta);
+ AnnotationFile aaf = new AnnotationFile();
+ aaf.readAnnotationFile(al, annFile, DataSourceType.PASTE);
+ al.getAlignmentAnnotation()[0].visible = true;
+
+ // TODO: create a better 'save as <format>' pattern
+ StockholmFile sf = new StockholmFile(al);
+
+ String stockholmFile = sf.print(al.getSequencesArray(), true);
+
+ AlignmentI newAl = new AppletFormatAdapter().readFile(stockholmFile,
+ DataSourceType.PASTE, jalview.io.FileFormat.Stockholm);
+ // AlignmentUtils.showOrHideSequenceAnnotations(newAl.getViewport()
+ // .getAlignment(), Arrays.asList("Secondary Structure"), newAl
+ // .getViewport().getAlignment().getSequences(), true, true);
+ testAlignmentEquivalence(al, newAl, true, true, true);
+
}
}