<classpathentry kind="lib" path="lib/jdas-1.0.4.jar"/>
<classpathentry kind="lib" path="lib/spring-core-3.0.5.RELEASE.jar"/>
<classpathentry kind="lib" path="lib/spring-web-3.0.5.RELEASE.jar"/>
- <classpathentry kind="lib" path="lib/min-jabaws-client-2.1.0.jar" sourcepath="/clustengine"/>
+ <classpathentry kind="lib" path="lib/jabaws-min-client-2.2.0.jar" sourcepath="/clustengine"/>
<classpathentry kind="lib" path="lib/json_simple-1.1.jar" sourcepath="/Users/jimp/Downloads/json_simple-1.1-all.zip"/>
<classpathentry kind="lib" path="lib/slf4j-api-1.7.7.jar"/>
<classpathentry kind="lib" path="lib/jsoup-1.8.1.jar"/>
<td>Default is true.</td>
</tr>
<tr>
+ <td>showOccupancy</td>
+ <td>true <em>or</em> false</td>
+ <td>Default is true.</td>
+ </tr>
+ <tr>
<td>sortBy</td>
<td> Id <em>, </em> Pairwise Identity<em>, or</em> Length</td>
<td> Sorts the alignment on startup</td>
--- /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 java.awt.Color
+import jalview.schemes.ColourSchemeI
+import jalview.schemes.ColourSchemes
+import jalview.datamodel.AnnotatedCollectionI
+import jalview.datamodel.SequenceI
+import jalview.datamodel.SequenceCollectionI
+import jalview.util.Comparison
+
+/*
+ * Closure that defines a colour scheme where fully conserved residues are red,
+ * partly conserved (match consensus but < 100% consensus) are yellow,
+ * unconserved and gaps are white
+ */
+def conserved
+conserved = { ->
+ [
+ /*
+ * name shown in the colour menu
+ */
+ getSchemeName: { -> 'Conserved' },
+
+ /*
+ * to make a new instance for each alignment view
+ */
+ getInstance: { AnnotatedCollectionI coll, Map<SequenceI, SequenceCollectionI> map -> conserved() },
+
+ /*
+ * method only needed if colour scheme has to recalculate
+ * values when an alignment is modified
+ */
+ alignmentChanged: { AnnotatedCollectionI coll, Map<SequenceI, SequenceCollectionI> map -> },
+
+ /*
+ * determine colour for a residue at an aligned position of a
+ * sequence, given consensus residue(s) for the column and the
+ * consensus percentage identity score for the column
+ */
+ findColour: { char res, int col, SequenceI seq, String consensus, float pid ->
+ if ('a' <= res && res <= 'z')
+ {
+ res -= ('a' - 'A');
+ }
+ if (Comparison.isGap(res) || !consensus.contains(String.valueOf(res)))
+ {
+ Color.white
+ } else if (pid < 100)
+ {
+ Color.yellow
+ } else
+ {
+ Color.red
+ }
+ },
+
+ /*
+ * true means applicable to nucleotide or peptide data
+ */
+ isApplicableTo: {AnnotatedCollectionI coll -> true},
+
+ /*
+ * simple colour schemes are those that depend on the residue
+ * only (these are also available to colour structure viewers)
+ */
+ isSimple: { false }
+ ] as ColourSchemeI
+}
+
+ColourSchemes.instance.registerColourScheme(conserved())
--- /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 java.awt.Color
+import jalview.schemes.ColourSchemeI
+import jalview.schemes.ColourSchemes
+import jalview.datamodel.AnnotatedCollectionI
+import jalview.datamodel.SequenceI
+import jalview.datamodel.SequenceCollectionI
+import jalview.util.Comparison
+
+/*
+ * Closure that defines a colour scheme where non-consensus residues are pink,
+ * other residues (and gaps) are white
+ */
+def unconserved
+unconserved = { ->
+ [
+ /*
+ * name shown in the colour menu
+ */
+ getSchemeName: { -> 'Unconserved' },
+
+ /*
+ * to make a new instance for each alignment view
+ */
+ getInstance: { AnnotatedCollectionI coll, Map<SequenceI, SequenceCollectionI> map -> unconserved() },
+
+ /*
+ * method only needed if colour scheme has to recalculate
+ * values when an alignment is modified
+ */
+ alignmentChanged: { AnnotatedCollectionI coll, Map<SequenceI, SequenceCollectionI> map -> },
+
+ /*
+ * determine colour for a residue at an aligned position of a
+ * sequence, given consensus residue(s) for the column and the
+ * consensus percentage identity score for the column
+ */
+ findColour: { char res, int col, SequenceI seq, String consensus, float pid ->
+ if ('a' <= res && res <= 'z')
+ {
+ res -= ('a' - 'A');
+ }
+ if (Comparison.isGap(res) || consensus.contains(String.valueOf(res)))
+ {
+ Color.white
+ } else
+ {
+ Color.pink
+ }
+ },
+
+ /*
+ * true means applicable to nucleotide or peptide data
+ */
+ isApplicableTo: {AnnotatedCollectionI coll -> true},
+
+ /*
+ * simple colour schemes are those that depend on the residue
+ * only (these are also available to colour structure viewers)
+ */
+ isSimple: { false }
+ ] as ColourSchemeI
+}
+
+ColourSchemes.instance.registerColourScheme(unconserved())
+++ /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)
SEQUENCE_GROUP Group_B 1 351 2-5
SEQUENCE_GROUP Group_C 12 14 -1 seq1 seq2 seq3
PROPERTIES Group_A description=This is the description colour=Helix Propensity pidThreshold=0 outlineColour=red displayBoxes=true displayText=false colourText=false textCol1=black textCol2=black textColThreshold=0
-PROPERTIES Group_B outlineColour=red
+PROPERTIES Group_B outlineColour=red colour=None
PROPERTIES Group_C colour=Clustal
<mapID target="home" url="html/index.html" />
<mapID target="new" url="html/whatsNew.html"/>
- <mapID target="release" url="html/releases.html#Jalview.2.10.1"/>
+ <mapID target="release" url="html/releases.html#Jalview.2.10.2"/>
<mapID target="alannotation" url="html/features/annotation.html"/>
<mapID target="keys" url="html/keys.html"/>
<mapID target="newkeys" url="html/features/newkeystrokes.html"/>
<mapID target="jalarchive" url="html/features/jalarchive.html"/>
<mapID target="multipleviews" url="html/features/multipleViews.html"/>
<mapID target="splitframe" url="html/features/splitView.html"/>
+ <mapID target="splitframe.mirrorfonts" url="html/features/splitView.html#mirror"/>
<mapID target="trees" url="html/calculations/tree.html"/>
<mapID target="treeviewer" url="html/calculations/treeviewer.html"/>
<mapID target="sorting" url="html/calculations/sorting.html"/>
<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.colours" url="html/features/groovy.html#groovyColours" />
+ <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" />
<mapID target="homeIcon" url="icons/Home.png" />
<mapID target="printIcon" url="icons/print.png" />
<mapID target="printSetupIcon" url="icons/setup.png" />
+
+ <mapID target="overview" url="features/overview.html" />
</map>
<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="Custom Colourschemes in Groovy" target="groovy.colours"/>
+ <tocitem text="Omit hidden regions in Overview" target="overview"/>
+ <tocitem text="identifers.org for URL Links" target="linksprefs" />
+ <tocitem text="New features in Split Frame View" target="splitframe.mirrorfonts" />
</tocitem>
<tocitem text="Editing Alignments" target="edit" />
</tocitem>
<tocitem text="Viewing RNA structures" target="varna" expand="false"/>
<tocitem text="Opening URLs from Jalview" target="urllinks" expand="true">
- <tocitem text="Configuring URL Links" target="urllinkspref" />
+ <tocitem text="Configuring URL Links" target="linksprefs" />
</tocitem>
<tocitem text="VAMSAS Data Exchange" target="vamsas">
<!-- what can Jalview share with other apps -->
<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" />
<strong>User Defined Colours</strong>
</p>
<p>
- <img src="userDefined_java6.gif" width="815" height="402">
+ <img src="userDefined_java7.gif" width="815" height="402">
</p>
<p>
You may define any number of new colour schemes, each with a unique
The <strong>Case Sensitive</strong> option allows you to choose
distinct colours for upper and lower case residue codes.
<p>
- The <strong>Lower Case Colour</strong> option allows you to apply a selected colour
+ The <strong>Colour All Lower Case </strong> option allows you to apply a selected colour
to all lower case residues.
<p>
Click <strong>Apply</strong> or <strong>OK</strong> to set your new
<br> Any saved colour schemes will be automatically loaded the
next time you use Jalview.
<br>
- <br>
- <em>Note: the screenshot shows the appearance when running Java
- version 6. For Java 7 (from Jalview 2.8.2) only the Swatches colour
- chooser is currently supported (for reasons of available screen
- space).</em>
- <p />
</body>
</html>
structure in the alignment. The regions used to calculate
the superposition will be highlighted using the 'Cartoon'
rendering style, and the remaining data shown as a chain
- trace.<br>
+ trace.<br/><br/>
</em></li>
- </ul></li>
- <li><strong>Help<br>
+ <li><strong><a name="experimental">EXPERIMENTAL FEATURES</a></strong><br/>
+ <em>
+ These are only available if the <strong>Tools→Enable
+ Experimental Features</strong> option is enabled. (Since Jalview 2.10.2)</em>
+ <ul>
+ <li><strong>Write Jalview features</strong><br /> <em>Selecting
+ this option will create new residue attributes for any
+ features currently visible in the associated alignment
+ views, allowing those positions to be selected and
+ analysed with via Chimera's 'Render by Attribute' tool
+ (found in the Tools submenu called Structure Analysis).<br />
+ <br />If you use this option, please remember to select
+ the <em>Refresh Menus</em> option in Chimera's Render by
+ Attribute dialog box in order to see the attributes
+ derived from Jalview sequence features.
+ </em><br />
+ <a href="https://issues.jalview.org/browse/JAL-2295">View
+ this function's issue in Jalview's bug tracker</a></li>
+ <li><strong>Fetch Chimera Attributes</strong><br /> <em>This
+ submenu lists available Chimera residue attributes that
+ can be imported as Jalview features on associated
+ sequences.<br />This is particularly useful for
+ transferring quantitative positional annotation. For
+ example, structure similarity for an alignment can be
+ visualised by transferring the local RMSD attributes
+ generated by Chimera's Match->Align tool onto aligned
+ sequences and displayed with a <a
+ href="featureschemes.html">Graduated feature colour
+ scheme</a>.
+ </em><a href="https://issues.jalview.org/browse/JAL-2296">View
+ this function's issue in Jalview's bug tracker</a></li>
+ </ul></li>
+ <li><strong>Help<br>
</strong>
<ul>
<li><strong>Chimera Help<br>
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>
+ <p><a name="groovyColours"/>
+ <em>Creating custom colourschemes</em><br/>
+ You can create your own alignment colourschemes with a groovy script. We've provided two examples:<br/>
+ <ul>
+ <li><a href="http://www.jalview.org/examples/groovy/colourConserved.groovy">colourConserved.groovy</a> creates an 'Conserved' colourscheme - similar to the classic <a href="http://www.nrbsc.org/old/gfx/genedoc/">GeneDOC</a> shading model.</li>
+ <li><a href="http://www.jalview.org/examples/groovy/colourUnconserved.groovy">colourUnconserved.groovy</a> creates an 'Unconserved' colourscheme, where any unconserved residues are coloured pink.</li>
+
+ </ul>
+ </p>
</body>
</html>
<p>The red box indicates the currently viewed region of the
alignment, this may be moved by clicking and dragging with the
mouse.</p>
+ <p><strong>Right-click</strong> (or CMD-Click) to open the
+ overview's popup menu. This provides an option to include hidden
+ regions in the overview (shown as dark-grey rows and columns). <br/><br/>
+ <em>The option to include/exclude hidden regions in the
+ overview was introduced in Jalview 2.10.2</em>.
<p>
<img src="overview.gif" width="407" height="137">
</p>
<p>
<em>Show Annotations</em> - If this is selected the new window will
display an annotation panel below the sequences. This annotation
- panel may have several rows describing the whole alignment. The 3
- standard annotations <em>Conservation</em>, <em>Quality</em> and <em>Consensus</em>
- for the alignment may be shown or hidden by default using the
- checkboxes below.
+ panel may have several rows describing the whole alignment. The 4
+ standard annotations <em>Conservation</em>, <em>Quality</em>,
+ <em>Occupancy</em> and <em>Consensus</em> for the alignment may
+ be shown or hidden by default using the checkboxes adjacent and
+ below.
</p>
<p>
<em>Show group: Conservation and Consensus</em> controls the display
The <em>Custom only</em> button limits the entries in the table to
just those you have configured yourself <em>via</em> the <em>Edit
Links</em> buttons. Press <em>Show all</em> to clear any filters.
- <p>
+ </p>
+ <p>The links table is prepoulated with persistent URLs for many common
+ bioinformatics databases (since 2.10.2). These links are downloaded by Jalview from
+ the <em>identifiers.org</em> website, and the names and URLs are not
+ user editable.
<a href="../webServices/urllinks.html#urllinks">Read more about configuring
URL links.</a>
</p>
alignments, the <strong><a href="../menus/alwformat.html">"Format→Font"</a></strong>
menu option has an option 'Scale protein residues to codons'. This
option will make each protein residue the same width as a DNA
- codon (so the alignments 'line up' vertically)
+ codon (so the alignments 'line up' vertically).<br/><br/>
+ <a name="mirror"/>The 'Use same
+ font for cDNA and peptide' checkbox, when enabled, ensures that font or
+ font-size changes in either the cDNA or Protein alignment will also
+ be mirrored. (<em>Added in 2.10.2</em>)
</li>
<li><strong>"View→Protein"</strong> (in the cDNA panel)
or <strong>"View→Nucleotide"</strong> (in the protein panel)
+++ /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>
the <a href="../features/groovy.html">Groovy Console</a> for
interactive scripting.
</em><strong><br></strong></li>
+ <li><strong>Enable Experimental Features</strong> <em>Enable or disable <a href="../whatsNew.html#experimental">features still under development</a> in Jalview's user interface. This setting is remembered in your preferences.</em>
</ul></li>
<li><strong>Vamsas</strong> <em>For more details, read the
href="../features/varna.html">VARNA</a>.
</em></li>
<li><a name="hideinserts"><strong>Hide Insertions</strong></a><br />
- <em>Hides columns containing gaps in the current sequence or
- selected region, and reveals columns not including gaps.</em>
+ <em>Hides columns containing gaps in both the current
+ sequence and selected region, and reveals columns not including
+ gaps. (before 2.10.2, this option hid or revealed columns
+ according to gaps in just the current sequence)</em></li>
<li><strong>Hide Sequences</strong><br> <em>Hides the
currently selected sequences in this alignment view.</em><strong><br>
</strong></li>
-->
<head>
<title>Release History</title>
+<style>
+ul {
+ /* remove bullets, narrower indent */
+ list-style-type: none;
+ margin:0;
+ padding-left: 10px;
+ padding-bottom: 4px;
+}
+
+li {
+ /* separate the items from eachother */
+ margin-left: -3px;
+ padding-bottom: 3px;
+ padding-left: 6px;
+}
+li:before {
+ /* doesnt get processed in javahelp */
+ content: '\00b7 ';
+ padding: 3px;
+ margin-left: -14px;
+}
+
+</style>
</head>
<body>
<p>
<tr>
<td width="60" nowrap>
<div align="center">
+ <strong><a name="Jalview.2.10.2">2.10.2</a><br />
+ <em>30/5/2017</em></strong>
+ </div>
+ </td>
+ <td><div align="left">
+ <em>General</em>
+ <ul>
+ <li><!-- JAL-2360,JAL-2371, -->More robust colours and shader model for alignments and groups</li>
+ <li><!-- JAL-384 -->Custom shading schemes created via groovy scripts</li>
+ <li><!-- JAL-2491 -->linked scrolling of CDS/Protein views via Overview or sequence motif search operations</li>
+ <li><!-- JAL-2526 -->Efficiency improvements for interacting with alignment and overview windows</li>
+ <li><!-- JAL-2388 -->Hidden columns and sequences can be omitted in Overview</li>
+ <li>
+ <!-- JAL-2535 -->Posterior probability annotation from
+ Stockholm files imported as sequence associated annotation
+ </li>
+ <li>
+ <!-- JAL-2533 -->Sequence names don't include file
+ extension when importing structure files without embedded
+ names or PDB accessions
+ </li>
+ <li><!-- JAL-2547 -->Amend sequence features dialog box can be opened by double clicking gaps within sequence feature extent</li>
+ </ul>
+ <em>Application</em>
+ <ul>
+ <li>
+ <!-- JAL-2447 -->
+ Experimental Features Checkbox in Desktop's Tools
+ menu to hide or show untested features in the application.
+ </li>
+ <li><!-- JAL-1476 -->Warning in alignment status bar when there are not enough columns to superimpose structures in Chimera</li>
+ <li><!-- JAL-1596 -->Faster Chimera/Jalview communication by file-based command exchange</li>
+ <li><!-- JAL-2316, -->URLs for viewing database cross-references provided by identifiers.org and the EMBL-EBI's MIRIAM DB</li>
+ <li><!-- JAL-2549 -->Updated JABAWS client to v2.2</li>
+ </ul>
+ <em>Experimental features</em>
+ <ul>
+ <li>
+ <!-- JAL-2295, JAL-2296 -->New entries in the Chimera menu
+ to transfer Chimera's structure attributes as Jalview
+ features, and vice-versa.
+ </li>
+ </ul>
+ <em>Applet</em>
+ <ul>
+ <li><!-- --></li>
+ </ul>
+ <em>Test Suite</em>
+ <li><!-- JAL-2474 -->Added PrivilegedAccessor to test suite</li>
+ <li><!-- JAL-2326 -->Prevent or clear modal dialogs raised during tests</li>
+ <li><!-- -->
+ </ul>
+ </div></td><td><div align="left">
+ <em>General</em>
+ <ul>
+ <li>
+ <!-- JAL-2398, -->Fixed incorrect value in BLOSUM 62 score
+ matrix - C->R should be '3'<br />Old matrix restored with
+ this one-line groovy script:<br />jalview.analysis.scoremodels.ScoreModels.instance.BLOSUM62.@matrix[4][1]=3
+ </li>
+ <li>
+ <!-- JAL-2397 -->Fixed Jalview's treatment of gaps in PCA
+ and substitution matrix based Tree calculations.<br />In
+ earlier versions of Jalview, gaps matching gaps were
+ penalised, and gaps matching non-gaps penalised even more.
+ In the PCA calculation, gaps were actually treated as
+ non-gaps - so different costs were applied, which mean't
+ Jalview's PCAs were different to those produced by
+ SeqSpace.<br />Jalview now treats gaps in the same way as
+ SeqSpace (ie it scores them as 0). To restore pre-2.10.2
+ behaviour<br />
+ jalview.viewmodel.PCAModel.scoreGapAsAny=true // for
+ 2.10.1 mode<br />
+ jalview.viewmodel.PCAModel.scoreGapAsAny=false // to
+ restore 2.10.2 mode
+ </li>
+ <li><!-- JAL-2346 -->Reopening Colour by annotation dialog doesn't reselect a specific sequence's associated annotation after it was used for colouring a view</li>
+ <li><!-- JAL-2430 -->Hidden regions in alignment views are not coloured in linked structure views</li>
+ <li><!-- JAL-2419 -->Current selection lost if popup menu opened on a region of alignment without groups</li>
+ <li><!-- JAL-2374 -->Popup menu not always shown for regions of an alignment with overlapping groups</li>
+ <li><!-- JAL-2310 -->Finder double counts if both a sequence's name and description match</li>
+ <li><!-- JAL-2370 -->Hiding column selection containing two hidden regions results in incorrect hidden regions</li>
+ <li><!-- JAL-2377 -->PCA calculation could hang when generating output report when working with highly redundant alignments</li>
+ <li><!-- JAL-2365 -->Cannot configure feature colours with lightGray or darkGray via features file</li>
+ <li><!-- JAL-2421 -->Overview window visible region moves erratically when hidden rows or columns are present</li>
+ <li><!-- JAL-2362 -->Per-residue colourschemes applied via the Structure Viewer's colour menu don't correspond to sequence colouring</li>
+ <li><!-- JAL-2405 -->Protein specific colours only offered in colour and group colour menu for protein alignments</li>
+ <li><!-- JAL-2386 -->'Apply to all groups' setting when changing colour does not apply Conservation slider value to all groups</li>
+ <li><!-- JAL-2385 -->Colour threshold slider doesn't update to reflect currently selected view or group's shading thresholds</li>
+ <li><!-- JAL-2373 -->Percentage identity and conservation menu items do not show a tick or allow shading to be disabled</li>
+ <li><!-- JAL-2385 -->Conservation shading or PID threshold lost when base colourscheme changed if slider not visible</li>
+ <li><!-- JAL-2547 -->Sequence features shown in tooltip for gaps before start of features</li>
+ <li><!-- JAL-2576 -->Very large alignments take a long time to load</li>
+ <li><!-- JAL-2590 -->Cannot load Newick trees from eggnog ortholog database</li>
+ </ul>
+ <em>Application</em>
+ <ul>
+ <li><!-- JAL-2401 -->Easier creation of colours for all 'Lower case' residues (button in colourscheme editor debugged and new documentation and tooltips added)</li>
+ <li><!-- JAL-2399-->Text colour threshold's 'Cancel' button doesn't restore group-specific text colour thresholds</li>
+ <li><!-- JAL-2243 -->Feature settings panel does not update as new features are added to alignment</li>
+ <li><!-- JAL-2436 -->Structure viewer's View -> Colour By view selection menu changes colours of alignment views</li>
+ <li><!-- JAL-2366 -->Proxy server address and port always appear enabled in Preferences->Connections</li>
+ <li><!-- JAL-2426 -->Spurious exceptions in console raised from alignment calculation workers after alignment has been closed</li>
+ <li><!-- JAL-1608 -->Typo in selection popup menu - Create groups now 'Create Group'</li>
+ <li><!-- JAL-1608 -->CMD/CTRL and G or Shift G for Create/Undefine group doesn't always work</li>
+ <li><!-- JAL-2464 -->Tree Viewer's Print Dialog doesn't get shown again after pressing 'Cancel'</li>
+ <li><!-- JAL-2461 -->DAS registry not found exceptions removed from console output</li>
+ <li><!-- JAL-2383 -->Above PID colour threshold not recovered when alignment view imported from project</li>
+ <li><!-- JAL-2465 -->No mappings generated between structure and sequences extracted from structure files imported via URL</li>
+ <li>
+ <!-- JAL-2520 -->Structures loaded via URL are saved in
+ Jalview Projects rather than fetched via URL again when
+ the project is loaded and the structure viewed
+ </li>
+ <li><!-- JAL-1256 -->Trackpad horizontal scroll gesture adjusts start position in wrap mode</li>
+ <li><!-- JAL-2563 -->Status bar doesn't show positions for ambiguous amino acids</li>
+ <li><!-- JAL-2291 -->Hide insertions in PopUp menu excludes gaps in selection, current sequence and only within selected columns</li>
+ </ul>
+ <em>Applet</em>
+ <ul>
+ <li><!-- JAL-2442 -->Features not rendered as transparent on overview or linked structure view</li>
+ <li><!-- JAL-2372 -->Colour group by conservation doesn't work (since 2.8)</li>
+ <li><!-- JAL-2517 -->Hitting Cancel after applying user-defined colourscheme doesn't restore original colourscheme</li>
+ </ul>
+ <em>New Known Issues</em>
+ <ul>
+ <li><!-- JAL-2566 -->Protein/CDS view scrolling not always in phase after a sequence motif find operation</li>
+ <li><!-- JAL-2550 -->Importing annotation file with rows containing just upper and lower case letters are interpreted as WUSS rna secondary structure symbols</li>
+ </ul>
+
+ </div>
+ <tr>
+ <td width="60" nowrap>
+ <div align="center">
<strong><a name="Jalview.2.10.1">2.10.1</a><br />
<em>29/11/2016</em></strong>
</div>
<!--JAL-2332 -->Attempting to view structure for Hen
lysozyme results in a PDB Client error dialog box
</li>
+ <li>
+ <!-- JAL-2319 -->Structure View's mapping report switched ranges for PDB and sequence for SIFTS</li>
+ <!-- JAL-2319 -->SIFTS 'Not_Observed' residues mapped to non-existant coordindate data</li>
</ul>
<!-- <em>New Known Issues</em>
<ul>
<strong><em>A</em></strong>nalysis <strong><em>W</em></strong>eb <strong><em>S</em></strong>ervices
<strong>system</strong> (<strong>JABAWS</strong>)<br> Jalview
includes a client for interacting with programmatic (SOAP) web
- services for the <a href="http://www.compbio.dundee.ac.uk/jabaws">JABAWS</a>
- service model, developed at the University of Dundee by Peter
- Troshin and Geoff Barton. This is an open source system that
- provides a framework for wrapping command line bioinformatics
+ services provided by the <a href="http://www.compbio.dundee.ac.uk/jabaws">JABAWS</a>
+ system, developed at the University of Dundee by Peter
+ Troshin, Sasha Sherstnev, Dan Barton, Fabio Madeira-Marquez, Jim Procter and Geoff Barton.
+ This is an open source system that provides a framework for wrapping command line bioinformatics
analysis programs that enables them to be executed locally or on a
cluster using data and analysis parameters provided by a program
linked with the JABA engine directly or accessing it remotely <em>via</em>
each new server.
</p>
<p>
- <em>Support for accessing JABAWS servers was introduced in
- Jalview 2.6.</em>
+ <em>JABAWS Client updated to version 2.2 in Jalview 2.10.2</em>
</p>
<p>
<em>Option for adding JABAWS servers which fails validation was
introduced from version 2.8.2 </em>
</p>
+ <p>
+ <em>Support for accessing JABAWS servers was introduced in
+ Jalview 2.6.</em>
+ </p>
</body>
</html>
<li>Lupas_21, Lupas_14, Lupas_28<br> <em>Coiled-coil
predictions for the sequence. These are binary predictions for
each location.</em></li>
- <li>JNETSOL25,JNETSOL5,JNETSOL0<br> <em>Solvent
- accessibility predictions - binary predictions of 25%, 5% or 0%
- solvent accessibility.</em></li>
+ <li>Jnet Burial<br> <em>Prediction of Solvent
+ Accessibility. levels are
+ <ul>
+ <li>0 - Exposed</li>
+ <li>3 - 25% or more S.A. accessible</li>
+ <li>6 - 5% or more S.A. accessible</li>
+ <li>9 - Buried (<5% exposed)</li>
+ </ul></li>
<li>JNetPRED<br> <em>The consensus prediction -
helices are marked as red tubes, and sheets as dark green
arrows.</em></li>
<li>JNetHMM<br> <em>HMM profile based prediction -
helices are marked as red tubes, and sheets as dark green
arrows.</em></li>
- <li>jpred<br> <em>Jpred prediction - helices are
- marked as red tubes, and sheets as dark green arrows.</em></li>
<li>JNETPSSM<br> <em>PSSM based prediction - helices
are marked as red tubes, and sheets as dark green arrows.</em></li>
- <li>JNETFREQ<br> <em>Amino Acid frequency based
- prediction - helices are marked as red tubes, and sheets as dark
- green arrows.</em></li>
<li>JNETJURY<br> <em>A '*' in this annotation
indicates that the JNETJURY was invoked to rationalise
significantly different primary predictions.</em></li>
href="../features/annotation.html#seqannots">Add reference
annotation</a> Sequence ID popup menu option.
</em>
- <em>As of Jalview 2.6, the JPred service accessed accessed via the
- 'Secondary structure prediction' submenu should be considered a
+ <em>As of Jalview 2.6, the JPred service accessed accessed via
+ the 'Secondary structure prediction' submenu should be considered a
legacy Jalview SOAP service, and will be replaced in the near future
by a JPred4 Rest service.</em>
</p>
<p>
<strong>Alignment programs supported by JABAWS</strong>. <br />Versions
- shown are those bundled with JABAWS 2.01 - if you are using a
+ shown are those bundled with JABAWS 2.2 - if you are using a
different server, check its home page to find out which versions are
provided.
- <ul>
- <li><a href="http://www.clustal.org/">Clustal Omega and
- Clustal W</a> (version 2.0.12)</li>
- <li><a href="http://mafft.cbrc.jp/alignment/software/">Mafft</a>
- (version 6.8.57b)</li>
- <li><a href="http://www.drive5.com/muscle">Muscle</a> (version
- 3.8.31)</li>
- <li><a
- href="http://www.tcoffee.org/Projects_home_page/t_coffee_home_page.html">Tcoffee</a>
- (version 8.99)</li>
- <li><a href="http://probcons.stanford.edu/">Probcons</a>
- (version 1.12)</li>
+ <ul>
+ <li><a href="http://www.clustal.org/omega">Clustal Omega</a> (version 1.2.4)</li>
+ <li><a href="http://www.clustal.org/clustal2">ClustalW</a> (version 2.1)</li>
+ <li><a href="http://align.bmr.kyushu-u.ac.jp/mafft/software/">Mafft</a> (version 7.310)</li>
+ <li><a href="http://www.drive5.com/muscle">Muscle</a> (version 3.8.31)</li>
+ <li><a href="http://www.tcoffee.org/Projects_home_page/t_coffee_home_page.html">T-coffee</a> (version 11.00.8cbe486)</li>
+ <li><a href="http://probcons.stanford.edu/">Probcons</a> (version 1.12)</li>
+ <li><a href="http://msaprobs.sourceforge.net/">MSAProbs</a> (version 0.9.7)</li>
+ <li><a href="http://sourceforge.net/projects/glprobs/">GLProbs</a> (version 0.9.7)</li>
</ul>
</p>
By Annotation</a> dialog box to colour sequences according to the
results of predictors shown as annotation rows.
</p>
- <p>JABAWS 2.0 provides four disorder predictors which are
+ <p>JABAWS 2.2 provides four disorder predictors which are
described below:</p>
<ul>
<li><a href="#disembl">DisEMBL</a></li>
</p>
<p>
<strong><a name="iupred"></a><a
- href="http://iupred.enzim.hu/Help.php">IUPred</a></strong><br />
+ href="http://iupred.enzim.hu/">IUPred</a></strong><br />
IUPred employs an empirical model to estimate likely regions of
disorder. There are three different prediction types offered, each
using different parameters optimized for slightly different
<em>Adding additional links</em><br /> You can configure your own
links via the Jalview <a href="../features/preferences.html#links"><strong>Preferences</strong></a>
dialog. Jalview also provides persistent URLs for many common
- bioinformatics databases. These links are downloaded by Jalview from
+ bioinformatics databases (since 2.10.2). These links are downloaded by Jalview from
the <em>identifiers.org</em> website, and the names and URLs are not
user editable.
</p>
<p>
- <em>Creating your own URL link</em> URL links are specified as a
+ <em>Creating your own URL link</em> <br/>URL links are specified as a
template containing special tokens that Jalview will replace with
the Sequence ID or Database Accession of the sequence when you
double click on its ID or open it's <strong>Link</strong> submenu.
Swissprot = http://www.expasy.org/uniprot/$SEQUENCE_ID$ <br> </pre>
<p>
Links will also be made for any database cross references associated
- with the sequence where the database name exactly matches a URL link
- name. In this case, the $DB_ACCESSION$ string will be replaced with
+ with the sequence for any link templates whose name begins with the database name.
+ In this case, the $DB_ACCESSION$ string will be replaced with
the accession string for the database cross-reference, rather than
the sequence ID for the sequence (<em>since Jalview 2.10.1</em>).
+ <br /> <em>For example: to create a link for viewing MACiE records
+ from PDB Entries, create a new custom link entry with the name
+ "PDB in MACiE", and link URL template:
+ <pre>https://www.ebi.ac.uk/thornton-srv/databases/cgi-bin/MACiE/index.pl?query_pdb=1&pdb=$DBACCESSION$</pre>
+ <br />The sequence ID popup menu for seuqences with a PDB entry
+ will now show 'PDB in MACiE|1xyz..' links in the <strong>links</strong>
+ submenu.
+ </em>
</p>
<p>
<strong><a name="warning">Warning dialog about updating
</head>
<body>
<p>
- <strong>What's new in Jalview 2.10.1 ?</strong>
+ <strong>What's new in Jalview 2.10.2 ?</strong>
</p>
<p>
- Jalview 2.10.1 was released on 29th November 2016. Full details are
- in the <a href="releases.html#Jalview.2.10.1">Jalview 2.10.1
- Release Notes</a>, but the highlights are below. This is also the
- first release to include contributions from Kira Mourão, who
- joined Jalview's core development team in October 2016.
+ Full details about Jalview 2.10.2 are in the <a
+ href="releases.html#Jalview.2.10.2"> Release Notes</a>, but the
+ highlights are below.
</p>
<ul>
- <li><strong>More memory efficient</strong><br />We've slimmed
- down the consensus analysis data structures used by Jalview so
- even wider alignments can be worked with.</li>
- <li><strong>Select highlighted region</strong><br />Press 'B'
- or use the new menu option in the alignment window's Select menu
- to mark columns containing highlighted regions generated from
- structure selections, mouse-overs, or resulting from a Find
- operation.</li>
- <li><strong>New custom link mechanism for opening URLs
- for database cross references.</strong><br /> If you have customised URL
- links in your Jalview preferences, then you may already have seen
- the <a href="#warning"> warning dialog (see below).</a></li>
- <li><strong>New command line export option for BioJS
- MSAviewer</strong><br />A number of small bugs with the HTML export
- functions from the Jalview desktop were also fixed.</li>
- <li><strong>Small but significant changes to the
- physicochemical properties and consensus calculations</strong><br />Threonine
- is no longer considered a non-hydrophobic residue in the protein
- conservation calculation, and minor bugs addressed in PID and
- consensus colouring.</li>
- <li><strong>Correct display of disulphide bond
- features</strong><br /> In linked structure views, Jalview would
- highlight all residues between in addition to the two linked
- cysteines. The 'select columns by feature' function in the feature
- settings would also select all intermediate columns.
+ <li><strong>Update to JABAWS 2.2</strong><br />Jalview's
+ alignment, protein conservation analysis, and protein disorder and
+ RNA secondary structure prediction services are now provided by <a
+ href="http://www.compbio.dundee.ac.uk/jabaws">JABAWS 2.2</a>.
+ Several of the programs provided as services have been updated, so
+ their options and parameters have changed.</li>
+ <li>New preferences for <a href="webServices/urllinks.html">opening
+ web pages for database cross-references</a> via the UK Elixir's
+ EMBL-EBI's MIRIAM database and identifiers.org services.
+ </li>
+ <li><em>Showing and hiding regions</em>
+ <ul>
+ <li><a href="menus/popupMenu.html#hideinserts">Hide
+ insertions</a> in the PopUp menu has changed its behaviour.
+ Prior to 2.10.2, columns were only shown or hidden according
+ to gaps in the sequence under the popup menu. Now, only
+ columns that are gapped in all selected sequences as well as
+ the sequence under the popup menu are hidden, and column
+ visibility outside the selected region is left as is. This
+ makes it easy to filter insertions from the alignment view
+ (just select the region containing insertions to remove)
+ without affecting the rest of the hidden columns.</li>
+ </ul></li>
</ul>
-
<p>
- <strong><a name="warning">Warning dialog about updating
- your configured URL links</a></strong><br /> In the desktop prior to Jalview
- 2.10.1, the only way to configure custom links for a particular
- database cross-reference for a sequence was to give it a name that <em>exactly</em>
- matched the database source, and a regular expression for filtering
- out any spurious matches generated when the custom linked was tested
- against the Sequence's ID string. Since the introduction of the
- $DB_ACCESSION$ token, however, $SEQUENCE_ID$ will not be used for
- database cross-reference accession strings, and if you have custom
- links configured, Jalview will raise a warning message so let you
- know that you may need to update your links to use $DB_ACCESSION$.
+ <strong><a name="experimental">Experimental Features</a></strong>
</p>
+ <p>
+ This release of Jalview includes a new option in the Jalview Desktop
+ that allows you to try out features that are still in development.
+ To access the features described below, please first enable the <strong>Tools→Enable
+ Experimental Features</strong> option, and then restart Jalview.
+ </p>
+ <ul>
+ <li><em>Annotation transfer between Chimera and Jalview</em><br />Two
+ <a href="features/chimera.html#experimental">new entries in
+ the Chimera viewer's Chimera menu</a> allow positional annotation to
+ be exchanged between Chimera and Jalview.</li>
+ </ul>
</body>
</html>
action.merge_results = Merge Results
action.load_scheme = Load scheme
action.save_scheme = Save scheme
+label.scheme_changed = Changes to scheme ''{0}'' have not been saved.<br><br>Save changes, or continue without saving to make a new colour scheme.
+label.save_changes = Save Changes
+label.dont_save_changes = Don't Save
action.save_image = Save Image
action.paste = Paste
action.show_html_source = Show HTML Source
action.show_hidden_markers = Show Hidden Markers
action.find = Find
action.undefine_groups = Undefine Groups
-action.create_groups = Create Groups
action.make_groups_selection = Make Groups For Selection
action.copy = Copy
action.cut = Cut
action.scale_right = Scale Right
action.by_tree_order = By Tree Order
action.sort = Sort
-action.calculate_tree = Calculate Tree
+action.calculate_tree = Calculate Tree...
+action.calculate_tree_pca = Calculate Tree or PCA...
action.help = Help
action.by_annotation = By Annotation...
action.invert_sequence_selection = Invert Sequence Selection
label.principal_component_analysis = Principal Component Analysis
label.average_distance_identity = Average Distance Using % Identity
label.neighbour_joining_identity = Neighbour Joining Using % Identity
+label.choose_calculation = Choose Calculation
label.treecalc_title = {0} Using {1}
label.tree_calc_av = Average Distance
label.tree_calc_nj = Neighbour Joining
label.score_model_pid = % Identity
label.score_model_blosum62 = BLOSUM62
label.score_model_pam250 = PAM 250
+label.score_model_smithwatermanscore = Score between two sequences aligned with Smith-Waterman with default Peptide/Nucleotide matrix
+label.score_model_sequencefeaturesimilarity = Distance measure of average number of features not shared at sequence positions
label.score_model_conservation = Physicochemical property conservation
label.score_model_enhconservation = Physicochemical property conservation
label.status_bar = Status bar
label.out_to_textbox = Output to Textbox
+label.occupancy = Occupancy
# delete Clustal - use FileFormat name instead
label.clustal = Clustal
# label.colourScheme_<schemeName> as in JalviewColourScheme
label.set_this_label_text = set this label text
label.sequences_from = Sequences from {0}
label.successfully_loaded_file = Successfully loaded file {0}
+label.successfully_loaded_matrix = Successfully loaded score matrix {0}
label.successfully_saved_to_file_in_format = Successfully saved to file: {0} in {1} format.
label.copied_sequences_to_clipboard = Copied {0} sequences to clipboard.
label.check_file_matches_sequence_ids_alignment = Check that the file matches sequence IDs in the alignment.
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_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.sequences_must_be_aligned_before_creating_tree = The sequences must be aligned before creating a tree.\nTry using the Pad function in the edit menu,\n or one of the multiple sequence alignment web services.
-label.sequences_not_aligned = Sequences not aligned
label.problem_reading_tree_file = Problem reading tree file
label.possible_problem_with_tree_file = Possible problem with tree file
label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation = Please select at least three bases in at least one sequence in order to perform a cDNA translation.
label.standard_databases = Standard Databases
label.fetch_embl_uniprot = Fetch from EMBL/EMBLCDS or Uniprot/PDB and any selected DAS sources
label.reset_min_max_colours_to_defaults = Reset min and max colours to defaults from user preferences.
-label.align_structures_using_linked_alignment_views = Align structures using {0} linked alignment views
+label.align_structures_using_linked_alignment_views = Superpose structures using {0} selected alignment view(s)
label.connect_to_session = Connect to session {0}
label.threshold_feature_display_by_score = Threshold the feature display by score.
label.threshold_feature_no_threshold = No Threshold
label.right_click_to_edit_currently_selected_parameter = Right click to edit currently selected parameter.
label.let_jmol_manage_structure_colours = Let Jmol manage structure colours
label.let_chimera_manage_structure_colours = Let Chimera manage structure colours
+label.fetch_chimera_attributes = Fetch Chimera attributes
+label.fetch_chimera_attributes_tip = Copy Chimera attribute to Jalview feature
label.marks_leaves_tree_not_associated_with_sequence = Marks leaves of tree not associated with a sequence
label.index_web_services_menu_by_host_site = Index web services in menu by the host site
label.option_want_informed_web_service_URL_cannot_be_accessed_jalview_when_starts_up = Check this option if you want to be informed<br>when a web service URL cannot be accessed by Jalview<br>when it starts up
label.edit_name_and_description_current_group = Edit name and description of current group
label.from_file = From File
label.enter_pdb_id = Enter PDB Id (or pdbid:chaincode)
-label.text_colour = Text Colour
-action.set_text_colour = Text Colour...
+label.text_colour = Text Colour...
label.structure = Structure
label.show_pdbstruct_dialog = 3D Structure Data...
label.view_rna_structure = VARNA 2D Structure
label.show_labels = Show labels
action.background_colour = Background Colour...
label.associate_nodes_with = Associate Nodes With
-label.jalview_pca_calculation = Jalview PCA Calculation
label.link_name = Link Name
label.pdb_file = PDB file
label.colour_with_jmol = Colour with Jmol
label.colour_with_chimera = Colour with Chimera
-label.align_structures = Align Structures
+label.superpose_structures = Superpose Structures
+error.superposition_failed = Superposition failed: {0}
+label.insufficient_residues = Not enough aligned residues ({0}) to perform superposition
label.jmol = Jmol
label.chimera = Chimera
+label.create_chimera_attributes = Write Jalview features
+label.create_chimera_attributes_tip = Set Chimera residue attributes for visible features
+label.attributes_set = {0} attribute values set on Chimera
label.sort_alignment_by_tree = Sort Alignment By Tree
label.mark_unlinked_leaves = Mark Unlinked Leaves
label.associate_leaves_with = Associate Leaves With
label.error_whilst_saving_current_state_to = Error whilst saving current state to {0}
label.error_whilst_loading_project_from = Error whilst loading project from {0}
label.couldnt_load_project = Couldn't load project
-label.pca_sequences_not_aligned = The sequences must be aligned before calculating PCA.\nTry using the Pad function in the edit menu,\nor one of the multiple sequence alignment web services.
label.invalid_name_preset_exists = Invalid name - preset already exists.
label.invalid_name = Invalid name
label.set_proxy_settings = Please set up your proxy settings in the 'Connections' tab of the Preferences window
label.save_as_html = Save as HTML
label.recently_opened = Recently Opened
label.blasting_for_unidentified_sequence_jobs_running = BLASTing for unidentified sequences - {0} jobs running.
+label.tree = Tree
label.tree_from = Tree from {0}
label.webservice_job_title = {0} using {1}
label.select_visible_region_of = selected {0} region of {1}
label.updating_vamsas_session = Updating vamsas session
label.loading_file = Loading File: {0}
label.edit_params = Edit {0}
+label.as_percentage = As Percentage
error.not_implemented = Not implemented
error.no_such_method_as_clone1_for = No such method as clone1 for {0}
error.null_from_clone1 = Null from clone1!
label.start_jalview = Start Jalview
label.biojs_html_export = BioJS
label.scale_as_cdna = Scale protein residues to codons
+label.font_as_cdna = Use same font for cDNA and peptide
label.scale_protein_to_cdna = Scale Protein to cDNA
label.scale_protein_to_cdna_tip = Make protein residues same width as codons in split frame views
info.select_annotation_row = Select Annotation Row
warn.name_cannot_be_duplicate = User-defined URL names must be unique and cannot be MIRIAM ids
label.invalid_name = Invalid Name !
label.output_seq_details = Output Sequence Details to list all database references
-label.urllinks = Links
\ No newline at end of file
+label.urllinks = Links
+label.default_cache_size = Default Cache Size
+action.clear_cached_items = Clear Cached Items
+label.togglehidden = Show hidden regions
+label.quality_descr = Alignment Quality based on Blosum62 scores
+label.conservation_descr = Conservation of total alignment less than {0}% gaps
+label.consensus_descr = PID
+label.complement_consensus_descr = PID for cDNA
+label.strucconsensus_descr = PID for base pairs
+label.occupancy_descr = Number of aligned positions
+label.show_experimental = Enable experimental features
+label.show_experimental_tip = Enable any new and currently 'experimental' features (see Latest Release Notes for details)
+label.warning_hidden = Warning: {0} {1} is currently hidden
action.merge_results = Unificar resultados
action.load_scheme = Cargar esquema
action.save_scheme = Guardar esquema
+label.scheme_changed = Cambios en el esquema ''{0}'' no se han guardado.<br><br>Guardar cambios, o continuar sin guardar para hacer un nuevo esquema.
+label.save_changes = Guardar cambios
+label.dont_save_changes = No guardar
action.save_image = Guardar imagen
action.paste = Pegar
action.show_html_source = Mostrar código HTML
action.show_hidden_markers = Mostrar marcadores ocultos
action.find = Buscar
action.undefine_groups = Grupos sin definir
-action.create_groups = Crear grupos
action.make_groups_selection = Hacer grupos para seleccionar
action.copy = Copiar
action.cut = Cortar
action.scale_right = Escala derecha
action.by_tree_order = Por orden del árbol
action.sort = Ordenar
-action.calculate_tree = Calcular árbol
+action.calculate_tree = Calcular árbol...
+action.calculate_tree_pca = Calcular árbol o ACP...
action.help = Ayuda
action.by_annotation = Por anotación...
action.invert_sequence_selection = Invertir selección de secuencias
label.principal_component_analysis = Análisis del Componente Principal
label.average_distance_identity = Distancia Media Usando % de Identidad
label.neighbour_joining_identity = Unir vecinos utilizando % de Identidad
+label.choose_calculation = Elegir el cálculo
label.treecalc_title = {0} utilizando {1}
label.tree_calc_av = Distancia media
label.tree_calc_nj = Unir vecinos
label.score_model_pid = % Identidad
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 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.out_to_textbox = Generar cuadro de texto
+label.occupancy = Ocupación
label.clustal = Clustal
# label.colourScheme_<schemeName> as in JalviewColourScheme
label.colourScheme_clustal = Clustalx
label.set_this_label_text = fijar como etiqueta
label.sequences_from = Secuencias de {0}
label.successfully_loaded_file = Fichero cargado exitosamente {0}
+label.successfully_loaded_matrix = Matriz cargada exitosamente {0}
label.successfully_saved_to_file_in_format = Guardado exitosamente en el fichero: {0} en formato {1}.
label.copied_sequences_to_clipboard = Copiadas {0} secuencias en el portapapeles.
label.check_file_matches_sequence_ids_alignment = Comprobar que el fichero coincide con el ID de la secuencia en el alineamiento.
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.sequences_must_be_aligned_before_creating_tree = Las secuencias deben estar alineadas antes de crear el \u00E1rbol.\nPrueba usando la funci\u00F3n Pad en el men\u00FA de editar,\n o uno de los m\u00FAltiples servicios web de alineamiento de secuencias.
-label.sequences_not_aligned = Secuencias no alineadas
label.problem_reading_tree_file = Problema al leer el fichero del árbol
label.possible_problem_with_tree_file = Posible problema con el fichero del árbol
label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation = Por favor seleccionar al menos tres bases de al menos una secuencia para poder realizar la traducción de cDNA.
label.selection_output_command = Seleccionar salida - {0}
label.annotation_for_displayid = <p><h2>Anotación para {0} </h2></p><p>
label.pdb_sequence_mapping = PDB - Mapeado de secuencia
-label.pca_details = detalles de la PCA
+label.pca_details = detalles de la ACP
label.redundancy_threshold_selection = Selección del umbral de redundancia
label.user_defined_colours = Colores definidos del usuario
label.jalviewLite_release = JalviewLite - versión {0}
label.no_features_added_to_this_alignment = No hay funciones asociadas a este alineamiento!!
label.features_can_be_added_from_searches_1 = (Las funciones pueden ser añadidas de búsquedas o
label.features_can_be_added_from_searches_2 = de ficheros de funciones Jalview / GFF)
-label.calculating_pca= Calculando PCA
+label.calculating_pca= Calculando ACP
label.jalview_cannot_open_file = Jalview no puede abrir el fichero
label.jalview_applet = Aplicación Jalview
label.loading_data = Cargando datos
label.standard_databases = Bases de datos estándar
label.fetch_embl_uniprot = Recuperar de EMBL/EMBLCDS o Uniprot/PDB y de cualquier fuente DAS seleccionada
label.reset_min_max_colours_to_defaults = Reiniciar los colores min y max colours a los valores por defecto establecidos en las preferencias de usuario
-label.align_structures_using_linked_alignment_views = Alinear las estructuras utlizando las {0} vistas de alineamiento enlazadas
+label.align_structures_using_linked_alignment_views = Alinear las estructuras utilizando las {0} vista(s) de alineamiento enlazada(s)
label.connect_to_session = Conectar a la sesión {0}
label.threshold_feature_display_by_score = Filtrar la característica mostrada por puntuación.
label.threshold_feature_no_threshold = Sin umbral
label.edit_name_and_description_current_group = Editar el nombre y la descripción del grupo actual
label.from_file = desde fichero
label.enter_pdb_id = Introducir PDB Id
-label.text_colour = Color del texto
+label.text_colour = Color de texto...
label.structure = Estructura
label.create_sequence_details_report_annotation_for = Anotación para {0}
label.sequence_details_for = Detalles de la secuencia para {0}
label.set_as_default = Establecer por defecto
label.show_labels = Mostrar etiquetas
label.associate_nodes_with = Asociar nodos con
-label.jalview_pca_calculation = Cálculo del PCA por Jalview
label.link_name = Nombre del enalce
label.pdb_file = Fichero PDB
label.colour_with_jmol = Colorear con Jmol
-label.align_structures = Alinear estructuras
label.jmol = Jmol
label.sort_alignment_by_tree = Ordenar alineamiento por árbol
label.mark_unlinked_leaves = Marcar las hojas como no enlazadas
label.error_whilst_saving_current_state_to = Error mientras se guardaba el estado a {0}
label.error_whilst_loading_project_from = Error cargando el proyecto desde {0}
label.couldnt_load_project = No es posible cargar el proyecto
-label.pca_sequences_not_aligned = Las secuencias deben estar alineadas antes de calcular el PCA.\nPruebe a utilizar la funci\u00F3n de rellenar huecos en el men\u00FA Editar,\no cualquiera de los servicios web de alineamiento m\u00FAltiple.
label.invalid_name_preset_exists = Nombre no válido - esta preconfiguración ya existe.
label.invalid_name = Nombre no válido
label.set_proxy_settings = Por favor, configure su proxy en la pestaña 'Conexiones' de la ventana de Preferencia
label.save_as_html = Guardar como HTML
label.recently_opened = Abiertos recientemente
label.blasting_for_unidentified_sequence_jobs_running = Ejecutando BLAST de las secuencias no indentificadas - {0} trabajos en marcha.
+label.tree = Árbol
label.tree_from = Árbol de {0}
label.webservice_job_title = {0} usando {1}
label.select_visible_region_of = seleccionada {0} región de {1}
label.updating_vamsas_session = Actualizando sesión VAMSAS
label.loading_file = Cargando fichero: {0}
label.edit_params = Editar {0}
+label.as_percentage = Como Porcentaje
error.not_implemented = No implementado
error.no_such_method_as_clone1_for = No existe ese método como un clone1 de {0}
error.null_from_clone1 = Nulo de clone1!
label.empty_alignment_job = Trabajo de alineamiento vacío
label.add_new_sbrs_service = Añadir un nuevo SBRS
label.edit_sbrs_entry = Editar entrada SBRS
-label.pca_recalculating = Recalculando PCA
-label.pca_calculating = Calculando PCA
+label.pca_recalculating = Recalculando ACP
+label.pca_calculating = Calculando ACP
label.select_foreground_colour = Escoger color del primer plano
label.select_colour_for_text = Seleccione el color del texto
label.adjunst_foreground_text_colour_threshold = Ajustar el umbral del color del texto en primer plano
label.nuc_alignment_colour=Color del Alineamiento Nucleotídico
label.copy_format_from=Copiar formato de
label.chimera=Chimera
+label.create_chimera_attributes = Escribir características de Jalview
+label.create_chimera_attributes_tip = Establecer atributos en Chimera para características visibles
+label.attributes_set = {0} valores de atributos establecidos en Chimera
label.open_split_window=Abrir ventana dividida
label.open_split_window?=¿Quieres abrir ventana dividida, con cDNA y proteína vinculadas?
status.searching_for_pdb_structures=Buscando Estructuras PDB
label.scale_as_cdna=Adaptar residuos proteicos a los codones
+label.font_as_cdna=Utilizar la misma fuente para nucleotídos y proteicos
action.export_hidden_sequences=Exportar Secuencias Ocultas
action.export_hidden_columns=Exportar Columnas Ocultas
label.found_structures_summary=Resumen de Estructuras Encontradas
action.export_annotations=Exportar Anotaciones
action.set_as_reference=Marcar como Referencia
action.unmark_as_reference=Desmarcar como Referencia
-action.set_text_colour=Color de Texto...
label.chimera_failed=Error al abrir Chimera - está instalado?\nCompruebe ruta en Preferencias, Estructura
label.find=Buscar
label.select_pdb_file=Seleccionar Fichero PDB
label.structures_filter=Filtro de Estructuras
label.scale_protein_to_cdna=Adaptar proteína a cDNA
+label.scale_protein_to_cdna_tip=Hacer a los residuos de proteínas de la misma anchura que los codones en ventanas divididas
status.loading_cached_pdb_entries=Cargando Entradas PDB en Caché
label.select=Seleccionar :
label.select_by_annotation=Seleccionar/Ocultar Columnas por Anotación
info.change_threshold_mode_to_enable=Cambiar Modo de Umbral para Habilitar
label.separate_multiple_query_values=Introducir uno o mas {0}s separados por punto y coma ";"
label.let_chimera_manage_structure_colours=Deja que Chimera maneje colores de estructuras
+label.fetch_chimera_attributes = Buscar atributos desde Chimera
+label.fetch_chimera_attributes_tip = Copiar atributo de Chimera a característica de Jalview
label.view_rna_structure=Estructura 2D VARNA
-label.scale_protein_to_cdna_tip=Hacer a los residuos de proteínas de la misma anchura que los codones en ventanas divididas
label.colour_with_chimera=Colorear con Chimera
+label.superpose_structures = Superponer estructuras
+error.superposition_failed = Superposición fallido: {0}
+label.insufficient_residues = Residuos alineados ({0}) insuficentes para superponer
label.show_pdbstruct_dialog=Datos de Estructura 3D...
label.hide_all=Ocultar todos
label.invert=Invertir
label.alpha_helix=Hélice Alfa
label.chimera_help=Ayuda para Chimera
label.find_tip=Buscar alineamiento, selección o IDs de secuencia para una subsecuencia (sin huecos)
-label.structure_viewer=Visualizador de estructura for defecto
+label.structure_viewer=Visualizador de estructura por defecto
label.embbed_biojson=Incrustar BioJSON al exportar HTML
label.transparency_tip=Ajustar la transparencia a "ver a través" los colores de las características.
label.choose_annotations=Escoja anotaciones
warn.name_cannot_be_duplicate = Los nombres URL definidos por el usuario deben ser únicos y no pueden ser ids de MIRIAM
label.invalid_name = Nombre inválido !
label.output_seq_details = Seleccionar Detalles de la secuencia para ver todas
-label.urllinks = Enlaces
\ No newline at end of file
+label.urllinks = Enlaces
+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
+label.warning_hidden = Advertencia: {0} {1} está actualmente oculto
--- /dev/null
+ScoreMatrix BLOSUM62
+#
+# The BLOSUM62 substitution matrix, as at https://www.ncbi.nlm.nih.gov/Class/FieldGuide/BLOSUM62.txt
+# The first line declares a ScoreMatrix with the name BLOSUM62 (shown in menus)
+#
+# Scores are not symbol case sensitive, unless column(s) are provided for lower case characters
+# The 'guide symbol' at the start of each row of score values is optional
+# Values may be integer or floating point, delimited by tab, space, comma or combinations
+#
+ A R N D C Q E G H I L K M F P S T W Y V B Z X *
+A 4 -1 -2 -2 0 -1 -1 0 -2 -1 -1 -1 -1 -2 -1 1 0 -3 -2 0 -2 -1 0 -4
+R -1 5 0 -2 -3 1 0 -2 0 -3 -2 2 -1 -3 -2 -1 -1 -3 -2 -3 -1 0 -1 -4
+N -2 0 6 1 -3 0 0 0 1 -3 -3 0 -2 -3 -2 1 0 -4 -2 -3 3 0 -1 -4
+D -2 -2 1 6 -3 0 2 -1 -1 -3 -4 -1 -3 -3 -1 0 -1 -4 -3 -3 4 1 -1 -4
+C 0 -3 -3 -3 9 -3 -4 -3 -3 -1 -1 -3 -1 -2 -3 -1 -1 -2 -2 -1 -3 -3 -2 -4
+Q -1 1 0 0 -3 5 2 -2 0 -3 -2 1 0 -3 -1 0 -1 -2 -1 -2 0 3 -1 -4
+E -1 0 0 2 -4 2 5 -2 0 -3 -3 1 -2 -3 -1 0 -1 -3 -2 -2 1 4 -1 -4
+G 0 -2 0 -1 -3 -2 -2 6 -2 -4 -4 -2 -3 -3 -2 0 -2 -2 -3 -3 -1 -2 -1 -4
+H -2 0 1 -1 -3 0 0 -2 8 -3 -3 -1 -2 -1 -2 -1 -2 -2 2 -3 0 0 -1 -4
+I -1 -3 -3 -3 -1 -3 -3 -4 -3 4 2 -3 1 0 -3 -2 -1 -3 -1 3 -3 -3 -1 -4
+L -1 -2 -3 -4 -1 -2 -3 -4 -3 2 4 -2 2 0 -3 -2 -1 -2 -1 1 -4 -3 -1 -4
+K -1 2 0 -1 -3 1 1 -2 -1 -3 -2 5 -1 -3 -1 0 -1 -3 -2 -2 0 1 -1 -4
+M -1 -1 -2 -3 -1 0 -2 -3 -2 1 2 -1 5 0 -2 -1 -1 -1 -1 1 -3 -1 -1 -4
+F -2 -3 -3 -3 -2 -3 -3 -3 -1 0 0 -3 0 6 -4 -2 -2 1 3 -1 -3 -3 -1 -4
+P -1 -2 -2 -1 -3 -1 -1 -2 -2 -3 -3 -1 -2 -4 7 -1 -1 -4 -3 -2 -2 -1 -2 -4
+S 1 -1 1 0 -1 0 0 0 -1 -2 -2 0 -1 -2 -1 4 1 -3 -2 -2 0 0 0 -4
+T 0 -1 0 -1 -1 -1 -1 -2 -2 -1 -1 -1 -1 -2 -1 1 5 -2 -2 0 -1 -1 0 -4
+W -3 -3 -4 -4 -2 -2 -3 -2 -2 -3 -2 -3 -1 1 -4 -3 -2 11 2 -3 -4 -3 -2 -4
+Y -2 -2 -2 -3 -2 -1 -2 -3 2 -1 -1 -2 -1 3 -3 -2 -2 2 7 -1 -3 -2 -1 -4
+V 0 -3 -3 -3 -1 -2 -2 -3 -3 3 1 -2 1 -1 -2 -2 0 -3 -1 4 -3 -2 -1 -4
+B -2 -1 3 4 -3 0 1 -1 0 -3 -4 0 -3 -3 -2 0 -1 -4 -3 -3 4 1 -1 -4
+Z -1 0 0 1 -3 3 4 -2 0 -3 -3 1 -1 -3 -1 0 -1 -3 -2 -2 1 4 -1 -4
+X 0 -1 -1 -1 -2 -1 -1 -1 -1 -1 -1 -1 -1 -1 -2 0 0 -2 -1 -1 -1 -1 -1 -4
+* -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 1
--- /dev/null
+#
+# Source: http://www.genome.jp/dbget-bin/www_bget?aaindex:HENS920103
+#
+H HENS920103
+D BLOSUM80 substitution matrix (Henikoff-Henikoff, 1992)
+R PMID:1438297
+A Henikoff, S. and Henikoff, J.G.
+T Amino acid substitution matrices from protein blocks
+J Proc. Natl. Acad. Sci. USA 89, 10915-10919 (1992)
+* matrix in 1/3 Bit Units
+M rows = ARNDCQEGHILKMFPSTWYV, cols = ARNDCQEGHILKMFPSTWYV
+ 7.
+ -3. 9.
+ -3. -1. 9.
+ -3. -3. 2. 10.
+ -1. -6. -5. -7. 13.
+ -2. 1. 0. -1. -5. 9.
+ -2. -1. -1. 2. -7. 3. 8.
+ 0. -4. -1. -3. -6. -4. -4. 9.
+ -3. 0. 1. -2. -7. 1. 0. -4. 12.
+ -3. -5. -6. -7. -2. -5. -6. -7. -6. 7.
+ -3. -4. -6. -7. -3. -4. -6. -7. -5. 2. 6.
+ -1. 3. 0. -2. -6. 2. 1. -3. -1. -5. -4. 8.
+ -2. -3. -4. -6. -3. -1. -4. -5. -4. 2. 3. -3. 9.
+ -4. -5. -6. -6. -4. -5. -6. -6. -2. -1. 0. -5. 0. 10.
+ -1. -3. -4. -3. -6. -3. -2. -5. -4. -5. -5. -2. -4. -6. 12.
+ 2. -2. 1. -1. -2. -1. -1. -1. -2. -4. -4. -1. -3. -4. -2. 7.
+ 0. -2. 0. -2. -2. -1. -2. -3. -3. -2. -3. -1. -1. -4. -3. 2. 8.
+ -5. -5. -7. -8. -5. -4. -6. -6. -4. -5. -4. -6. -3. 0. -7. -6. -5. 16.
+ -4. -4. -4. -6. -5. -3. -5. -6. 3. -3. -2. -4. -3. 4. -6. -3. -3. 3. 11.
+ -1. -4. -5. -6. -2. -4. -4. -6. -5. 4. 1. -4. 1. -2. -4. -3. 0. -5. -3. 7.
+//
--- /dev/null
+ScoreMatrix DNA
+#
+# A DNA substitution matrix.
+# This is an ad-hoc matrix which, in addition to penalising mutations between the common
+# nucleotides (ACGT), includes T/U equivalence in order to allow both DNA and/or RNA.
+# In addition, it encodes weak equivalence between R and Y with AG and CTU, respectively,
+# and N is allowed to match any other base weakly.
+# This matrix also includes I (Inosine) and X (Xanthine), but encodes them to weakly match
+# any of (ACGTU), and unfavourably match each other.
+#
+# The first line declares a ScoreMatrix with the name DNA (shown in menus)
+# Scores are not case sensitive, unless column(s) are provided for lower case characters
+#
+# Values may be integer or floating point, delimited by tab, space, comma or combinations
+#
+ A C G T U I X R Y N -
+A 10 -8 -8 -8 -8 1 1 1 -8 1 1
+C -8 10 -8 -8 -8 1 1 -8 1 1 1
+G -8 -8 10 -8 -8 1 1 1 -8 1 1
+T -8 -8 -8 10 10 1 1 -8 1 1 1
+U -8 -8 -8 10 10 1 1 -8 1 1 1
+I 1 1 1 1 1 10 0 0 0 1 1
+X 1 1 1 1 1 0 10 0 0 1 1
+R 1 -8 1 -8 -8 0 0 10 -8 1 1
+Y -8 1 -8 1 1 0 0 -8 10 1 1
+N 1 1 1 1 1 1 1 1 1 10 1
+- 1 1 1 1 1 1 1 1 1 1 1
--- /dev/null
+ScoreMatrix PAM250
+#
+# The PAM250 substitution matrix
+# The first line declares a ScoreMatrix with the name PAM250 (shown in menus)
+# Scores are not case sensitive, unless column(s) are provided for lower case characters
+# Values may be integer or floating point, delimited by tab, space, comma or combinations
+#
+ A R N D C Q E G H I L K M F P S T W Y V B Z X *
+A 2 -2 0 0 -2 0 0 1 -1 -1 -2 -1 -1 -3 1 1 1 -6 -3 0 0 0 0 -8
+R -2 6 0 -1 -4 1 -1 -3 2 -2 -3 3 0 -4 0 0 -1 2 -4 -2 -1 0 -1 -8
+N 0 0 2 2 -4 1 1 0 2 -2 -3 1 -2 -3 0 1 0 -4 -2 -2 2 1 0 -8
+D 0 -1 2 4 -5 2 3 1 1 -2 -4 0 -3 -6 -1 0 0 -7 -4 -2 3 3 -1 -8
+C -2 -4 -4 -5 12 -5 -5 -3 -3 -2 -6 -5 -5 -4 -3 0 -2 -8 0 -2 -4 -5 -3 -8
+Q 0 1 1 2 -5 4 2 -1 3 -2 -2 1 -1 -5 0 -1 -1 -5 -4 -2 1 3 -1 -8
+E 0 -1 1 3 -5 2 4 0 1 -2 -3 0 -2 -5 -1 0 0 -7 -4 -2 3 3 -1 -8
+G 1 -3 0 1 -3 -1 0 5 -2 -3 -4 -2 -3 -5 0 1 0 -7 -5 -1 0 0 -1 -8
+H -1 2 2 1 -3 3 1 -2 6 -2 -2 0 -2 -2 0 -1 -1 -3 0 -2 1 2 -1 -8
+I -1 -2 -2 -2 -2 -2 -2 -3 -2 5 2 -2 2 1 -2 -1 0 -5 -1 4 -2 -2 -1 -8
+L -2 -3 -3 -4 -6 -2 -3 -4 -2 2 6 -3 4 2 -3 -3 -2 -2 -1 2 -3 -3 -1 -8
+K -1 3 1 0 -5 1 0 -2 0 -2 -3 5 0 -5 -1 0 0 -3 -4 -2 1 0 -1 -8
+M -1 0 -2 -3 -5 -1 -2 -3 -2 2 4 0 6 0 -2 -2 -1 -4 -2 2 -2 -2 -1 -8
+F -3 -4 -3 -6 -4 -5 -5 -5 -2 1 2 -5 0 9 -5 -3 -3 0 7 -1 -4 -5 -2 -8
+P 1 0 0 -1 -3 0 -1 0 0 -2 -3 -1 -2 -5 6 1 0 -6 -5 -1 -1 0 -1 -8
+S 1 0 1 0 0 -1 0 1 -1 -1 -3 0 -2 -3 1 2 1 -2 -3 -1 0 0 0 -8
+T 1 -1 0 0 -2 -1 0 0 -1 0 -2 0 -1 -3 0 1 3 -5 -3 0 0 -1 0 -8
+W -6 2 -4 -7 -8 -5 -7 -7 -3 -5 -2 -3 -4 0 -6 -2 -5 17 0 -6 -5 -6 -4 -8
+Y -3 -4 -2 -4 0 -4 -4 -5 0 -1 -1 -4 -2 7 -5 -3 -3 0 10 -2 -3 -4 -2 -8
+V 0 -2 -2 -2 -2 -2 -2 -1 -2 4 2 -2 2 -1 -1 -1 0 -6 -2 4 -2 -2 -1 -8
+B 0 -1 2 3 -4 1 3 0 1 -2 -3 1 -2 -4 -1 0 0 -5 -3 -2 3 2 -1 -8
+Z 0 0 1 3 -5 3 3 0 2 -2 -3 0 -2 -5 0 0 -1 -6 -4 -2 2 3 -1 -8
+X 0 -1 0 -1 -3 -1 -1 -1 -1 -1 -1 -1 -1 -2 -1 0 0 -4 -2 -1 -1 -1 -1 -8
+* -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 -8 1
import jalview.datamodel.SequenceI;
import jalview.io.DataSourceType;
import jalview.io.StructureFile;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.structure.AtomSpec;
import jalview.structure.StructureListener;
import jalview.structure.StructureMapping;
colourBySequence();
- int max = -10;
+ float max = -10;
int maxchain = -1;
int pdbstart = 0;
int pdbend = 0;
showFeatures = true;
}
+ FeatureColourFinder finder = new FeatureColourFinder(fr);
+
PDBChain chain;
if (bysequence && pdb != null)
{
if (pos > 0)
{
pos = sequence[s].findIndex(pos);
- tmp.startCol = sr.getResidueBoxColour(sequence[s], pos);
- if (showFeatures)
- {
- tmp.startCol = fr.findFeatureColour(tmp.startCol,
- sequence[s], pos);
- }
+ tmp.startCol = sr.getResidueColour(sequence[s], pos,
+ finder);
}
pos = mapping[m].getSeqPos(tmp.at2.resNumber) - 1;
if (pos > 0)
{
pos = sequence[s].findIndex(pos);
- tmp.endCol = sr.getResidueBoxColour(sequence[s], pos);
- if (showFeatures)
- {
- tmp.endCol = fr.findFeatureColour(tmp.endCol,
- sequence[s], pos);
- }
+ tmp.endCol = sr
+ .getResidueColour(sequence[s], pos, finder);
}
-
}
}
}
// ////////////////////////////////
// /StructureListener
@Override
- public String[] getPdbFile()
+ public String[] getStructureFiles()
{
return new String[] { pdbentry.getFile() };
}
import jalview.gui.SequenceRenderer;
import jalview.io.DataSourceType;
import jalview.io.StructureFile;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.structure.AtomSpec;
import jalview.structure.StructureListener;
import jalview.structure.StructureMapping;
colourBySequence();
- int max = -10;
+ float max = -10;
int maxchain = -1;
int pdbstart = 0;
int pdbend = 0;
showFeatures = true;
}
+ FeatureColourFinder finder = new FeatureColourFinder(fr);
PDBChain chain;
if (bysequence && pdb != null)
{
if (pos > 0)
{
pos = sequence[s].findIndex(pos);
- tmp.startCol = sr.getResidueBoxColour(sequence[s], pos);
- if (showFeatures)
- {
- tmp.startCol = fr.findFeatureColour(tmp.startCol,
- sequence[s], pos);
- }
+ tmp.startCol = sr.getResidueColour(sequence[s], pos,
+ finder);
}
pos = mapping[m].getSeqPos(tmp.at2.resNumber) - 1;
if (pos > 0)
{
pos = sequence[s].findIndex(pos);
- tmp.endCol = sr.getResidueBoxColour(sequence[s], pos);
- if (showFeatures)
- {
- tmp.endCol = fr.findFeatureColour(tmp.endCol,
- sequence[s], pos);
- }
+ tmp.endCol = sr
+ .getResidueColour(sequence[s], pos, finder);
}
}
// ////////////////////////////////
// /StructureListener
@Override
- public String[] getPdbFile()
+ public String[] getStructureFiles()
{
return new String[] { pdbentry.getFile() };
}
public class PDBChain
{
+ public static final String RESNUM_FEATURE = "RESNUM";
+
/**
* SequenceFeature group for PDB File features added to sequences
*/
Residue tmpres = residues.lastElement();
Atom tmpat = tmpres.atoms.get(0);
// Make A new SequenceFeature for the current residue numbering
- SequenceFeature sf = new SequenceFeature("RESNUM", tmpat.resName
+ SequenceFeature sf = new SequenceFeature(RESNUM_FEATURE, tmpat.resName
+ ":" + tmpat.resNumIns + " " + pdbid + id, "", offset
+ count, offset + count, pdbid);
resFeatures.addElement(sf);
"list selection level residue", true);
if (chimeraReply != null)
{
+ /*
+ * expect 0, 1 or more lines of the format
+ * residue id #0:43.A type GLY
+ * where we are only interested in the atomspec #0.43.A
+ */
for (String inputLine : chimeraReply)
{
String[] inputLineParts = inputLine.split("\\s+");
import jalview.util.MappingUtils;
import jalview.util.QuickSort;
+import java.awt.Color;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
}
}
- public static final ProfilesI calculate(List<SequenceI> list,
- int start, int end)
+ public static final ProfilesI calculate(List<SequenceI> list, int start,
+ int end)
{
return calculate(list, start, end, false);
}
}
/**
+ * Derive the gap count annotation row.
+ *
+ * @param gaprow
+ * the annotation row to add annotations to
+ * @param profiles
+ * the source consensus data
+ * @param startCol
+ * start column (inclusive)
+ * @param endCol
+ * end column (exclusive)
+ */
+ public static void completeGapAnnot(AlignmentAnnotation gaprow,
+ ProfilesI profiles, int startCol, int endCol, long nseq)
+ {
+ if (gaprow == null || gaprow.annotations == null
+ || gaprow.annotations.length < endCol)
+ {
+ /*
+ * called with a bad alignment annotation row
+ * wait for it to be initialised properly
+ */
+ return;
+ }
+ // always set ranges again
+ gaprow.graphMax = nseq;
+ gaprow.graphMin = 0;
+ double scale = 0.8/nseq;
+ for (int i = startCol; i < endCol; i++)
+ {
+ ProfileI profile = profiles.get(i);
+ if (profile == null)
+ {
+ /*
+ * happens if sequences calculated over were
+ * shorter than alignment width
+ */
+ gaprow.annotations[i] = null;
+ return;
+ }
+
+ final int gapped = profile.getNonGapped();
+
+ String description = "" + gapped;
+
+ gaprow.annotations[i] = new Annotation("", description,
+ '\0', gapped, jalview.util.ColorUtils.bleachColour(
+ Color.DARK_GRAY, (float) scale * gapped));
+ }
+ }
+
+ /**
* Returns a tooltip showing either
* <ul>
* <li>the full profile (percentages of all residues present), if
* calculations
* @return
*/
- public static int[] extractProfile(ProfileI profile,
- boolean ignoreGaps)
+ public static int[] extractProfile(ProfileI profile, boolean ignoreGaps)
{
int[] rtnval = new int[64];
ResidueCount counts = profile.getCounts();
*/
package jalview.analysis;
+import jalview.analysis.scoremodels.PIDModel;
+import jalview.analysis.scoremodels.ScoreMatrix;
+import jalview.analysis.scoremodels.ScoreModels;
+import jalview.analysis.scoremodels.SimilarityParams;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.Mapping;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceI;
-import jalview.schemes.ResidueProperties;
-import jalview.schemes.ScoreMatrix;
import jalview.util.Comparison;
import jalview.util.Format;
import jalview.util.MapList;
private static final String NEWLINE = System.lineSeparator();
- static String[] dna = { "A", "C", "G", "T", "-" };
+ float[][] score;
- // "C", "T", "A", "G", "-"};
- static String[] pep = { "A", "R", "N", "D", "C", "Q", "E", "G", "H", "I",
- "L", "K", "M", "F", "P", "S", "T", "W", "Y", "V", "B", "Z", "X", "-" };
+ float[][] E;
- int[][] score;
-
- int[][] E;
-
- int[][] F;
+ float[][] F;
int[][] traceback;
int count;
/** DOCUMENT ME!! */
- public int maxscore;
+ public float maxscore;
float pid;
int gapExtend = 20;
- int[][] lookup = ResidueProperties.getBLOSUM62();
-
- String[] intToStr = pep;
-
- int defInt = 23;
-
StringBuffer output = new StringBuffer();
- String type;
+ String type; // AlignSeq.PEP or AlignSeq.DNA
+
+ private ScoreMatrix scoreMatrix;
- private int[] charToInt;
+ private static final int GAP_INDEX = -1;
/**
* Creates a new AlignSeq object.
*
- * @param s1
- * DOCUMENT ME!
- * @param s2
- * DOCUMENT ME!
- * @param type
- * DOCUMENT ME!
+ * @param s1 first sequence for alignment
+ * @param s2 second sequence for alignment
+ * @param type molecule type, either AlignSeq.PEP or AlignSeq.DNA
*/
public AlignSeq(SequenceI s1, SequenceI s2, String type)
{
- SeqInit(s1, s1.getSequenceAsString(), s2, s2.getSequenceAsString(),
+ seqInit(s1, s1.getSequenceAsString(), s2, s2.getSequenceAsString(),
type);
}
public AlignSeq(SequenceI s1, String string1, SequenceI s2,
String string2, String type)
{
- SeqInit(s1, string1.toUpperCase(), s2, string2.toUpperCase(), type);
+ seqInit(s1, string1.toUpperCase(), s2, string2.toUpperCase(), type);
}
/**
*
* @return DOCUMENT ME!
*/
- public int getMaxScore()
+ public float getMaxScore()
{
return maxscore;
}
}
/**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public SequenceI getS1()
- {
- return s1;
- }
-
- /**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public SequenceI getS2()
- {
- return s2;
- }
-
- /**
*
* @return aligned instance of Seq 1
*/
* @param type
* DNA or PEPTIDE
*/
- public void SeqInit(SequenceI s1, String string1, SequenceI s2,
+ public void seqInit(SequenceI s1, String string1, SequenceI s2,
String string2, String type)
{
this.s1 = s1;
this.s2 = s2;
setDefaultParams(type);
- SeqInit(string1, string2);
- }
-
- /**
- * Construct score matrix for sequences with custom substitution matrix
- *
- * @param s1
- * - sequence 1
- * @param string1
- * - string to use for s1
- * @param s2
- * - sequence 2
- * @param string2
- * - string to use for s2
- * @param scoreMatrix
- * - substitution matrix to use for alignment
- */
- public void SeqInit(SequenceI s1, String string1, SequenceI s2,
- String string2, ScoreMatrix scoreMatrix)
- {
- this.s1 = s1;
- this.s2 = s2;
- setType(scoreMatrix.isDNA() ? AlignSeq.DNA : AlignSeq.PEP);
- lookup = scoreMatrix.getMatrix();
+ seqInit(string1, string2);
}
/**
* @param string1
* @param string2
*/
- private void SeqInit(String string1, String string2)
+ private void seqInit(String string1, String string2)
{
s1str = extractGaps(jalview.util.Comparison.GapChars, string1);
s2str = extractGaps(jalview.util.Comparison.GapChars, string2);
return;
}
- // System.out.println("lookuip " + rt.freeMemory() + " "+ rt.totalMemory());
- seq1 = new int[s1str.length()];
-
- // System.out.println("seq1 " + rt.freeMemory() +" " + rt.totalMemory());
- seq2 = new int[s2str.length()];
-
- // System.out.println("seq2 " + rt.freeMemory() + " " + rt.totalMemory());
- score = new int[s1str.length()][s2str.length()];
+ score = new float[s1str.length()][s2str.length()];
- // System.out.println("score " + rt.freeMemory() + " " + rt.totalMemory());
- E = new int[s1str.length()][s2str.length()];
+ E = new float[s1str.length()][s2str.length()];
- // System.out.println("E " + rt.freeMemory() + " " + rt.totalMemory());
- F = new int[s1str.length()][s2str.length()];
+ F = new float[s1str.length()][s2str.length()];
traceback = new int[s1str.length()][s2str.length()];
- // System.out.println("F " + rt.freeMemory() + " " + rt.totalMemory());
- seq1 = stringToInt(s1str, type);
-
- // System.out.println("seq1 " + rt.freeMemory() + " " + rt.totalMemory());
- seq2 = stringToInt(s2str, type);
-
- // System.out.println("Seq2 " + rt.freeMemory() + " " + rt.totalMemory());
- // long tstart = System.currentTimeMillis();
- // calcScoreMatrix();
- // long tend = System.currentTimeMillis();
- // System.out.println("Time take to calculate score matrix = " +
- // (tend-tstart) + " ms");
- // printScoreMatrix(score);
- // System.out.println();
- // printScoreMatrix(traceback);
- // System.out.println();
- // printScoreMatrix(E);
- // System.out.println();
- // /printScoreMatrix(F);
- // System.out.println();
- // tstart = System.currentTimeMillis();
- // traceAlignment();
- // tend = System.currentTimeMillis();
- // System.out.println("Time take to traceback alignment = " + (tend-tstart)
- // + " ms");
- }
-
- private void setDefaultParams(String type)
- {
- setType(type);
+ seq1 = indexEncode(s1str);
- if (type.equals(AlignSeq.PEP))
- {
- lookup = ResidueProperties.getDefaultPeptideMatrix();
- }
- else if (type.equals(AlignSeq.DNA))
- {
- lookup = ResidueProperties.getDefaultDnaMatrix();
- }
+ seq2 = indexEncode(s2str);
}
- private void setType(String type2)
+ private void setDefaultParams(String moleculeType)
{
- this.type = type2;
- if (type.equals(AlignSeq.PEP))
- {
- intToStr = pep;
- charToInt = ResidueProperties.aaIndex;
- defInt = ResidueProperties.maxProteinIndex;
- }
- else if (type.equals(AlignSeq.DNA))
- {
- intToStr = dna;
- charToInt = ResidueProperties.nucleotideIndex;
- defInt = ResidueProperties.maxNucleotideIndex;
- }
- else
+ if (!PEP.equals(moleculeType) && !DNA.equals(moleculeType))
{
output.append("Wrong type = dna or pep only");
throw new Error(MessageManager.formatMessage(
- "error.unknown_type_dna_or_pep", new String[] { type2 }));
+ "error.unknown_type_dna_or_pep",
+ new String[] { moleculeType }));
}
+
+ type = moleculeType;
+ scoreMatrix = ScoreModels.getInstance().getDefaultModel(
+ PEP.equals(type));
}
/**
public void traceAlignment()
{
// Find the maximum score along the rhs or bottom row
- int max = -9999;
+ float max = -Float.MAX_VALUE;
for (int i = 0; i < seq1.length; i++)
{
aseq1 = new int[seq1.length + seq2.length];
aseq2 = new int[seq1.length + seq2.length];
+ StringBuilder sb1 = new StringBuilder(aseq1.length);
+ StringBuilder sb2 = new StringBuilder(aseq2.length);
+
count = (seq1.length + seq2.length) - 1;
- while ((i > 0) && (j > 0))
+ while (i > 0 && j > 0)
{
- if ((aseq1[count] != defInt) && (i >= 0))
- {
- aseq1[count] = seq1[i];
- astr1 = s1str.charAt(i) + astr1;
- }
-
- if ((aseq2[count] != defInt) && (j > 0))
- {
- aseq2[count] = seq2[j];
- astr2 = s2str.charAt(j) + astr2;
- }
+ aseq1[count] = seq1[i];
+ sb1.append(s1str.charAt(i));
+ aseq2[count] = seq2[j];
+ sb2.append(s2str.charAt(j));
trace = findTrace(i, j);
else if (trace == 1)
{
j--;
- aseq1[count] = defInt;
- astr1 = "-" + astr1.substring(1);
+ aseq1[count] = GAP_INDEX;
+ sb1.replace(sb1.length() - 1, sb1.length(), "-");
}
else if (trace == -1)
{
i--;
- aseq2[count] = defInt;
- astr2 = "-" + astr2.substring(1);
+ aseq2[count] = GAP_INDEX;
+ sb2.replace(sb2.length() - 1, sb2.length(), "-");
}
count--;
seq1start = i + 1;
seq2start = j + 1;
- if (aseq1[count] != defInt)
+ if (aseq1[count] != GAP_INDEX)
{
aseq1[count] = seq1[i];
- astr1 = s1str.charAt(i) + astr1;
+ sb1.append(s1str.charAt(i));
}
- if (aseq2[count] != defInt)
+ if (aseq2[count] != GAP_INDEX)
{
aseq2[count] = seq2[j];
- astr2 = s2str.charAt(j) + astr2;
+ sb2.append(s2str.charAt(j));
}
+
+ /*
+ * we built the character strings backwards, so now
+ * reverse them to convert to sequence strings
+ */
+ astr1 = sb1.reverse().toString();
+ astr2 = sb2.reverse().toString();
}
/**
.append(String.valueOf(s2str.length())).append(")")
.append(NEWLINE).append(NEWLINE);
+ ScoreMatrix pam250 = ScoreModels.getInstance().getPam250();
+
for (int j = 0; j < nochunks; j++)
{
// Print the first aligned sequence
output.append(NEWLINE);
output.append(new Format("%" + (maxid) + "s").form(" ")).append(" ");
- // Print out the matching chars
+ /*
+ * Print out the match symbols:
+ * | for exact match (ignoring case)
+ * . if PAM250 score is positive
+ * else a space
+ */
for (int i = 0; i < len; i++)
{
if ((i + (j * len)) < astr1.length())
{
- boolean sameChar = Comparison.isSameResidue(
- astr1.charAt(i + (j * len)), astr2.charAt(i + (j * len)),
- false);
- if (sameChar
- && !jalview.util.Comparison.isGap(astr1.charAt(i
- + (j * len))))
+ char c1 = astr1.charAt(i + (j * len));
+ char c2 = astr2.charAt(i + (j * len));
+ boolean sameChar = Comparison.isSameResidue(c1, c2, false);
+ if (sameChar && !Comparison.isGap(c1))
{
pid++;
output.append("|");
}
else if (type.equals("pep"))
{
- if (ResidueProperties.getPAM250(astr1.charAt(i + (j * len)),
- astr2.charAt(i + (j * len))) > 0)
+ if (pam250.getPairwiseScore(c1, c2) > 0)
{
output.append(".");
}
/**
* DOCUMENT ME!
*
- * @param mat
- * DOCUMENT ME!
- */
- public void printScoreMatrix(int[][] mat)
- {
- int n = seq1.length;
- int m = seq2.length;
-
- for (int i = 0; i < n; i++)
- {
- // Print the top sequence
- if (i == 0)
- {
- Format.print(System.out, "%8s", s2str.substring(0, 1));
-
- for (int jj = 1; jj < m; jj++)
- {
- Format.print(System.out, "%5s", s2str.substring(jj, jj + 1));
- }
-
- System.out.println();
- }
-
- for (int j = 0; j < m; j++)
- {
- if (j == 0)
- {
- Format.print(System.out, "%3s", s1str.substring(i, i + 1));
- }
-
- Format.print(System.out, "%3d ", mat[i][j] / 10);
- }
-
- System.out.println();
- }
- }
-
- /**
- * DOCUMENT ME!
- *
* @param i
* DOCUMENT ME!
* @param j
public int findTrace(int i, int j)
{
int t = 0;
- int max = score[i - 1][j - 1] + (lookup[seq1[i]][seq2[j]] * 10);
+ // float pairwiseScore = lookup[seq1[i]][seq2[j]];
+ float pairwiseScore = scoreMatrix.getPairwiseScore(s1str.charAt(i),
+ s2str.charAt(j));
+ float max = score[i - 1][j - 1] + (pairwiseScore * 10);
if (F[i][j] > max)
{
int m = seq2.length;
// top left hand element
- score[0][0] = lookup[seq1[0]][seq2[0]] * 10;
+ score[0][0] = scoreMatrix.getPairwiseScore(s1str.charAt(0),
+ s2str.charAt(0)) * 10;
E[0][0] = -gapExtend;
F[0][0] = 0;
E[0][j] = max(score[0][j - 1] - gapOpen, E[0][j - 1] - gapExtend);
F[0][j] = -gapExtend;
- score[0][j] = max(lookup[seq1[0]][seq2[j]] * 10, -gapOpen, -gapExtend);
+ float pairwiseScore = scoreMatrix.getPairwiseScore(s1str.charAt(0),
+ s2str.charAt(j));
+ score[0][j] = max(pairwiseScore * 10, -gapOpen, -gapExtend);
traceback[0][j] = 1;
}
E[i][0] = -gapOpen;
F[i][0] = max(score[i - 1][0] - gapOpen, F[i - 1][0] - gapExtend);
- score[i][0] = max(lookup[seq1[i]][seq2[0]] * 10, E[i][0], F[i][0]);
+ float pairwiseScore = scoreMatrix.getPairwiseScore(s1str.charAt(i),
+ s2str.charAt(0));
+ score[i][0] = max(pairwiseScore * 10, E[i][0], F[i][0]);
traceback[i][0] = -1;
}
E[i][j] = max(score[i][j - 1] - gapOpen, E[i][j - 1] - gapExtend);
F[i][j] = max(score[i - 1][j] - gapOpen, F[i - 1][j] - gapExtend);
+ float pairwiseScore = scoreMatrix.getPairwiseScore(s1str.charAt(i),
+ s2str.charAt(j));
score[i][j] = max(score[i - 1][j - 1]
- + (lookup[seq1[i]][seq2[j]] * 10), E[i][j], F[i][j]);
+ + (pairwiseScore * 10), E[i][j], F[i][j]);
traceback[i][j] = findTrace(i, j);
}
}
/**
* DOCUMENT ME!
*
- * @param i1
+ * @param f1
* DOCUMENT ME!
- * @param i2
+ * @param f2
* DOCUMENT ME!
- * @param i3
+ * @param f3
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
- public int max(int i1, int i2, int i3)
+ private static float max(float f1, float f2, float f3)
{
- int max = i1;
+ float max = f1;
- if (i2 > i1)
+ if (f2 > f1)
{
- max = i2;
+ max = f2;
}
- if (i3 > max)
+ if (f3 > max)
{
- max = i3;
+ max = f3;
}
return max;
/**
* DOCUMENT ME!
*
- * @param i1
+ * @param f1
* DOCUMENT ME!
- * @param i2
+ * @param f2
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
- public int max(int i1, int i2)
+ private static float max(float f1, float f2)
{
- int max = i1;
+ float max = f1;
- if (i2 > i1)
+ if (f2 > f1)
{
- max = i2;
+ max = f2;
}
return max;
}
/**
- * DOCUMENT ME!
+ * Converts the character string to an array of integers which are the
+ * corresponding indices to the characters in the score matrix
*
* @param s
- * DOCUMENT ME!
- * @param type
- * DOCUMENT ME!
*
- * @return DOCUMENT ME!
+ * @return
*/
- public int[] stringToInt(String s, String type)
+ int[] indexEncode(String s)
{
- int[] seq1 = new int[s.length()];
+ int[] encoded = new int[s.length()];
for (int i = 0; i < s.length(); i++)
{
- // String ss = s.substring(i, i + 1).toUpperCase();
char c = s.charAt(i);
- if ('a' <= c && c <= 'z')
- {
- // TO UPPERCASE !!!
- c -= ('a' - 'A');
- }
-
- try
- {
- seq1[i] = charToInt[c]; // set accordingly from setType
- if (seq1[i] < 0 || seq1[i] > defInt) // set from setType: 23 for
- // peptides, or 4 for NA.
- {
- seq1[i] = defInt;
- }
-
- } catch (Exception e)
- {
- seq1[i] = defInt;
- }
+ encoded[i] = scoreMatrix.getMatrixIndex(c);
}
- return seq1;
+ return encoded;
}
/**
public static void displayMatrix(Graphics g, int[][] mat, int n, int m,
int psize)
{
- // TODO method dosen't seem to be referenced anywhere delete??
+ // TODO method doesn't seem to be referenced anywhere delete??
int max = -1000;
int min = 1000;
{
SequenceI bestm = null;
AlignSeq bestaseq = null;
- int bestscore = 0;
+ float bestscore = 0;
for (SequenceI msq : al.getSequences())
{
AlignSeq aseq = doGlobalNWAlignment(msq, sq, dnaOrProtein);
bestm = msq;
}
}
- System.out.println("Best Score for " + (matches.size() + 1) + " :"
- + bestscore);
+ // System.out.println("Best Score for " + (matches.size() + 1) + " :"
+ // + bestscore);
matches.add(bestm);
aligns.add(bestaseq);
al.deleteSequence(bestm);
// long start = System.currentTimeMillis();
+ SimilarityParams pidParams = new SimilarityParams(true, true, true,
+ true);
float pid;
String seqi, seqj;
for (int i = 0; i < height; i++)
seqj = ug;
}
}
- pid = Comparison.PID(seqi, seqj);
+ pid = (float) PIDModel.computePID(seqi, seqj, pidParams);
// use real sequence length rather than string length
if (lngth[j] < lngth[i])
*/
package jalview.analysis;
+import jalview.analysis.scoremodels.PIDModel;
+import jalview.analysis.scoremodels.SimilarityParams;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentOrder;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.datamodel.SequenceNode;
-import jalview.util.Comparison;
import jalview.util.MessageManager;
import jalview.util.QuickSort;
static boolean sortOrderAscending = true;
- static NJTree lastTree = null;
+ static TreeModel lastTree = null;
static boolean sortTreeAscending = true;
private static boolean sortLengthAscending;
/**
- * Sort by Percentage Identity w.r.t. s
+ * Sorts sequences in the alignment by Percentage Identity with the given
+ * reference sequence, sorting the highest identity to the top
*
* @param align
* AlignmentI
* @param s
* SequenceI
- * @param tosort
- * sequences from align that are to be sorted.
- */
- public static void sortByPID(AlignmentI align, SequenceI s,
- SequenceI[] tosort)
- {
- sortByPID(align, s, tosort, 0, -1);
- }
-
- /**
- * Sort by Percentage Identity w.r.t. s
- *
- * @param align
- * AlignmentI
- * @param s
- * SequenceI
- * @param tosort
- * sequences from align that are to be sorted.
- * @param start
- * start column (0 for beginning
* @param end
*/
- public static void sortByPID(AlignmentI align, SequenceI s,
- SequenceI[] tosort, int start, int end)
+ public static void sortByPID(AlignmentI align, SequenceI s)
{
int nSeq = align.getHeight();
float[] scores = new float[nSeq];
SequenceI[] seqs = new SequenceI[nSeq];
+ String refSeq = s.getSequenceAsString();
+ SimilarityParams pidParams = new SimilarityParams(true, true, true,
+ true);
for (int i = 0; i < nSeq; i++)
{
- scores[i] = Comparison.PID(align.getSequenceAt(i)
- .getSequenceAsString(), s.getSequenceAsString());
+ scores[i] = (float) PIDModel.computePID(align.getSequenceAt(i)
+ .getSequenceAsString(), refSeq, pidParams);
seqs[i] = align.getSequenceAt(i);
}
* @return DOCUMENT ME!
*/
private static List<SequenceI> getOrderByTree(AlignmentI align,
- NJTree tree)
+ TreeModel tree)
{
int nSeq = align.getHeight();
* @param tree
* tree which has
*/
- public static void sortByTree(AlignmentI align, NJTree tree)
+ public static void sortByTree(AlignmentI align, TreeModel tree)
{
List<SequenceI> tmp = getOrderByTree(align, tree);
for (int f = 0; f < sf.length; f++)
{
// filter for selection criteria
- if (
- // ignore features outwith alignment start-stop positions.
- (sf[f].end < sstart || sf[f].begin > sstop) ||
- // or ignore based on selection criteria
- (featureLabels != null && !AlignmentSorter
- .containsIgnoreCase(sf[f].type, featureLabels))
- || (groupLabels != null
- // problem here: we cannot eliminate null feature group features
- && (sf[f].getFeatureGroup() != null && !AlignmentSorter
- .containsIgnoreCase(sf[f].getFeatureGroup(),
- groupLabels))))
+ SequenceFeature feature = sf[f];
+
+ /*
+ * double-check feature overlaps columns (JAL-2544)
+ * (could avoid this with a findPositions(fromCol, toCol) method)
+ * findIndex returns base 1 column values, startCol/endCol are base 0
+ */
+ boolean noOverlap = seqs[i].findIndex(feature.getBegin()) > stop + 1
+ || seqs[i].findIndex(feature.getEnd()) < start + 1;
+ boolean skipFeatureType = featureLabels != null
+ && !AlignmentSorter.containsIgnoreCase(feature.type,
+ featureLabels);
+ boolean skipFeatureGroup = groupLabels != null
+ && (feature.getFeatureGroup() != null && !AlignmentSorter
+ .containsIgnoreCase(feature.getFeatureGroup(),
+ groupLabels));
+ if (noOverlap || skipFeatureType || skipFeatureGroup)
{
// forget about this feature
sf[f] = null;
else
{
// or, also take a look at the scores if necessary.
- if (!ignoreScore && !Float.isNaN(sf[f].getScore()))
+ if (!ignoreScore && !Float.isNaN(feature.getScore()))
{
if (seqScores[i] == 0)
{
}
seqScores[i]++;
hasScore[i] = true;
- scores[i] += sf[f].getScore(); // take the first instance of this
+ scores[i] += feature.getScore(); // take the first instance of this
// score.
}
}
import jalview.util.DBRefUtils;
import jalview.util.MapList;
import jalview.util.MappingUtils;
+import jalview.util.RangeComparator;
import jalview.util.StringUtils;
import java.io.UnsupportedEncodingException;
* ranges are assembled in order. Other cases should not use this method,
* but instead construct an explicit mapping for CDS (e.g. EMBL parsing).
*/
- Collections.sort(result, new Comparator<int[]>()
- {
- @Override
- public int compare(int[] o1, int[] o2)
- {
- return Integer.compare(o1[0], o2[0]);
- }
- });
+ Collections.sort(result, new RangeComparator(true));
return result;
}
--- /dev/null
+package jalview.analysis;
+
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityParamsI;
+import jalview.datamodel.SequenceNode;
+import jalview.viewmodel.AlignmentViewport;
+
+/**
+ * This class implements distance calculations used in constructing a Average
+ * Distance tree (also known as UPGMA)
+ */
+public class AverageDistanceTree extends TreeBuilder
+{
+ /**
+ * Constructor
+ *
+ * @param av
+ * @param sm
+ * @param scoreParameters
+ */
+ public AverageDistanceTree(AlignmentViewport av, ScoreModelI sm,
+ SimilarityParamsI scoreParameters)
+ {
+ super(av, sm, scoreParameters);
+ }
+
+ /**
+ * Calculates and saves the distance between the combination of cluster(i) and
+ * cluster(j) and all other clusters. An average of the distances from
+ * cluster(i) and cluster(j) is calculated, weighted by the sizes of each
+ * cluster.
+ *
+ * @param i
+ * @param j
+ */
+ @Override
+ protected void findClusterDistance(int i, int j)
+ {
+ int noi = clusters.elementAt(i).cardinality();
+ int noj = clusters.elementAt(j).cardinality();
+
+ // New distances from cluster i to others
+ double[] newdist = new double[noseqs];
+
+ for (int l = 0; l < noseqs; l++)
+ {
+ if ((l != i) && (l != j))
+ {
+ newdist[l] = ((distances.getValue(i, l) * noi) + (distances
+ .getValue(j, l) * noj)) / (noi + noj);
+ }
+ else
+ {
+ newdist[l] = 0;
+ }
+ }
+
+ for (int ii = 0; ii < noseqs; ii++)
+ {
+ distances.setValue(i, ii, newdist[ii]);
+ distances.setValue(ii, i, newdist[ii]);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected double findMinDistance()
+ {
+ double min = Double.MAX_VALUE;
+
+ for (int i = 0; i < (noseqs - 1); i++)
+ {
+ for (int j = i + 1; j < noseqs; j++)
+ {
+ if (!done.get(i) && !done.get(j))
+ {
+ if (distances.getValue(i, j) < min)
+ {
+ mini = i;
+ minj = j;
+
+ min = distances.getValue(i, j);
+ }
+ }
+ }
+ }
+ return min;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void findNewDistances(SequenceNode nodei, SequenceNode nodej,
+ double dist)
+ {
+ double ih = 0;
+ double jh = 0;
+
+ SequenceNode sni = nodei;
+ SequenceNode snj = nodej;
+
+ while (sni != null)
+ {
+ ih = ih + sni.dist;
+ sni = (SequenceNode) sni.left();
+ }
+
+ while (snj != null)
+ {
+ jh = jh + snj.dist;
+ snj = (SequenceNode) snj.left();
+ }
+
+ nodei.dist = ((dist / 2) - ih);
+ nodej.dist = ((dist / 2) - jh);
+ }
+
+}
*/
package jalview.analysis;
+import jalview.analysis.scoremodels.ScoreMatrix;
+import jalview.analysis.scoremodels.ScoreModels;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.Annotation;
import jalview.datamodel.ResidueCount;
private static final int TOUPPERCASE = 'a' - 'A';
+ private static final int GAP_INDEX = -1;
+
SequenceI[] sequences;
int start;
int end;
- Vector<int[]> seqNums; // vector of int vectors where first is sequence
- // checksum
+ /*
+ * a list whose i'th element is an array whose first entry is the checksum
+ * of the i'th sequence, followed by residues encoded to score matrix index
+ */
+ Vector<int[]> seqNums;
int maxLength = 0; // used by quality calcs
*/
Map<String, Integer>[] total;
- boolean canonicaliseAa = true; // if true then conservation calculation will
-
- // map all symbols to canonical aa numbering
- // rather than consider conservation of that
- // symbol
+ /*
+ * if true then conservation calculation will map all symbols to canonical aa
+ * numbering rather than consider conservation of that symbol
+ */
+ boolean canonicaliseAa = true;
- /** Stores calculated quality values */
private Vector<Double> quality;
- /** Stores maximum and minimum values of quality values */
- private double[] qualityRange = new double[2];
+ private double qualityMinimum;
+
+ private double qualityMaximum;
private Sequence consSequence;
private String name = "";
+ /*
+ * an array, for each column, of counts of symbols (by score matrix index)
+ */
private int[][] cons2;
+ /*
+ * gap counts for each column
+ */
+ private int[] cons2GapCounts;
+
private String[] consSymbs;
/**
}
/**
- * Translate sequence i into a numerical representation and store it in the
- * i'th position of the seqNums array.
+ * Translate sequence i into score matrix indices and store it in the i'th
+ * position of the seqNums array.
*
* @param i
+ * @param sm
*/
- private void calcSeqNum(int i)
+ private void calcSeqNum(int i, ScoreMatrix sm)
{
- String sq = null; // for dumb jbuilder not-inited exception warning
- int[] sqnum = null;
-
int sSize = sequences.length;
if ((i > -1) && (i < sSize))
{
- sq = sequences[i].getSequenceAsString();
+ String sq = sequences[i].getSequenceAsString();
if (seqNums.size() <= i)
{
seqNums.addElement(new int[sq.length() + 1]);
}
+ /*
+ * the first entry in the array is the sequence's hashcode,
+ * following entries are matrix indices of sequence characters
+ */
if (sq.hashCode() != seqNums.elementAt(i)[0])
{
int j;
maxLength = len;
}
- sqnum = new int[len + 1]; // better to always make a new array -
+ int[] sqnum = new int[len + 1]; // better to always make a new array -
// sequence can change its length
sqnum[0] = sq.hashCode();
for (j = 1; j <= len; j++)
{
- sqnum[j] = jalview.schemes.ResidueProperties.aaIndex[sq
- .charAt(j - 1)];
+ // sqnum[j] = ResidueProperties.aaIndex[sq.charAt(j - 1)];
+ char residue = sq.charAt(j - 1);
+ if (Comparison.isGap(residue))
+ {
+ sqnum[j] = GAP_INDEX;
+ }
+ else
+ {
+ sqnum[j] = sm.getMatrixIndex(residue);
+ if (sqnum[j] == -1)
+ {
+ sqnum[j] = GAP_INDEX;
+ }
+ }
}
seqNums.setElementAt(sqnum, i);
// From Alignment.java in jalview118
public void findQuality()
{
- findQuality(0, maxLength - 1);
+ findQuality(0, maxLength - 1, ScoreModels.getInstance().getBlosum62());
}
/**
* DOCUMENT ME!
+ *
+ * @param sm
*/
- private void percentIdentity2()
+ private void percentIdentity(ScoreMatrix sm)
{
seqNums = new Vector<int[]>();
- // calcSeqNum(s);
int i = 0, iSize = sequences.length;
// Do we need to calculate this again?
for (i = 0; i < iSize; i++)
{
- calcSeqNum(i);
+ calcSeqNum(i, sm);
}
if ((cons2 == null) || seqNumsChanged)
{
+ // FIXME remove magic number 24 without changing calc
+ // sm.getSize() returns 25 so doesn't quite do it...
cons2 = new int[maxLength][24];
+ cons2GapCounts = new int[maxLength];
- // Initialize the array
- for (int j = 0; j < 24; j++)
- {
- for (i = 0; i < maxLength; i++)
- {
- cons2[i][j] = 0;
- }
- }
-
- int[] sqnum;
int j = 0;
while (j < sequences.length)
{
- sqnum = seqNums.elementAt(j);
+ int[] sqnum = seqNums.elementAt(j);
for (i = 1; i < sqnum.length; i++)
{
- cons2[i - 1][sqnum[i]]++;
+ int index = sqnum[i];
+ if (index == GAP_INDEX)
+ {
+ cons2GapCounts[i - 1]++;
+ }
+ else
+ {
+ cons2[i - 1][index]++;
+ }
}
+ // TODO should this start from sqnum.length?
for (i = sqnum.length - 1; i < maxLength; i++)
{
- cons2[i][23]++; // gap count
+ cons2GapCounts[i]++;
}
-
j++;
}
-
- // unnecessary ?
-
- /*
- * for (int i=start; i <= end; i++) { int max = -1000; int maxi = -1; int
- * maxj = -1;
- *
- * for (int j=0;j<24;j++) { if (cons2[i][j] > max) { max = cons2[i][j];
- * maxi = i; maxj = j; } } }
- */
}
}
/**
- * Calculates the quality of the set of sequences
+ * Calculates the quality of the set of sequences over the given inclusive
+ * column range, using the specified substitution score matrix
*
- * @param startRes
- * Start residue
- * @param endRes
- * End residue
+ * @param startCol
+ * @param endCol
+ * @param scoreMatrix
*/
- public void findQuality(int startRes, int endRes)
+ protected void findQuality(int startCol, int endCol, ScoreMatrix scoreMatrix)
{
quality = new Vector<Double>();
- double max = -10000;
- int[][] BLOSUM62 = ResidueProperties.getBLOSUM62();
+ double max = -Double.MAX_VALUE;
+ float[][] scores = scoreMatrix.getMatrix();
- // Loop over columns // JBPNote Profiling info
- // long ts = System.currentTimeMillis();
- // long te = System.currentTimeMillis();
- percentIdentity2();
+ percentIdentity(scoreMatrix);
int size = seqNums.size();
int[] lengths = new int[size];
- double tot, bigtot, sr, tmp;
- double[] x, xx;
- int l, j, i, ii, i2, k, seqNum;
- for (l = 0; l < size; l++)
+ for (int l = 0; l < size; l++)
{
lengths[l] = seqNums.elementAt(l).length - 1;
}
- for (j = startRes; j <= endRes; j++)
+ final int symbolCount = scoreMatrix.getSize();
+
+ for (int j = startCol; j <= endCol; j++)
{
- bigtot = 0;
+ double bigtot = 0;
// First Xr = depends on column only
- x = new double[24];
+ double[] x = new double[symbolCount];
- for (ii = 0; ii < 24; ii++)
+ for (int ii = 0; ii < symbolCount; ii++)
{
x[ii] = 0;
- for (i2 = 0; i2 < 24; i2++)
+ /*
+ * todo JAL-728 currently assuming last symbol in matrix is * for gap
+ * (which we ignore as counted separately); true for BLOSUM62 but may
+ * not be once alternative matrices are supported
+ */
+ for (int i2 = 0; i2 < symbolCount - 1; i2++)
{
- x[ii] += (((double) cons2[j][i2] * BLOSUM62[ii][i2]) + 4);
+ x[ii] += (((double) cons2[j][i2] * scores[ii][i2]) + 4D);
}
+ x[ii] += 4D + cons2GapCounts[j] * scoreMatrix.getMinimumScore();
x[ii] /= size;
}
// Now calculate D for each position and sum
- for (k = 0; k < size; k++)
+ for (int k = 0; k < size; k++)
{
- tot = 0;
- xx = new double[24];
- seqNum = (j < lengths[k]) ? seqNums.elementAt(k)[j + 1] : 23; // Sequence,
- // or gap
- // at the
- // end
-
- // This is a loop over r
- for (i = 0; i < 23; i++)
- {
- sr = 0;
+ double tot = 0;
+ double[] xx = new double[symbolCount];
+ // sequence character index, or implied gap if sequence too short
+ int seqNum = (j < lengths[k]) ? seqNums.elementAt(k)[j + 1]
+ : GAP_INDEX;
- sr = (double) BLOSUM62[i][seqNum] + 4;
+ for (int i = 0; i < symbolCount - 1; i++)
+ {
+ double sr = 4D;
+ if (seqNum == GAP_INDEX)
+ {
+ sr += scoreMatrix.getMinimumScore();
+ }
+ else
+ {
+ sr += scores[i][seqNum];
+ }
- // Calculate X with another loop over residues
- // System.out.println("Xi " + i + " " + x[i] + " " + sr);
xx[i] = x[i] - sr;
tot += (xx[i] * xx[i]);
bigtot += Math.sqrt(tot);
}
- // This is the quality for one column
- if (max < bigtot)
- {
- max = bigtot;
- }
+ max = Math.max(max, bigtot);
- // bigtot = bigtot * (size-cons2[j][23])/size;
quality.addElement(new Double(bigtot));
-
- // Need to normalize by gaps
}
- double newmax = -10000;
+ double newmax = -Double.MAX_VALUE;
- for (j = startRes; j <= endRes; j++)
+ for (int j = startCol; j <= endCol; j++)
{
- tmp = quality.elementAt(j).doubleValue();
- tmp = ((max - tmp) * (size - cons2[j][23])) / size;
+ double tmp = quality.elementAt(j).doubleValue();
+ // tmp = ((max - tmp) * (size - cons2[j][23])) / size;
+ tmp = ((max - tmp) * (size - cons2GapCounts[j])) / size;
// System.out.println(tmp+ " " + j);
quality.setElementAt(new Double(tmp), j);
}
}
- // System.out.println("Quality " + s);
- qualityRange[0] = 0D;
- qualityRange[1] = newmax;
+ qualityMinimum = 0D;
+ qualityMaximum = newmax;
}
/**
if (quality2 != null)
{
- quality2.graphMax = (float) qualityRange[1];
+ quality2.graphMax = (float) qualityMaximum;
if (quality2.annotations != null
&& quality2.annotations.length < alWidth)
{
quality2.annotations = new Annotation[alWidth];
}
- qmin = (float) qualityRange[0];
- qmax = (float) qualityRange[1];
+ qmin = (float) qualityMinimum;
+ qmax = (float) qualityMaximum;
}
for (int i = istart; i < alWidth; i++)
package jalview.analysis;
import jalview.api.analysis.ScoreModelI;
-import jalview.datamodel.AlignmentView;
-import jalview.datamodel.BinaryNode;
-import jalview.datamodel.CigarArray;
-import jalview.datamodel.NodeTransformI;
-import jalview.datamodel.SeqCigar;
-import jalview.datamodel.Sequence;
-import jalview.datamodel.SequenceI;
+import jalview.api.analysis.SimilarityParamsI;
import jalview.datamodel.SequenceNode;
-import jalview.io.NewickFile;
-import jalview.schemes.ResidueProperties;
-
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Vector;
+import jalview.viewmodel.AlignmentViewport;
/**
- * DOCUMENT ME!
- *
- * @author $author$
- * @version $Revision$
+ * This class implements distance calculations used in constructing a Neighbour
+ * Joining tree
*/
-public class NJTree
+public class NJTree extends TreeBuilder
{
- Vector<Cluster> cluster;
-
- SequenceI[] sequence;
-
- // SequenceData is a string representation of what the user
- // sees. The display may contain hidden columns.
- public AlignmentView seqData = null;
-
- int[] done;
-
- int noseqs;
-
- int noClus;
-
- float[][] distance;
-
- int mini;
-
- int minj;
-
- float ri;
-
- float rj;
-
- Vector<SequenceNode> groups = new Vector<SequenceNode>();
-
- SequenceNode maxdist;
-
- SequenceNode top;
-
- float maxDistValue;
-
- float maxheight;
-
- int ycount;
-
- Vector<SequenceNode> node;
-
- String type;
-
- String pwtype;
-
- Object found = null;
-
- boolean hasDistances = true; // normal case for jalview trees
-
- boolean hasBootstrap = false; // normal case for jalview trees
-
- private boolean hasRootDistance = true;
-
- /**
- * Create a new NJTree object with leaves associated with sequences in seqs,
- * and original alignment data represented by Cigar strings.
- *
- * @param seqs
- * SequenceI[]
- * @param odata
- * Cigar[]
- * @param treefile
- * NewickFile
- */
- public NJTree(SequenceI[] seqs, AlignmentView odata, NewickFile treefile)
- {
- this(seqs, treefile);
- if (odata != null)
- {
- seqData = odata;
- }
- /*
- * sequenceString = new String[odata.length]; char gapChar =
- * jalview.util.Comparison.GapChars.charAt(0); for (int i = 0; i <
- * odata.length; i++) { SequenceI oseq_aligned = odata[i].getSeq(gapChar);
- * sequenceString[i] = oseq_aligned.getSequence(); }
- */
- }
-
- /**
- * Creates a new NJTree object from a tree from an external source
- *
- * @param seqs
- * SequenceI which should be associated with leafs of treefile
- * @param treefile
- * A parsed tree
- */
- public NJTree(SequenceI[] seqs, NewickFile treefile)
- {
- this.sequence = seqs;
- top = treefile.getTree();
-
- /**
- * There is no dependent alignment to be recovered from an imported tree.
- *
- * if (sequenceString == null) { sequenceString = new String[seqs.length];
- * for (int i = 0; i < seqs.length; i++) { sequenceString[i] =
- * seqs[i].getSequence(); } }
- */
-
- hasDistances = treefile.HasDistances();
- hasBootstrap = treefile.HasBootstrap();
- hasRootDistance = treefile.HasRootDistance();
-
- maxheight = findHeight(top);
-
- SequenceIdMatcher algnIds = new SequenceIdMatcher(seqs);
-
- Vector<SequenceNode> leaves = findLeaves(top);
-
- int i = 0;
- int namesleft = seqs.length;
-
- SequenceNode j;
- SequenceI nam;
- String realnam;
- Vector<SequenceI> one2many = new Vector<SequenceI>();
- int countOne2Many = 0;
- while (i < leaves.size())
- {
- j = leaves.elementAt(i++);
- realnam = j.getName();
- nam = null;
-
- if (namesleft > -1)
- {
- nam = algnIds.findIdMatch(realnam);
- }
-
- if (nam != null)
- {
- j.setElement(nam);
- if (one2many.contains(nam))
- {
- countOne2Many++;
- // if (jalview.bin.Cache.log.isDebugEnabled())
- // jalview.bin.Cache.log.debug("One 2 many relationship for
- // "+nam.getName());
- }
- else
- {
- one2many.addElement(nam);
- namesleft--;
- }
- }
- else
- {
- j.setElement(new Sequence(realnam, "THISISAPLACEHLDER"));
- j.setPlaceholder(true);
- }
- }
- // if (jalview.bin.Cache.log.isDebugEnabled() && countOne2Many>0) {
- // jalview.bin.Cache.log.debug("There were "+countOne2Many+" alignment
- // sequence ids (out of "+one2many.size()+" unique ids) linked to two or
- // more leaves.");
- // }
- // one2many.clear();
- }
-
/**
- * Creates a new NJTree object.
+ * Constructor given a viewport, tree type and score model
*
- * @param sequence
- * DOCUMENT ME!
- * @param type
- * DOCUMENT ME!
- * @param pwtype
- * DOCUMENT ME!
- * @param start
- * DOCUMENT ME!
- * @param end
- * DOCUMENT ME!
+ * @param av
+ * the current alignment viewport
+ * @param sm
+ * a distance or similarity score model to use to compute the tree
+ * @param scoreParameters
*/
- public NJTree(SequenceI[] sequence, AlignmentView seqData, String type,
- String pwtype, ScoreModelI sm, int start, int end)
+ public NJTree(AlignmentViewport av, ScoreModelI sm,
+ SimilarityParamsI scoreParameters)
{
- this.sequence = sequence;
- this.node = new Vector<SequenceNode>();
- this.type = type;
- this.pwtype = pwtype;
- if (seqData != null)
- {
- this.seqData = seqData;
- }
- else
- {
- SeqCigar[] seqs = new SeqCigar[sequence.length];
- for (int i = 0; i < sequence.length; i++)
- {
- seqs[i] = new SeqCigar(sequence[i], start, end);
- }
- CigarArray sdata = new CigarArray(seqs);
- sdata.addOperation(CigarArray.M, end - start + 1);
- this.seqData = new AlignmentView(sdata, start);
- }
- // System.err.println("Made seqData");// dbg
- if (!(type.equals("NJ")))
- {
- type = "AV";
- }
-
- if (sm == null && !(pwtype.equals("PID")))
- {
- if (ResidueProperties.getScoreMatrix(pwtype) == null)
- {
- pwtype = "BLOSUM62";
- }
- }
-
- int i = 0;
-
- done = new int[sequence.length];
-
- while ((i < sequence.length) && (sequence[i] != null))
- {
- done[i] = 0;
- i++;
- }
-
- noseqs = i++;
-
- distance = findDistances(sm);
- // System.err.println("Made distances");// dbg
- makeLeaves();
- // System.err.println("Made leaves");// dbg
-
- noClus = cluster.size();
-
- cluster();
- // System.err.println("Made clusters");// dbg
-
+ super(av, sm, scoreParameters);
}
/**
- * Generate a string representation of the Tree
- *
- * @return Newick File with all tree data available
+ * {@inheritDoc}
*/
@Override
- public String toString()
- {
- jalview.io.NewickFile fout = new jalview.io.NewickFile(getTopNode());
-
- return fout.print(isHasBootstrap(), isHasDistances(),
- isHasRootDistance()); // output all data available for tree
- }
-
- /**
- *
- * used when the alignment associated to a tree has changed.
- *
- * @param list
- * Sequence set to be associated with tree nodes
- */
- public void UpdatePlaceHolders(List<SequenceI> list)
+ protected double findMinDistance()
{
- Vector<SequenceNode> leaves = findLeaves(top);
+ double min = Double.MAX_VALUE;
- int sz = leaves.size();
- SequenceIdMatcher seqmatcher = null;
- int i = 0;
-
- while (i < sz)
+ for (int i = 0; i < (noseqs - 1); i++)
{
- SequenceNode leaf = leaves.elementAt(i++);
-
- if (list.contains(leaf.element()))
- {
- leaf.setPlaceholder(false);
- }
- else
+ for (int j = i + 1; j < noseqs; j++)
{
- if (seqmatcher == null)
+ if (!done.get(i) && !done.get(j))
{
- // Only create this the first time we need it
- SequenceI[] seqs = new SequenceI[list.size()];
+ double tmp = distances.getValue(i, j)
+ - (findr(i, j) + findr(j, i));
- for (int j = 0; j < seqs.length; j++)
+ if (tmp < min)
{
- seqs[j] = list.get(j);
- }
-
- seqmatcher = new SequenceIdMatcher(seqs);
- }
-
- SequenceI nam = seqmatcher.findIdMatch(leaf.getName());
+ mini = i;
+ minj = j;
- if (nam != null)
- {
- if (!leaf.isPlaceholder())
- {
- // remapping the node to a new sequenceI - should remove any refs to
- // old one.
- // TODO - make many sequenceI to one leaf mappings possible!
- // (JBPNote)
- }
- leaf.setPlaceholder(false);
- leaf.setElement(nam);
- }
- else
- {
- if (!leaf.isPlaceholder())
- {
- // Construct a new placeholder sequence object for this leaf
- leaf.setElement(new Sequence(leaf.getName(),
- "THISISAPLACEHLDER"));
+ min = tmp;
}
- leaf.setPlaceholder(true);
-
- }
- }
- }
- }
-
- /**
- * rename any nodes according to their associated sequence. This will modify
- * the tree's metadata! (ie the original NewickFile or newly generated
- * BinaryTree's label data)
- */
- public void renameAssociatedNodes()
- {
- applyToNodes(new NodeTransformI()
- {
-
- @Override
- public void transform(BinaryNode nd)
- {
- Object el = nd.element();
- if (el != null && el instanceof SequenceI)
- {
- nd.setName(((SequenceI) el).getName());
}
}
- });
- }
-
- /**
- * DOCUMENT ME!
- */
- public void cluster()
- {
- while (noClus > 2)
- {
- if (type.equals("NJ"))
- {
- findMinNJDistance();
- }
- else
- {
- findMinDistance();
- }
-
- Cluster c = joinClusters(mini, minj);
-
- done[minj] = 1;
-
- cluster.setElementAt(null, minj);
- cluster.setElementAt(c, mini);
-
- noClus--;
- }
-
- boolean onefound = false;
-
- int one = -1;
- int two = -1;
-
- for (int i = 0; i < noseqs; i++)
- {
- if (done[i] != 1)
- {
- if (onefound == false)
- {
- two = i;
- onefound = true;
- }
- else
- {
- one = i;
- }
- }
- }
-
- joinClusters(one, two);
- top = (node.elementAt(one));
-
- reCount(top);
- findHeight(top);
- findMaxDist(top);
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param i
- * DOCUMENT ME!
- * @param j
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public Cluster joinClusters(int i, int j)
- {
- float dist = distance[i][j];
-
- int noi = cluster.elementAt(i).value.length;
- int noj = cluster.elementAt(j).value.length;
-
- int[] value = new int[noi + noj];
-
- for (int ii = 0; ii < noi; ii++)
- {
- value[ii] = cluster.elementAt(i).value[ii];
- }
-
- for (int ii = noi; ii < (noi + noj); ii++)
- {
- value[ii] = cluster.elementAt(j).value[ii - noi];
- }
-
- Cluster c = new Cluster(value);
-
- ri = findr(i, j);
- rj = findr(j, i);
-
- if (type.equals("NJ"))
- {
- findClusterNJDistance(i, j);
- }
- else
- {
- findClusterDistance(i, j);
- }
-
- SequenceNode sn = new SequenceNode();
-
- sn.setLeft((node.elementAt(i)));
- sn.setRight((node.elementAt(j)));
-
- SequenceNode tmpi = (node.elementAt(i));
- SequenceNode tmpj = (node.elementAt(j));
-
- if (type.equals("NJ"))
- {
- findNewNJDistances(tmpi, tmpj, dist);
- }
- else
- {
- findNewDistances(tmpi, tmpj, dist);
- }
-
- tmpi.setParent(sn);
- tmpj.setParent(sn);
-
- node.setElementAt(sn, i);
-
- return c;
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param tmpi
- * DOCUMENT ME!
- * @param tmpj
- * DOCUMENT ME!
- * @param dist
- * DOCUMENT ME!
- */
- public void findNewNJDistances(SequenceNode tmpi, SequenceNode tmpj,
- float dist)
- {
-
- tmpi.dist = ((dist + ri) - rj) / 2;
- tmpj.dist = (dist - tmpi.dist);
-
- if (tmpi.dist < 0)
- {
- tmpi.dist = 0;
- }
-
- if (tmpj.dist < 0)
- {
- tmpj.dist = 0;
- }
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param tmpi
- * DOCUMENT ME!
- * @param tmpj
- * DOCUMENT ME!
- * @param dist
- * DOCUMENT ME!
- */
- public void findNewDistances(SequenceNode tmpi, SequenceNode tmpj,
- float dist)
- {
- float ih = 0;
- float jh = 0;
-
- SequenceNode sni = tmpi;
- SequenceNode snj = tmpj;
-
- while (sni != null)
- {
- ih = ih + sni.dist;
- sni = (SequenceNode) sni.left();
- }
-
- while (snj != null)
- {
- jh = jh + snj.dist;
- snj = (SequenceNode) snj.left();
}
- tmpi.dist = ((dist / 2) - ih);
- tmpj.dist = ((dist / 2) - jh);
+ return min;
}
/**
- * DOCUMENT ME!
- *
- * @param i
- * DOCUMENT ME!
- * @param j
- * DOCUMENT ME!
+ * {@inheritDoc}
*/
- public void findClusterDistance(int i, int j)
+ @Override
+ protected void findNewDistances(SequenceNode nodei, SequenceNode nodej,
+ double dist)
{
- int noi = cluster.elementAt(i).value.length;
- int noj = cluster.elementAt(j).value.length;
+ nodei.dist = ((dist + ri) - rj) / 2;
+ nodej.dist = (dist - nodei.dist);
- // New distances from cluster to others
- float[] newdist = new float[noseqs];
-
- for (int l = 0; l < noseqs; l++)
+ if (nodei.dist < 0)
{
- if ((l != i) && (l != j))
- {
- newdist[l] = ((distance[i][l] * noi) + (distance[j][l] * noj))
- / (noi + noj);
- }
- else
- {
- newdist[l] = 0;
- }
+ nodei.dist = 0;
}
- for (int ii = 0; ii < noseqs; ii++)
+ if (nodej.dist < 0)
{
- distance[i][ii] = newdist[ii];
- distance[ii][i] = newdist[ii];
+ nodej.dist = 0;
}
}
/**
- * DOCUMENT ME!
+ * Calculates and saves the distance between the combination of cluster(i) and
+ * cluster(j) and all other clusters. The new distance to cluster k is
+ * calculated as the average of the distances from i to k and from j to k,
+ * less half the distance from i to j.
*
* @param i
- * DOCUMENT ME!
* @param j
- * DOCUMENT ME!
*/
- public void findClusterNJDistance(int i, int j)
+ @Override
+ protected
+ void findClusterDistance(int i, int j)
{
-
- // New distances from cluster to others
- float[] newdist = new float[noseqs];
-
+ // New distances from cluster i to others
+ double[] newdist = new double[noseqs];
+
+ double ijDistance = distances.getValue(i, j);
for (int l = 0; l < noseqs; l++)
{
if ((l != i) && (l != j))
{
- newdist[l] = ((distance[i][l] + distance[j][l]) - distance[i][j]) / 2;
+ newdist[l] = (distances.getValue(i, l) + distances.getValue(j, l) - ijDistance) / 2;
}
else
{
newdist[l] = 0;
}
}
-
+
for (int ii = 0; ii < noseqs; ii++)
{
- distance[i][ii] = newdist[ii];
- distance[ii][i] = newdist[ii];
- }
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param i
- * DOCUMENT ME!
- * @param j
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public float findr(int i, int j)
- {
- float tmp = 1;
-
- for (int k = 0; k < noseqs; k++)
- {
- if ((k != i) && (k != j) && (done[k] != 1))
- {
- tmp = tmp + distance[i][k];
- }
- }
-
- if (noClus > 2)
- {
- tmp = tmp / (noClus - 2);
+ distances.setValue(i, ii, newdist[ii]);
+ distances.setValue(ii, i, newdist[ii]);
}
-
- return tmp;
- }
-
- /**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public float findMinNJDistance()
- {
- float min = 100000;
-
- for (int i = 0; i < (noseqs - 1); i++)
- {
- for (int j = i + 1; j < noseqs; j++)
- {
- if ((done[i] != 1) && (done[j] != 1))
- {
- float tmp = distance[i][j] - (findr(i, j) + findr(j, i));
-
- if (tmp < min)
- {
- mini = i;
- minj = j;
-
- min = tmp;
- }
- }
- }
- }
-
- return min;
- }
-
- /**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public float findMinDistance()
- {
- float min = 100000;
-
- for (int i = 0; i < (noseqs - 1); i++)
- {
- for (int j = i + 1; j < noseqs; j++)
- {
- if ((done[i] != 1) && (done[j] != 1))
- {
- if (distance[i][j] < min)
- {
- mini = i;
- minj = j;
-
- min = distance[i][j];
- }
- }
- }
- }
-
- return min;
- }
-
- /**
- * Calculate a distance matrix given the sequence input data and score model
- *
- * @return similarity matrix used to compute tree
- */
- public float[][] findDistances(ScoreModelI _pwmatrix)
- {
-
- float[][] dist = new float[noseqs][noseqs];
- if (_pwmatrix == null)
- {
- // Resolve substitution model
- _pwmatrix = ResidueProperties.getScoreModel(pwtype);
- if (_pwmatrix == null)
- {
- _pwmatrix = ResidueProperties.getScoreMatrix("BLOSUM62");
- }
- }
- dist = _pwmatrix.findDistances(seqData);
- return dist;
-
- }
-
- /**
- * DOCUMENT ME!
- */
- public void makeLeaves()
- {
- cluster = new Vector<Cluster>();
-
- for (int i = 0; i < noseqs; i++)
- {
- SequenceNode sn = new SequenceNode();
-
- sn.setElement(sequence[i]);
- sn.setName(sequence[i].getName());
- node.addElement(sn);
-
- int[] value = new int[1];
- value[0] = i;
-
- Cluster c = new Cluster(value);
- cluster.addElement(c);
- }
- }
-
- /**
- * Search for leaf nodes below (or at) the given node
- *
- * @param nd
- * root node to search from
- *
- * @return
- */
- public Vector<SequenceNode> findLeaves(SequenceNode nd)
- {
- Vector<SequenceNode> leaves = new Vector<SequenceNode>();
- findLeaves(nd, leaves);
- return leaves;
- }
-
- /**
- * Search for leaf nodes.
- *
- * @param nd
- * root node to search from
- * @param leaves
- * Vector of leaves to add leaf node objects too.
- *
- * @return Vector of leaf nodes on binary tree
- */
- Vector<SequenceNode> findLeaves(SequenceNode nd,
- Vector<SequenceNode> leaves)
- {
- if (nd == null)
- {
- return leaves;
- }
-
- if ((nd.left() == null) && (nd.right() == null)) // Interior node
- // detection
- {
- leaves.addElement(nd);
-
- return leaves;
- }
- else
- {
- /*
- * TODO: Identify internal nodes... if (node.isSequenceLabel()) {
- * leaves.addElement(node); }
- */
- findLeaves((SequenceNode) nd.left(), leaves);
- findLeaves((SequenceNode) nd.right(), leaves);
- }
-
- return leaves;
- }
-
- /**
- * Find the leaf node with a particular ycount
- *
- * @param nd
- * initial point on tree to search from
- * @param count
- * value to search for
- *
- * @return null or the node with ycound=count
- */
- public Object findLeaf(SequenceNode nd, int count)
- {
- found = _findLeaf(nd, count);
-
- return found;
- }
-
- /*
- * #see findLeaf(SequenceNode node, count)
- */
- public Object _findLeaf(SequenceNode nd, int count)
- {
- if (nd == null)
- {
- return null;
- }
-
- if (nd.ycount == count)
- {
- found = nd.element();
-
- return found;
- }
- else
- {
- _findLeaf((SequenceNode) nd.left(), count);
- _findLeaf((SequenceNode) nd.right(), count);
- }
-
- return found;
- }
-
- /**
- * printNode is mainly for debugging purposes.
- *
- * @param nd
- * SequenceNode
- */
- public void printNode(SequenceNode nd)
- {
- if (nd == null)
- {
- return;
- }
-
- if ((nd.left() == null) && (nd.right() == null))
- {
- System.out.println("Leaf = " + ((SequenceI) nd.element()).getName());
- System.out.println("Dist " + nd.dist);
- System.out.println("Boot " + nd.getBootstrap());
- }
- else
- {
- System.out.println("Dist " + nd.dist);
- printNode((SequenceNode) nd.left());
- printNode((SequenceNode) nd.right());
- }
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param nd
- * DOCUMENT ME!
- */
- public void findMaxDist(SequenceNode nd)
- {
- if (nd == null)
- {
- return;
- }
-
- if ((nd.left() == null) && (nd.right() == null))
- {
- float dist = nd.dist;
-
- if (dist > maxDistValue)
- {
- maxdist = nd;
- maxDistValue = dist;
- }
- }
- else
- {
- findMaxDist((SequenceNode) nd.left());
- findMaxDist((SequenceNode) nd.right());
- }
- }
-
- /**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public Vector<SequenceNode> getGroups()
- {
- return groups;
- }
-
- /**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public float getMaxHeight()
- {
- return maxheight;
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param nd
- * DOCUMENT ME!
- * @param threshold
- * DOCUMENT ME!
- */
- public void groupNodes(SequenceNode nd, float threshold)
- {
- if (nd == null)
- {
- return;
- }
-
- if ((nd.height / maxheight) > threshold)
- {
- groups.addElement(nd);
- }
- else
- {
- groupNodes((SequenceNode) nd.left(), threshold);
- groupNodes((SequenceNode) nd.right(), threshold);
- }
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param nd
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public float findHeight(SequenceNode nd)
- {
- if (nd == null)
- {
- return maxheight;
- }
-
- if ((nd.left() == null) && (nd.right() == null))
- {
- nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
-
- if (nd.height > maxheight)
- {
- return nd.height;
- }
- else
- {
- return maxheight;
- }
- }
- else
- {
- if (nd.parent() != null)
- {
- nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
- }
- else
- {
- maxheight = 0;
- nd.height = (float) 0.0;
- }
-
- maxheight = findHeight((SequenceNode) (nd.left()));
- maxheight = findHeight((SequenceNode) (nd.right()));
- }
-
- return maxheight;
- }
-
- /**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public SequenceNode reRoot()
- {
- if (maxdist != null)
- {
- ycount = 0;
-
- float tmpdist = maxdist.dist;
-
- // New top
- SequenceNode sn = new SequenceNode();
- sn.setParent(null);
-
- // New right hand of top
- SequenceNode snr = (SequenceNode) maxdist.parent();
- changeDirection(snr, maxdist);
- System.out.println("Printing reversed tree");
- printN(snr);
- snr.dist = tmpdist / 2;
- maxdist.dist = tmpdist / 2;
-
- snr.setParent(sn);
- maxdist.setParent(sn);
-
- sn.setRight(snr);
- sn.setLeft(maxdist);
-
- top = sn;
-
- ycount = 0;
- reCount(top);
- findHeight(top);
- }
-
- return top;
- }
-
- /**
- *
- * @return true if original sequence data can be recovered
- */
- public boolean hasOriginalSequenceData()
- {
- return seqData != null;
- }
-
- /**
- * Returns original alignment data used for calculation - or null where not
- * available.
- *
- * @return null or cut'n'pasteable alignment
- */
- public String printOriginalSequenceData(char gapChar)
- {
- if (seqData == null)
- {
- return null;
- }
-
- StringBuffer sb = new StringBuffer();
- String[] seqdatas = seqData.getSequenceStrings(gapChar);
- for (int i = 0; i < seqdatas.length; i++)
- {
- sb.append(new jalview.util.Format("%-" + 15 + "s").form(sequence[i]
- .getName()));
- sb.append(" " + seqdatas[i] + "\n");
- }
- return sb.toString();
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param nd
- * DOCUMENT ME!
- */
- public void printN(SequenceNode nd)
- {
- if (nd == null)
- {
- return;
- }
-
- if ((nd.left() != null) && (nd.right() != null))
- {
- printN((SequenceNode) nd.left());
- printN((SequenceNode) nd.right());
- }
- else
- {
- System.out.println(" name = " + ((SequenceI) nd.element()).getName());
- }
-
- System.out.println(" dist = " + nd.dist + " " + nd.count + " "
- + nd.height);
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param nd
- * DOCUMENT ME!
- */
- public void reCount(SequenceNode nd)
- {
- ycount = 0;
- _lycount = 0;
- // _lylimit = this.node.size();
- _reCount(nd);
- }
-
- private long _lycount = 0, _lylimit = 0;
-
- /**
- * DOCUMENT ME!
- *
- * @param nd
- * DOCUMENT ME!
- */
- public void _reCount(SequenceNode nd)
- {
- // if (_lycount<_lylimit)
- // {
- // System.err.println("Warning: depth of _recount greater than number of nodes.");
- // }
- if (nd == null)
- {
- return;
- }
- _lycount++;
-
- if ((nd.left() != null) && (nd.right() != null))
- {
-
- _reCount((SequenceNode) nd.left());
- _reCount((SequenceNode) nd.right());
-
- SequenceNode l = (SequenceNode) nd.left();
- SequenceNode r = (SequenceNode) nd.right();
-
- nd.count = l.count + r.count;
- nd.ycount = (l.ycount + r.ycount) / 2;
- }
- else
- {
- nd.count = 1;
- nd.ycount = ycount++;
- }
- _lycount--;
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param nd
- * DOCUMENT ME!
- */
- public void swapNodes(SequenceNode nd)
- {
- if (nd == null)
- {
- return;
- }
-
- SequenceNode tmp = (SequenceNode) nd.left();
-
- nd.setLeft(nd.right());
- nd.setRight(tmp);
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param nd
- * DOCUMENT ME!
- * @param dir
- * DOCUMENT ME!
- */
- public void changeDirection(SequenceNode nd, SequenceNode dir)
- {
- if (nd == null)
- {
- return;
- }
-
- if (nd.parent() != top)
- {
- changeDirection((SequenceNode) nd.parent(), nd);
-
- SequenceNode tmp = (SequenceNode) nd.parent();
-
- if (dir == nd.left())
- {
- nd.setParent(dir);
- nd.setLeft(tmp);
- }
- else if (dir == nd.right())
- {
- nd.setParent(dir);
- nd.setRight(tmp);
- }
- }
- else
- {
- if (dir == nd.left())
- {
- nd.setParent(nd.left());
-
- if (top.left() == nd)
- {
- nd.setRight(top.right());
- }
- else
- {
- nd.setRight(top.left());
- }
- }
- else
- {
- nd.setParent(nd.right());
-
- if (top.left() == nd)
- {
- nd.setLeft(top.right());
- }
- else
- {
- nd.setLeft(top.left());
- }
- }
- }
- }
-
- /**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public SequenceNode getMaxDist()
- {
- return maxdist;
- }
-
- /**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public SequenceNode getTopNode()
- {
- return top;
- }
-
- /**
- *
- * @return true if tree has real distances
- */
- public boolean isHasDistances()
- {
- return hasDistances;
- }
-
- /**
- *
- * @return true if tree has real bootstrap values
- */
- public boolean isHasBootstrap()
- {
- return hasBootstrap;
- }
-
- public boolean isHasRootDistance()
- {
- return hasRootDistance;
- }
-
- /**
- * apply the given transform to all the nodes in the tree.
- *
- * @param nodeTransformI
- */
- public void applyToNodes(NodeTransformI nodeTransformI)
- {
- for (Enumeration<SequenceNode> nodes = node.elements(); nodes
- .hasMoreElements(); nodeTransformI.transform(nodes
- .nextElement()))
- {
- ;
- }
- }
-}
-
-/**
- * DOCUMENT ME!
- *
- * @author $author$
- * @version $Revision$
- */
-class Cluster
-{
- int[] value;
-
- /**
- * Creates a new Cluster object.
- *
- * @param value
- * DOCUMENT ME!
- */
- public Cluster(int[] value)
- {
- this.value = value;
}
}
*/
package jalview.analysis;
-import jalview.datamodel.BinarySequence;
-import jalview.datamodel.BinarySequence.InvalidSequenceTypeException;
-import jalview.math.Matrix;
-import jalview.schemes.ResidueProperties;
-import jalview.schemes.ScoreMatrix;
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityParamsI;
+import jalview.datamodel.AlignmentView;
+import jalview.math.MatrixI;
import java.io.PrintStream;
/**
* Performs Principal Component Analysis on given sequences
- *
- * @author $author$
- * @version $Revision$
*/
public class PCA implements Runnable
{
- Matrix m;
-
- Matrix symm;
-
- Matrix m2;
+ MatrixI symm;
double[] eigenvalue;
- Matrix eigenvector;
+ MatrixI eigenvector;
- StringBuffer details = new StringBuffer();
+ StringBuilder details = new StringBuilder(1024);
- /**
- * Creates a new PCA object. By default, uses blosum62 matrix to generate
- * sequence similarity matrices
- *
- * @param s
- * Set of amino acid sequences to perform PCA on
- */
- public PCA(String[] s)
- {
- this(s, false);
- }
+ final private AlignmentView seqs;
- /**
- * Creates a new PCA object. By default, uses blosum62 matrix to generate
- * sequence similarity matrices
- *
- * @param s
- * Set of sequences to perform PCA on
- * @param nucleotides
- * if true, uses standard DNA/RNA matrix for sequence similarity
- * calculation.
- */
- public PCA(String[] s, boolean nucleotides)
- {
- this(s, nucleotides, null);
- }
+ private ScoreModelI scoreModel;
+
+ private SimilarityParamsI similarityParams;
- public PCA(String[] s, boolean nucleotides, String s_m)
+ public PCA(AlignmentView s, ScoreModelI sm, SimilarityParamsI options)
{
-
- BinarySequence[] bs = new BinarySequence[s.length];
- int ii = 0;
-
- while ((ii < s.length) && (s[ii] != null))
- {
- bs[ii] = new BinarySequence(s[ii], nucleotides);
- bs[ii].encode();
- ii++;
- }
-
- BinarySequence[] bs2 = new BinarySequence[s.length];
- ii = 0;
- ScoreMatrix smtrx = null;
- String sm = s_m;
- if (sm != null)
- {
- smtrx = ResidueProperties.getScoreMatrix(sm);
- }
- if (smtrx == null)
- {
- // either we were given a non-existent score matrix or a scoremodel that
- // isn't based on a pairwise symbol score matrix
- smtrx = ResidueProperties.getScoreMatrix(sm = (nucleotides ? "DNA"
- : "BLOSUM62"));
- }
- details.append("PCA calculation using " + sm
+ this.seqs = s;
+ this.similarityParams = options;
+ this.scoreModel = sm;
+
+ details.append("PCA calculation using " + sm.getName()
+ " sequence similarity matrix\n========\n\n");
- while ((ii < s.length) && (s[ii] != null))
- {
- bs2[ii] = new BinarySequence(s[ii], nucleotides);
- if (smtrx != null)
- {
- try
- {
- bs2[ii].matrixEncode(smtrx);
- } catch (InvalidSequenceTypeException x)
- {
- details.append("Unexpected mismatch of sequence type and score matrix. Calculation will not be valid!\n\n");
- }
- }
- ii++;
- }
-
- // System.out.println("Created binary encoding");
- // printMemory(rt);
- int count = 0;
-
- while ((count < bs.length) && (bs[count] != null))
- {
- count++;
- }
-
- double[][] seqmat = new double[count][bs[0].getDBinary().length];
- double[][] seqmat2 = new double[count][bs2[0].getDBinary().length];
- int i = 0;
-
- while (i < count)
- {
- seqmat[i] = bs[i].getDBinary();
- seqmat2[i] = bs2[i].getDBinary();
- i++;
- }
-
- // System.out.println("Created array");
- // printMemory(rt);
- // System.out.println(" --- Original matrix ---- ");
- m = new Matrix(seqmat);
- m2 = new Matrix(seqmat2);
-
- }
-
- /**
- * Returns the matrix used in PCA calculation
- *
- * @return java.math.Matrix object
- */
-
- public Matrix getM()
- {
- return m;
}
/**
*/
public double getEigenvalue(int i)
{
- return eigenvector.d[i];
+ return eigenvector.getD()[i];
}
/**
*/
public float[][] getComponents(int l, int n, int mm, float factor)
{
- float[][] out = new float[m.rows][3];
+ float[][] out = new float[getHeight()][3];
- for (int i = 0; i < m.rows; i++)
+ for (int i = 0; i < getHeight(); i++)
{
out[i][0] = (float) component(i, l) * factor;
out[i][1] = (float) component(i, n) * factor;
public double[] component(int n)
{
// n = index of eigenvector
- double[] out = new double[m.rows];
+ double[] out = new double[getHeight()];
- for (int i = 0; i < m.rows; i++)
+ for (int i = 0; i < out.length; i++)
{
out[i] = component(i, n);
}
{
double out = 0.0;
- for (int i = 0; i < symm.cols; i++)
+ for (int i = 0; i < symm.width(); i++)
{
- out += (symm.value[row][i] * eigenvector.value[i][n]);
+ out += (symm.getValue(row, i) * eigenvector.getValue(i, n));
}
- return out / eigenvector.d[n];
+ return out / eigenvector.getD()[n];
}
public String getDetails()
}
};
+ // long now = System.currentTimeMillis();
try
{
- details.append("PCA Calculation Mode is "
- + (jvCalcMode ? "Jalview variant" : "Original SeqSpace")
- + "\n");
- Matrix mt = m.transpose();
+ eigenvector = scoreModel.findSimilarities(seqs, similarityParams);
details.append(" --- OrigT * Orig ---- \n");
- if (!jvCalcMode)
- {
- eigenvector = mt.preMultiply(m); // standard seqspace comparison matrix
- }
- else
- {
- eigenvector = mt.preMultiply(m2); // jalview variation on seqsmace
- // method
- }
-
- eigenvector.print(ps);
+ eigenvector.print(ps, "%8.2f");
symm = eigenvector.copy();
details.append(" ---Tridiag transform matrix ---\n");
details.append(" --- D vector ---\n");
- eigenvector.printD(ps);
+ eigenvector.printD(ps, "%15.4e");
ps.println();
details.append("--- E vector ---\n");
- eigenvector.printE(ps);
+ eigenvector.printE(ps, "%15.4e");
ps.println();
// Now produce the diagonalization matrix
}
details.append(" --- New diagonalization matrix ---\n");
- eigenvector.print(ps);
+ eigenvector.print(ps, "%8.2f");
details.append(" --- Eigenvalues ---\n");
- eigenvector.printD(ps);
+ eigenvector.printD(ps, "%15.4e");
ps.println();
/*
* for (int seq=0;seq<symm.rows;seq++) { ps.print("\"Seq"+seq+"\""); for
*
* ps.print(","+component(seq, ev)); } ps.println(); }
*/
+ // System.out.println(("PCA.run() took "
+ // + (System.currentTimeMillis() - now) + "ms"));
}
- boolean jvCalcMode = true;
-
- public void setJvCalcMode(boolean calcMode)
+ /**
+ * Answers the N dimensions of the NxN PCA matrix. This is the number of
+ * sequences involved in the pairwise score calculation.
+ *
+ * @return
+ */
+ public int getHeight()
{
- this.jvCalcMode = calcMode;
+ // TODO can any of seqs[] be null?
+ return seqs.getSequences().length;
}
}
--- /dev/null
+package jalview.analysis;
+
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityParamsI;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.CigarArray;
+import jalview.datamodel.SeqCigar;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.SequenceNode;
+import jalview.math.MatrixI;
+import jalview.viewmodel.AlignmentViewport;
+
+import java.util.BitSet;
+import java.util.Vector;
+
+public abstract class TreeBuilder
+{
+ public static final String AVERAGE_DISTANCE = "AV";
+
+ public static final String NEIGHBOUR_JOINING = "NJ";
+
+ protected Vector<BitSet> clusters;
+
+ protected SequenceI[] sequences;
+
+ public AlignmentView seqData;
+
+ protected BitSet done;
+
+ protected int noseqs;
+
+ int noClus;
+
+ protected MatrixI distances;
+
+ protected int mini;
+
+ protected int minj;
+
+ protected double ri;
+
+ protected double rj;
+
+ SequenceNode maxdist;
+
+ SequenceNode top;
+
+ double maxDistValue;
+
+ double maxheight;
+
+ int ycount;
+
+ Vector<SequenceNode> node;
+
+ private AlignmentView seqStrings;
+
+ /**
+ * Constructor
+ *
+ * @param av
+ * @param sm
+ * @param scoreParameters
+ */
+ public TreeBuilder(AlignmentViewport av, ScoreModelI sm,
+ SimilarityParamsI scoreParameters)
+ {
+ int start, end;
+ boolean selview = av.getSelectionGroup() != null
+ && av.getSelectionGroup().getSize() > 1;
+ seqStrings = av.getAlignmentView(selview);
+ if (!selview)
+ {
+ start = 0;
+ end = av.getAlignment().getWidth();
+ this.sequences = av.getAlignment().getSequencesArray();
+ }
+ else
+ {
+ start = av.getSelectionGroup().getStartRes();
+ end = av.getSelectionGroup().getEndRes() + 1;
+ this.sequences = av.getSelectionGroup().getSequencesInOrder(
+ av.getAlignment());
+ }
+
+ init(seqStrings, start, end);
+
+ computeTree(sm, scoreParameters);
+ }
+
+ public SequenceI[] getSequences()
+ {
+ return sequences;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param nd
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ double findHeight(SequenceNode nd)
+ {
+ if (nd == null)
+ {
+ return maxheight;
+ }
+
+ if ((nd.left() == null) && (nd.right() == null))
+ {
+ nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
+
+ if (nd.height > maxheight)
+ {
+ return nd.height;
+ }
+ else
+ {
+ return maxheight;
+ }
+ }
+ else
+ {
+ if (nd.parent() != null)
+ {
+ nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
+ }
+ else
+ {
+ maxheight = 0;
+ nd.height = (float) 0.0;
+ }
+
+ maxheight = findHeight((SequenceNode) (nd.left()));
+ maxheight = findHeight((SequenceNode) (nd.right()));
+ }
+
+ return maxheight;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param nd
+ * DOCUMENT ME!
+ */
+ void reCount(SequenceNode nd)
+ {
+ ycount = 0;
+ // _lycount = 0;
+ // _lylimit = this.node.size();
+ _reCount(nd);
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param nd
+ * DOCUMENT ME!
+ */
+ void _reCount(SequenceNode nd)
+ {
+ // if (_lycount<_lylimit)
+ // {
+ // System.err.println("Warning: depth of _recount greater than number of nodes.");
+ // }
+ if (nd == null)
+ {
+ return;
+ }
+ // _lycount++;
+
+ if ((nd.left() != null) && (nd.right() != null))
+ {
+
+ _reCount((SequenceNode) nd.left());
+ _reCount((SequenceNode) nd.right());
+
+ SequenceNode l = (SequenceNode) nd.left();
+ SequenceNode r = (SequenceNode) nd.right();
+
+ nd.count = l.count + r.count;
+ nd.ycount = (l.ycount + r.ycount) / 2;
+ }
+ else
+ {
+ nd.count = 1;
+ nd.ycount = ycount++;
+ }
+ // _lycount--;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public SequenceNode getTopNode()
+ {
+ return top;
+ }
+
+ /**
+ *
+ * @return true if tree has real distances
+ */
+ public boolean hasDistances()
+ {
+ return true;
+ }
+
+ /**
+ *
+ * @return true if tree has real bootstrap values
+ */
+ public boolean hasBootstrap()
+ {
+ return false;
+ }
+
+ public boolean hasRootDistance()
+ {
+ return true;
+ }
+
+ /**
+ * Form clusters by grouping sub-clusters, starting from one sequence per
+ * cluster, and finishing when only two clusters remain
+ */
+ void cluster()
+ {
+ while (noClus > 2)
+ {
+ findMinDistance();
+
+ joinClusters(mini, minj);
+
+ noClus--;
+ }
+
+ int rightChild = done.nextClearBit(0);
+ int leftChild = done.nextClearBit(rightChild + 1);
+
+ joinClusters(leftChild, rightChild);
+ top = (node.elementAt(leftChild));
+
+ reCount(top);
+ findHeight(top);
+ findMaxDist(top);
+ }
+
+ /**
+ * Returns the minimum distance between two clusters, and also sets the
+ * indices of the clusters in fields mini and minj
+ *
+ * @return
+ */
+ protected abstract double findMinDistance();
+
+ /**
+ * Calculates the tree using the given score model and parameters, and the
+ * configured tree type
+ * <p>
+ * If the score model computes pairwise distance scores, then these are used
+ * directly to derive the tree
+ * <p>
+ * If the score model computes similarity scores, then the range of the scores
+ * is reversed to give a distance measure, and this is used to derive the tree
+ *
+ * @param sm
+ * @param scoreOptions
+ */
+ protected void computeTree(ScoreModelI sm, SimilarityParamsI scoreOptions)
+ {
+ distances = sm.findDistances(seqData, scoreOptions);
+
+ makeLeaves();
+
+ noClus = clusters.size();
+
+ cluster();
+ }
+
+ /**
+ * Finds the node, at or below the given node, with the maximum distance, and
+ * saves the node and the distance value
+ *
+ * @param nd
+ */
+ void findMaxDist(SequenceNode nd)
+ {
+ if (nd == null)
+ {
+ return;
+ }
+
+ if ((nd.left() == null) && (nd.right() == null))
+ {
+ double dist = nd.dist;
+
+ if (dist > maxDistValue)
+ {
+ maxdist = nd;
+ maxDistValue = dist;
+ }
+ }
+ else
+ {
+ findMaxDist((SequenceNode) nd.left());
+ findMaxDist((SequenceNode) nd.right());
+ }
+ }
+
+ /**
+ * Calculates and returns r, whatever that is
+ *
+ * @param i
+ * @param j
+ *
+ * @return
+ */
+ protected double findr(int i, int j)
+ {
+ double tmp = 1;
+
+ for (int k = 0; k < noseqs; k++)
+ {
+ if ((k != i) && (k != j) && (!done.get(k)))
+ {
+ tmp = tmp + distances.getValue(i, k);
+ }
+ }
+
+ if (noClus > 2)
+ {
+ tmp = tmp / (noClus - 2);
+ }
+
+ return tmp;
+ }
+
+ protected void init(AlignmentView seqView, int start, int end)
+ {
+ this.node = new Vector<SequenceNode>();
+ if (seqView != null)
+ {
+ this.seqData = seqView;
+ }
+ else
+ {
+ SeqCigar[] seqs = new SeqCigar[sequences.length];
+ for (int i = 0; i < sequences.length; i++)
+ {
+ seqs[i] = new SeqCigar(sequences[i], start, end);
+ }
+ CigarArray sdata = new CigarArray(seqs);
+ sdata.addOperation(CigarArray.M, end - start + 1);
+ this.seqData = new AlignmentView(sdata, start);
+ }
+
+ /*
+ * count the non-null sequences
+ */
+ noseqs = 0;
+
+ done = new BitSet();
+
+ for (SequenceI seq : sequences)
+ {
+ if (seq != null)
+ {
+ noseqs++;
+ }
+ }
+ }
+
+ /**
+ * Merges cluster(j) to cluster(i) and recalculates cluster and node distances
+ *
+ * @param i
+ * @param j
+ */
+ void joinClusters(final int i, final int j)
+ {
+ double dist = distances.getValue(i, j);
+
+ ri = findr(i, j);
+ rj = findr(j, i);
+
+ findClusterDistance(i, j);
+
+ SequenceNode sn = new SequenceNode();
+
+ sn.setLeft((node.elementAt(i)));
+ sn.setRight((node.elementAt(j)));
+
+ SequenceNode tmpi = (node.elementAt(i));
+ SequenceNode tmpj = (node.elementAt(j));
+
+ findNewDistances(tmpi, tmpj, dist);
+
+ tmpi.setParent(sn);
+ tmpj.setParent(sn);
+
+ node.setElementAt(sn, i);
+
+ /*
+ * move the members of cluster(j) to cluster(i)
+ * and mark cluster j as out of the game
+ */
+ clusters.get(i).or(clusters.get(j));
+ clusters.get(j).clear();
+ done.set(j);
+ }
+
+ /*
+ * Computes and stores new distances for nodei and nodej, given the previous
+ * distance between them
+ */
+ protected abstract void findNewDistances(SequenceNode nodei,
+ SequenceNode nodej, double previousDistance);
+
+ /**
+ * Calculates and saves the distance between the combination of cluster(i) and
+ * cluster(j) and all other clusters. The form of the calculation depends on
+ * the tree clustering method being used.
+ *
+ * @param i
+ * @param j
+ */
+ protected abstract void findClusterDistance(int i, int j);
+
+ /**
+ * Start by making a cluster for each individual sequence
+ */
+ void makeLeaves()
+ {
+ clusters = new Vector<BitSet>();
+
+ for (int i = 0; i < noseqs; i++)
+ {
+ SequenceNode sn = new SequenceNode();
+
+ sn.setElement(sequences[i]);
+ sn.setName(sequences[i].getName());
+ node.addElement(sn);
+ BitSet bs = new BitSet();
+ bs.set(i);
+ clusters.addElement(bs);
+ }
+ }
+
+ public AlignmentView getOriginalData()
+ {
+ return seqStrings;
+ }
+
+}
--- /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.
+ */
+package jalview.analysis;
+
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.BinaryNode;
+import jalview.datamodel.NodeTransformI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.SequenceNode;
+import jalview.io.NewickFile;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Vector;
+
+/**
+ * A model of a tree, either computed by Jalview or loaded from a file or other
+ * resource or service
+ */
+public class TreeModel
+{
+
+ SequenceI[] sequences;
+
+ /*
+ * SequenceData is a string representation of what the user
+ * sees. The display may contain hidden columns.
+ */
+ private AlignmentView seqData;
+
+ int noseqs;
+
+ SequenceNode top;
+
+ double maxDistValue;
+
+ double maxheight;
+
+ int ycount;
+
+ Vector<SequenceNode> node;
+
+ boolean hasDistances = true; // normal case for jalview trees
+
+ boolean hasBootstrap = false; // normal case for jalview trees
+
+ private boolean hasRootDistance = true;
+
+ /**
+ * Create a new TreeModel object with leaves associated with sequences in
+ * seqs, and (optionally) original alignment data represented by Cigar strings
+ *
+ * @param seqs
+ * SequenceI[]
+ * @param odata
+ * Cigar[]
+ * @param treefile
+ * NewickFile
+ */
+ public TreeModel(SequenceI[] seqs, AlignmentView odata, NewickFile treefile)
+ {
+ this(seqs, treefile.getTree(), treefile.HasDistances(), treefile
+ .HasBootstrap(), treefile.HasRootDistance());
+ seqData = odata;
+
+ associateLeavesToSequences(seqs);
+ }
+
+ /**
+ * Constructor given a calculated tree
+ *
+ * @param tree
+ */
+ public TreeModel(TreeBuilder tree)
+ {
+ this(tree.getSequences(), tree.getTopNode(), tree.hasDistances(), tree
+ .hasBootstrap(), tree.hasRootDistance());
+ seqData = tree.getOriginalData();
+ }
+
+ /**
+ * Constructor given sequences, root node and tree property flags
+ *
+ * @param seqs
+ * @param root
+ * @param hasDist
+ * @param hasBoot
+ * @param hasRootDist
+ */
+ public TreeModel(SequenceI[] seqs, SequenceNode root, boolean hasDist,
+ boolean hasBoot, boolean hasRootDist)
+ {
+ this.sequences = seqs;
+ top = root;
+
+ hasDistances = hasDist;
+ hasBootstrap = hasBoot;
+ hasRootDistance = hasRootDist;
+
+ maxheight = findHeight(top);
+ }
+
+ /**
+ * @param seqs
+ */
+ public void associateLeavesToSequences(SequenceI[] seqs)
+ {
+ SequenceIdMatcher algnIds = new SequenceIdMatcher(seqs);
+
+ Vector<SequenceNode> leaves = findLeaves(top);
+
+ int i = 0;
+ int namesleft = seqs.length;
+
+ SequenceNode j;
+ SequenceI nam;
+ String realnam;
+ Vector<SequenceI> one2many = new Vector<SequenceI>();
+ // int countOne2Many = 0;
+ while (i < leaves.size())
+ {
+ j = leaves.elementAt(i++);
+ realnam = j.getName();
+ nam = null;
+
+ if (namesleft > -1)
+ {
+ nam = algnIds.findIdMatch(realnam);
+ }
+
+ if (nam != null)
+ {
+ j.setElement(nam);
+ if (one2many.contains(nam))
+ {
+ // countOne2Many++;
+ // if (jalview.bin.Cache.log.isDebugEnabled())
+ // jalview.bin.Cache.log.debug("One 2 many relationship for
+ // "+nam.getName());
+ }
+ else
+ {
+ one2many.addElement(nam);
+ namesleft--;
+ }
+ }
+ else
+ {
+ j.setElement(new Sequence(realnam, "THISISAPLACEHLDER"));
+ j.setPlaceholder(true);
+ }
+ }
+ // if (jalview.bin.Cache.log.isDebugEnabled() && countOne2Many>0) {
+ // jalview.bin.Cache.log.debug("There were "+countOne2Many+" alignment
+ // sequence ids (out of "+one2many.size()+" unique ids) linked to two or
+ // more leaves.");
+ // }
+ // one2many.clear();
+ }
+
+ /**
+ * Generate a string representation of the Tree
+ *
+ * @return Newick File with all tree data available
+ */
+ public String print()
+ {
+ NewickFile fout = new NewickFile(getTopNode());
+
+ return fout.print(hasBootstrap(), hasDistances(),
+ hasRootDistance()); // output all data available for tree
+ }
+
+ /**
+ *
+ * used when the alignment associated to a tree has changed.
+ *
+ * @param list
+ * Sequence set to be associated with tree nodes
+ */
+ public void updatePlaceHolders(List<SequenceI> list)
+ {
+ Vector<SequenceNode> leaves = findLeaves(top);
+
+ int sz = leaves.size();
+ SequenceIdMatcher seqmatcher = null;
+ int i = 0;
+
+ while (i < sz)
+ {
+ SequenceNode leaf = leaves.elementAt(i++);
+
+ if (list.contains(leaf.element()))
+ {
+ leaf.setPlaceholder(false);
+ }
+ else
+ {
+ if (seqmatcher == null)
+ {
+ // Only create this the first time we need it
+ SequenceI[] seqs = new SequenceI[list.size()];
+
+ for (int j = 0; j < seqs.length; j++)
+ {
+ seqs[j] = list.get(j);
+ }
+
+ seqmatcher = new SequenceIdMatcher(seqs);
+ }
+
+ SequenceI nam = seqmatcher.findIdMatch(leaf.getName());
+
+ if (nam != null)
+ {
+ if (!leaf.isPlaceholder())
+ {
+ // remapping the node to a new sequenceI - should remove any refs to
+ // old one.
+ // TODO - make many sequenceI to one leaf mappings possible!
+ // (JBPNote)
+ }
+ leaf.setPlaceholder(false);
+ leaf.setElement(nam);
+ }
+ else
+ {
+ if (!leaf.isPlaceholder())
+ {
+ // Construct a new placeholder sequence object for this leaf
+ leaf.setElement(new Sequence(leaf.getName(),
+ "THISISAPLACEHLDER"));
+ }
+ leaf.setPlaceholder(true);
+
+ }
+ }
+ }
+ }
+
+ /**
+ * rename any nodes according to their associated sequence. This will modify
+ * the tree's metadata! (ie the original NewickFile or newly generated
+ * BinaryTree's label data)
+ */
+ public void renameAssociatedNodes()
+ {
+ applyToNodes(new NodeTransformI()
+ {
+
+ @Override
+ public void transform(BinaryNode nd)
+ {
+ Object el = nd.element();
+ if (el != null && el instanceof SequenceI)
+ {
+ nd.setName(((SequenceI) el).getName());
+ }
+ }
+ });
+ }
+
+ /**
+ * Search for leaf nodes below (or at) the given node
+ *
+ * @param nd
+ * root node to search from
+ *
+ * @return
+ */
+ public Vector<SequenceNode> findLeaves(SequenceNode nd)
+ {
+ Vector<SequenceNode> leaves = new Vector<SequenceNode>();
+ findLeaves(nd, leaves);
+ return leaves;
+ }
+
+ /**
+ * Search for leaf nodes.
+ *
+ * @param nd
+ * root node to search from
+ * @param leaves
+ * Vector of leaves to add leaf node objects too.
+ *
+ * @return Vector of leaf nodes on binary tree
+ */
+ Vector<SequenceNode> findLeaves(SequenceNode nd,
+ Vector<SequenceNode> leaves)
+ {
+ if (nd == null)
+ {
+ return leaves;
+ }
+
+ if ((nd.left() == null) && (nd.right() == null)) // Interior node
+ // detection
+ {
+ leaves.addElement(nd);
+
+ return leaves;
+ }
+ else
+ {
+ /*
+ * TODO: Identify internal nodes... if (node.isSequenceLabel()) {
+ * leaves.addElement(node); }
+ */
+ findLeaves((SequenceNode) nd.left(), leaves);
+ findLeaves((SequenceNode) nd.right(), leaves);
+ }
+
+ return leaves;
+ }
+
+ /**
+ * printNode is mainly for debugging purposes.
+ *
+ * @param nd
+ * SequenceNode
+ */
+ void printNode(SequenceNode nd)
+ {
+ if (nd == null)
+ {
+ return;
+ }
+
+ if ((nd.left() == null) && (nd.right() == null))
+ {
+ System.out.println("Leaf = " + ((SequenceI) nd.element()).getName());
+ System.out.println("Dist " + nd.dist);
+ System.out.println("Boot " + nd.getBootstrap());
+ }
+ else
+ {
+ System.out.println("Dist " + nd.dist);
+ printNode((SequenceNode) nd.left());
+ printNode((SequenceNode) nd.right());
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public double getMaxHeight()
+ {
+ return maxheight;
+ }
+
+ /**
+ * Makes a list of groups, where each group is represented by a node whose
+ * height (distance from the root node), as a fraction of the height of the
+ * whole tree, is greater than the given threshold. This corresponds to
+ * selecting the nodes immediately to the right of a vertical line
+ * partitioning the tree (if the tree is drawn with root to the left). Each
+ * such node represents a group that contains all of the sequences linked to
+ * the child leaf nodes.
+ *
+ * @param threshold
+ * @see #getGroups()
+ */
+ public List<SequenceNode> groupNodes(float threshold)
+ {
+ List<SequenceNode> groups = new ArrayList<SequenceNode>();
+ _groupNodes(groups, getTopNode(), threshold);
+ return groups;
+ }
+
+ protected void _groupNodes(List<SequenceNode> groups, SequenceNode nd,
+ float threshold)
+ {
+ if (nd == null)
+ {
+ return;
+ }
+
+ if ((nd.height / maxheight) > threshold)
+ {
+ groups.add(nd);
+ }
+ else
+ {
+ _groupNodes(groups, (SequenceNode) nd.left(), threshold);
+ _groupNodes(groups, (SequenceNode) nd.right(), threshold);
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param nd
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public double findHeight(SequenceNode nd)
+ {
+ if (nd == null)
+ {
+ return maxheight;
+ }
+
+ if ((nd.left() == null) && (nd.right() == null))
+ {
+ nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
+
+ if (nd.height > maxheight)
+ {
+ return nd.height;
+ }
+ else
+ {
+ return maxheight;
+ }
+ }
+ else
+ {
+ if (nd.parent() != null)
+ {
+ nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
+ }
+ else
+ {
+ maxheight = 0;
+ nd.height = (float) 0.0;
+ }
+
+ maxheight = findHeight((SequenceNode) (nd.left()));
+ maxheight = findHeight((SequenceNode) (nd.right()));
+ }
+
+ return maxheight;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param nd
+ * DOCUMENT ME!
+ */
+ void printN(SequenceNode nd)
+ {
+ if (nd == null)
+ {
+ return;
+ }
+
+ if ((nd.left() != null) && (nd.right() != null))
+ {
+ printN((SequenceNode) nd.left());
+ printN((SequenceNode) nd.right());
+ }
+ else
+ {
+ System.out.println(" name = " + ((SequenceI) nd.element()).getName());
+ }
+
+ System.out.println(" dist = " + nd.dist + " " + nd.count + " "
+ + nd.height);
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param nd
+ * DOCUMENT ME!
+ */
+ public void reCount(SequenceNode nd)
+ {
+ ycount = 0;
+ // _lycount = 0;
+ // _lylimit = this.node.size();
+ _reCount(nd);
+ }
+
+ // private long _lycount = 0, _lylimit = 0;
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param nd
+ * DOCUMENT ME!
+ */
+ void _reCount(SequenceNode nd)
+ {
+ // if (_lycount<_lylimit)
+ // {
+ // System.err.println("Warning: depth of _recount greater than number of nodes.");
+ // }
+ if (nd == null)
+ {
+ return;
+ }
+ // _lycount++;
+
+ if ((nd.left() != null) && (nd.right() != null))
+ {
+
+ _reCount((SequenceNode) nd.left());
+ _reCount((SequenceNode) nd.right());
+
+ SequenceNode l = (SequenceNode) nd.left();
+ SequenceNode r = (SequenceNode) nd.right();
+
+ nd.count = l.count + r.count;
+ nd.ycount = (l.ycount + r.ycount) / 2;
+ }
+ else
+ {
+ nd.count = 1;
+ nd.ycount = ycount++;
+ }
+ // _lycount--;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param nd
+ * DOCUMENT ME!
+ */
+ public void swapNodes(SequenceNode nd)
+ {
+ if (nd == null)
+ {
+ return;
+ }
+
+ SequenceNode tmp = (SequenceNode) nd.left();
+
+ nd.setLeft(nd.right());
+ nd.setRight(tmp);
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param nd
+ * DOCUMENT ME!
+ * @param dir
+ * DOCUMENT ME!
+ */
+ void changeDirection(SequenceNode nd, SequenceNode dir)
+ {
+ if (nd == null)
+ {
+ return;
+ }
+
+ if (nd.parent() != top)
+ {
+ changeDirection((SequenceNode) nd.parent(), nd);
+
+ SequenceNode tmp = (SequenceNode) nd.parent();
+
+ if (dir == nd.left())
+ {
+ nd.setParent(dir);
+ nd.setLeft(tmp);
+ }
+ else if (dir == nd.right())
+ {
+ nd.setParent(dir);
+ nd.setRight(tmp);
+ }
+ }
+ else
+ {
+ if (dir == nd.left())
+ {
+ nd.setParent(nd.left());
+
+ if (top.left() == nd)
+ {
+ nd.setRight(top.right());
+ }
+ else
+ {
+ nd.setRight(top.left());
+ }
+ }
+ else
+ {
+ nd.setParent(nd.right());
+
+ if (top.left() == nd)
+ {
+ nd.setLeft(top.right());
+ }
+ else
+ {
+ nd.setLeft(top.left());
+ }
+ }
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public SequenceNode getTopNode()
+ {
+ return top;
+ }
+
+ /**
+ *
+ * @return true if tree has real distances
+ */
+ public boolean hasDistances()
+ {
+ return hasDistances;
+ }
+
+ /**
+ *
+ * @return true if tree has real bootstrap values
+ */
+ public boolean hasBootstrap()
+ {
+ return hasBootstrap;
+ }
+
+ public boolean hasRootDistance()
+ {
+ return hasRootDistance;
+ }
+
+ /**
+ * apply the given transform to all the nodes in the tree.
+ *
+ * @param nodeTransformI
+ */
+ public void applyToNodes(NodeTransformI nodeTransformI)
+ {
+ for (Enumeration<SequenceNode> nodes = node.elements(); nodes
+ .hasMoreElements(); nodeTransformI.transform(nodes
+ .nextElement()))
+ {
+ ;
+ }
+ }
+
+ public AlignmentView getOriginalData()
+ {
+ return seqData;
+ }
+}
--- /dev/null
+package jalview.analysis.scoremodels;
+
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityParamsI;
+import jalview.datamodel.AlignmentView;
+import jalview.math.MatrixI;
+
+public abstract class DistanceScoreModel implements ScoreModelI
+{
+ /**
+ * A similarity score is calculated by first computing a distance score, and
+ * then reversing the min-max range of the score values
+ */
+ @Override
+ public MatrixI findSimilarities(AlignmentView seqData,
+ SimilarityParamsI options)
+ {
+ MatrixI distances = findDistances(seqData, options);
+
+ MatrixI similarities = distanceToSimilarity(distances);
+
+ return similarities;
+ }
+
+ /**
+ * Converts distance scores to similarity scores, by reversing the range of
+ * score values so that max becomes min and vice versa. The input matrix is
+ * not modified.
+ *
+ * @param distances
+ */
+ public static MatrixI distanceToSimilarity(MatrixI distances)
+ {
+ MatrixI similarities = distances.copy();
+
+ similarities.reverseRange(false);
+
+ return similarities;
+ }
+}
--- /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.
+ */
+package jalview.analysis.scoremodels;
+
+import jalview.api.AlignmentViewPanel;
+import jalview.api.FeatureRenderer;
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityParamsI;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.SeqCigar;
+import jalview.datamodel.SequenceFeature;
+import jalview.math.Matrix;
+import jalview.math.MatrixI;
+import jalview.util.SetUtils;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class FeatureDistanceModel extends DistanceScoreModel
+{
+ private static final String NAME = "Sequence Feature Similarity";
+
+ private String description;
+
+ FeatureRenderer fr;
+
+ /**
+ * Constructor
+ */
+ public FeatureDistanceModel()
+ {
+ }
+
+ @Override
+ public ScoreModelI getInstance(AlignmentViewPanel view)
+ {
+ FeatureDistanceModel instance;
+ try
+ {
+ instance = this.getClass().newInstance();
+ instance.configureFromAlignmentView(view);
+ return instance;
+ } catch (InstantiationException | IllegalAccessException e)
+ {
+ System.err.println("Error in " + getClass().getName()
+ + ".getInstance(): " + e.getMessage());
+ return null;
+ }
+ }
+
+ boolean configureFromAlignmentView(AlignmentViewPanel view)
+
+ {
+ fr = view.cloneFeatureRenderer();
+ return true;
+ }
+
+ /**
+ * Calculates a distance measure [i][j] between each pair of sequences as the
+ * average number of features they have but do not share. That is, find the
+ * features each sequence pair has at each column, ignore feature types they
+ * have in common, and count the rest. The totals are normalised by the number
+ * of columns processed.
+ * <p>
+ * The parameters argument provides settings for treatment of gap-residue
+ * aligned positions, and whether the score is over the longer or shorter of
+ * each pair of sequences
+ *
+ * @param seqData
+ * @param params
+ */
+ @Override
+ public MatrixI findDistances(AlignmentView seqData,
+ SimilarityParamsI params)
+ {
+ SeqCigar[] seqs = seqData.getSequences();
+ int noseqs = seqs.length;
+ int cpwidth = 0;// = seqData.getWidth();
+ double[][] distances = new double[noseqs][noseqs];
+ List<String> dft = null;
+ if (fr != null)
+ {
+ dft = fr.getDisplayedFeatureTypes();
+ }
+ if (dft == null || dft.isEmpty())
+ {
+ return new Matrix(distances);
+ }
+
+ // need to get real position for view position
+ int[] viscont = seqData.getVisibleContigs();
+
+ /*
+ * scan each column, compute and add to each distance[i, j]
+ * the number of feature types that seqi and seqj do not share
+ */
+ for (int vc = 0; vc < viscont.length; vc += 2)
+ {
+ for (int cpos = viscont[vc]; cpos <= viscont[vc + 1]; cpos++)
+ {
+ cpwidth++;
+
+ /*
+ * first record feature types in this column for each sequence
+ */
+ Map<SeqCigar, Set<String>> sfap = findFeatureTypesAtColumn(
+ seqs, cpos);
+
+ /*
+ * count feature types on either i'th or j'th sequence but not both
+ * and add this 'distance' measure to the total for [i, j] for j > i
+ */
+ for (int i = 0; i < (noseqs - 1); i++)
+ {
+ for (int j = i + 1; j < noseqs; j++)
+ {
+ SeqCigar sc1 = seqs[i];
+ SeqCigar sc2 = seqs[j];
+ Set<String> set1 = sfap.get(sc1);
+ Set<String> set2 = sfap.get(sc2);
+ boolean gap1 = set1 == null;
+ boolean gap2 = set2 == null;
+
+ /*
+ * gap-gap always scores zero
+ * residue-residue is always scored
+ * include gap-residue score if params say to do so
+ */
+ if ((!gap1 && !gap2) || params.includeGaps())
+ {
+ int seqDistance = SetUtils.countDisjunction(set1, set2);
+ distances[i][j] += seqDistance;
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * normalise the distance scores (summed over columns) by the
+ * number of visible columns used in the calculation
+ * and fill in the bottom half of the matrix
+ */
+ // TODO JAL-2424 cpwidth may be out by 1 - affects scores but not tree shape
+ for (int i = 0; i < noseqs; i++)
+ {
+ for (int j = i + 1; j < noseqs; j++)
+ {
+ distances[i][j] /= cpwidth;
+ distances[j][i] = distances[i][j];
+ }
+ }
+ return new Matrix(distances);
+ }
+
+ /**
+ * Builds and returns a map containing a (possibly empty) list (one per
+ * SeqCigar) of visible feature types at the given column position. The map
+ * has no entry for sequences which are gapped at the column position.
+ *
+ * @param seqs
+ * @param columnPosition
+ * @return
+ */
+ protected Map<SeqCigar, Set<String>> findFeatureTypesAtColumn(
+ SeqCigar[] seqs, int columnPosition)
+ {
+ Map<SeqCigar, Set<String>> sfap = new HashMap<SeqCigar, Set<String>>();
+ for (SeqCigar seq : seqs)
+ {
+ int spos = seq.findPosition(columnPosition);
+ if (spos != -1)
+ {
+ Set<String> types = new HashSet<String>();
+ List<SequenceFeature> sfs = fr.findFeaturesAtRes(seq.getRefSeq(),
+ spos);
+ for (SequenceFeature sf : sfs)
+ {
+ types.add(sf.getType());
+ }
+ sfap.put(seq, types);
+ }
+ }
+ return sfap;
+ }
+
+ @Override
+ public String getName()
+ {
+ return NAME;
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return description;
+ }
+
+ @Override
+ public boolean isDNA()
+ {
+ return true;
+ }
+
+ @Override
+ public boolean isProtein()
+ {
+ return true;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "Score between sequences based on hamming distance between binary vectors marking features displayed at each column";
+ }
+}
+++ /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.
- */
-package jalview.analysis.scoremodels;
-
-import jalview.api.analysis.ScoreModelI;
-import jalview.api.analysis.ViewBasedAnalysisI;
-import jalview.datamodel.AlignmentView;
-import jalview.datamodel.SeqCigar;
-import jalview.datamodel.SequenceFeature;
-
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.List;
-
-public class FeatureScoreModel implements ScoreModelI, ViewBasedAnalysisI
-{
- jalview.api.FeatureRenderer fr;
-
- @Override
- public boolean configureFromAlignmentView(
- jalview.api.AlignmentViewPanel view)
- {
- fr = view.cloneFeatureRenderer();
- return true;
- }
-
- @Override
- public float[][] findDistances(AlignmentView seqData)
- {
- int nofeats = 0;
- List<String> dft = fr.getDisplayedFeatureTypes();
- nofeats = dft.size();
- SeqCigar[] seqs = seqData.getSequences();
- int noseqs = seqs.length;
- int cpwidth = 0;// = seqData.getWidth();
- float[][] distance = new float[noseqs][noseqs];
- if (nofeats == 0)
- {
- for (float[] d : distance)
- {
- for (int i = 0; i < d.length; d[i++] = 0f)
- {
- ;
- }
- }
- return distance;
- }
- // need to get real position for view position
- int[] viscont = seqData.getVisibleContigs();
- for (int vc = 0; vc < viscont.length; vc += 2)
- {
-
- for (int cpos = viscont[vc]; cpos <= viscont[vc + 1]; cpos++)
- {
- cpwidth++;
- // get visible features at cpos under view's display settings and
- // compare them
- List<Hashtable<String, SequenceFeature>> sfap = new ArrayList<Hashtable<String, SequenceFeature>>();
- for (int i = 0; i < noseqs; i++)
- {
- Hashtable<String, SequenceFeature> types = new Hashtable<String, SequenceFeature>();
- int spos = seqs[i].findPosition(cpos);
- if (spos != -1)
- {
- List<SequenceFeature> sfs = fr.findFeaturesAtRes(
- seqs[i].getRefSeq(), spos);
- for (SequenceFeature sf : sfs)
- {
- types.put(sf.getType(), sf);
- }
- }
- sfap.add(types);
- }
- for (int i = 0; i < (noseqs - 1); i++)
- {
- if (cpos == 0)
- {
- distance[i][i] = 0f;
- }
- for (int j = i + 1; j < noseqs; j++)
- {
- int sfcommon = 0;
- // compare the two lists of features...
- Hashtable<String, SequenceFeature> fi = sfap.get(i), fk, fj = sfap
- .get(j);
- if (fi.size() > fj.size())
- {
- fk = fj;
- }
- else
- {
- fk = fi;
- fi = fj;
- }
- for (String k : fi.keySet())
- {
- SequenceFeature sfj = fk.get(k);
- if (sfj != null)
- {
- sfcommon++;
- }
- }
- distance[i][j] += (fi.size() + fk.size() - 2f * sfcommon);
- distance[j][i] += distance[i][j];
- }
- }
- }
- }
- for (int i = 0; i < noseqs; i++)
- {
- for (int j = i + 1; j < noseqs; j++)
- {
- distance[i][j] /= cpwidth;
- distance[j][i] = distance[i][j];
- }
- }
- return distance;
- }
-
- @Override
- public String getName()
- {
- return "Sequence Feature Similarity";
- }
-
- @Override
- public boolean isDNA()
- {
- return true;
- }
-
- @Override
- public boolean isProtein()
- {
- return true;
- }
-
- @Override
- public String toString()
- {
- return "Score between sequences based on hamming distance between binary vectors marking features displayed at each column";
- }
-}
--- /dev/null
+package jalview.analysis.scoremodels;
+
+import jalview.api.AlignmentViewPanel;
+import jalview.api.analysis.PairwiseScoreModelI;
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityParamsI;
+import jalview.datamodel.AlignmentView;
+import jalview.math.Matrix;
+import jalview.math.MatrixI;
+import jalview.util.Comparison;
+
+/**
+ * A class to provide sequence pairwise similarity based on residue identity.
+ * Instances of this class are immutable and thread-safe, so the same object is
+ * returned from calls to getInstance().
+ */
+public class PIDModel extends SimilarityScoreModel implements
+ PairwiseScoreModelI
+{
+ private static final String NAME = "PID";
+
+ /**
+ * Constructor
+ */
+ public PIDModel()
+ {
+ }
+
+ @Override
+ public String getName()
+ {
+ return NAME;
+ }
+
+ /**
+ * Answers null for description. If a display name is needed, use getName() or
+ * an internationalized string built from the name.
+ */
+ @Override
+ public String getDescription()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isDNA()
+ {
+ return true;
+ }
+
+ @Override
+ public boolean isProtein()
+ {
+ return true;
+ }
+
+ /**
+ * Answers 1 if c and d are the same residue (ignoring case), and not gap
+ * characters. Answers 0 for non-matching or gap characters.
+ */
+ @Override
+ public float getPairwiseScore(char c, char d)
+ {
+ c = toUpper(c);
+ d = toUpper(d);
+ if (c == d && !Comparison.isGap(c))
+ {
+ return 1f;
+ }
+ return 0f;
+ }
+
+ /**
+ * @param c
+ */
+ protected static char toUpper(char c)
+ {
+ if ('a' <= c && c <= 'z')
+ {
+ c += 'A' - 'a';
+ }
+ return c;
+ }
+
+ /**
+ * Computes similarity scores based on pairwise percentage identity of
+ * sequences. For consistency with Jalview 2.10.1's SeqSpace mode PCA
+ * calculation, the percentage scores are rescaled to the width of the
+ * sequences (as if counts of identical residues). This method is thread-safe.
+ */
+ @Override
+ public MatrixI findSimilarities(AlignmentView seqData,
+ SimilarityParamsI options)
+ {
+ String[] seqs = seqData.getSequenceStrings(Comparison.GAP_DASH);
+
+ MatrixI result = findSimilarities(seqs, options);
+
+ result.multiply(seqData.getWidth() / 100d);
+
+ return result;
+ }
+
+ /**
+ * A distance score is computed in the usual way (by reversing the range of
+ * the similarity score results), and then rescaled to percentage values
+ * (reversing the rescaling to count values done in findSimilarities). This
+ * method is thread-safe.
+ */
+ @Override
+ public MatrixI findDistances(AlignmentView seqData,
+ SimilarityParamsI options)
+ {
+ MatrixI result = super.findDistances(seqData, options);
+
+ if (seqData.getWidth() != 0)
+ {
+ result.multiply(100d / seqData.getWidth());
+ }
+
+ return result;
+ }
+
+ /**
+ * Compute percentage identity scores, using the gap treatment and
+ * normalisation specified by the options parameter
+ *
+ * @param seqs
+ * @param options
+ * @return
+ */
+ protected MatrixI findSimilarities(String[] seqs,
+ SimilarityParamsI options)
+ {
+ // TODO reuse code in ScoreMatrix instead somehow
+ double[][] values = new double[seqs.length][];
+ for (int row = 0; row < seqs.length; row++)
+ {
+ values[row] = new double[seqs.length];
+ for (int col = 0; col < seqs.length; col++)
+ {
+ double total = computePID(seqs[row], seqs[col], options);
+ values[row][col] = total;
+ }
+ }
+ return new Matrix(values);
+ }
+
+ /**
+ * Computes a percentage identity for two sequences, using the algorithm
+ * choices specified by the options parameter
+ *
+ * @param seq1
+ * @param seq2
+ * @param options
+ * @return
+ */
+ public static double computePID(String seq1, String seq2,
+ SimilarityParamsI options)
+ {
+ int len1 = seq1.length();
+ int len2 = seq2.length();
+ int width = Math.max(len1, len2);
+ int total = 0;
+ int divideBy = 0;
+
+ for (int i = 0; i < width; i++)
+ {
+ if (i >= len1 || i >= len2)
+ {
+ /*
+ * off the end of one sequence; stop if we are only matching
+ * on the shorter sequence length, else treat as trailing gap
+ */
+ if (options.denominateByShortestLength())
+ {
+ break;
+ }
+ if (options.includeGaps())
+ {
+ divideBy++;
+ }
+ if (options.matchGaps())
+ {
+ total++;
+ }
+ continue;
+ }
+ char c1 = seq1.charAt(i);
+ char c2 = seq2.charAt(i);
+ boolean gap1 = Comparison.isGap(c1);
+ boolean gap2 = Comparison.isGap(c2);
+
+ if (gap1 && gap2)
+ {
+ /*
+ * gap-gap: include if options say so, if so
+ * have to score as identity; else ignore
+ */
+ if (options.includeGappedColumns())
+ {
+ divideBy++;
+ total++;
+ }
+ continue;
+ }
+
+ if (gap1 || gap2)
+ {
+ /*
+ * gap-residue: include if options say so,
+ * count as match if options say so
+ */
+ if (options.includeGaps())
+ {
+ divideBy++;
+ }
+ if (options.matchGaps())
+ {
+ total++;
+ }
+ continue;
+ }
+
+ /*
+ * remaining case is gap-residue
+ */
+ if (toUpper(c1) == toUpper(c2))
+ {
+ total++;
+ }
+ divideBy++;
+ }
+
+ return divideBy == 0 ? 0D : 100D * total / divideBy;
+ }
+
+ @Override
+ public ScoreModelI getInstance(AlignmentViewPanel avp)
+ {
+ return this;
+ }
+}
+++ /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.
- */
-package jalview.analysis.scoremodels;
-
-import jalview.api.analysis.ScoreModelI;
-import jalview.datamodel.AlignmentView;
-import jalview.util.Comparison;
-
-public class PIDScoreModel implements ScoreModelI
-{
-
- @Override
- public float[][] findDistances(AlignmentView seqData)
- {
- String[] sequenceString = seqData
- .getSequenceStrings(Comparison.GapChars.charAt(0));
- int noseqs = sequenceString.length;
- float[][] distance = new float[noseqs][noseqs];
- for (int i = 0; i < (noseqs - 1); i++)
- {
- for (int j = i; j < noseqs; j++)
- {
- if (j == i)
- {
- distance[i][i] = 0;
- }
- else
- {
- distance[i][j] = 100 - Comparison.PID(sequenceString[i],
- sequenceString[j]);
-
- distance[j][i] = distance[i][j];
- }
- }
- }
- return distance;
- }
-
- @Override
- public String getName()
- {
- return "PID";
- }
-
- @Override
- public boolean isDNA()
- {
- return true;
- }
-
- @Override
- public boolean isProtein()
- {
- return true;
- }
-
-}
+++ /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.
- */
-package jalview.analysis.scoremodels;
-
-import jalview.api.analysis.ScoreModelI;
-import jalview.datamodel.AlignmentView;
-import jalview.util.Comparison;
-
-public abstract class PairwiseSeqScoreModel implements ScoreModelI
-{
- abstract public int getPairwiseScore(char c, char d);
-
- public float[][] findDistances(AlignmentView seqData)
- {
- String[] sequenceString = seqData
- .getSequenceStrings(Comparison.GapChars.charAt(0));
- int noseqs = sequenceString.length;
- float[][] distance = new float[noseqs][noseqs];
-
- int maxscore = 0;
- int end = sequenceString[0].length();
- for (int i = 0; i < (noseqs - 1); i++)
- {
- for (int j = i; j < noseqs; j++)
- {
- int score = 0;
-
- for (int k = 0; k < end; k++)
- {
- try
- {
- score += getPairwiseScore(sequenceString[i].charAt(k),
- sequenceString[j].charAt(k));
- } catch (Exception ex)
- {
- System.err.println("err creating " + getName() + " tree");
- ex.printStackTrace();
- }
- }
-
- distance[i][j] = (float) score;
-
- if (score > maxscore)
- {
- maxscore = score;
- }
- }
- }
-
- for (int i = 0; i < (noseqs - 1); i++)
- {
- for (int j = i; j < noseqs; j++)
- {
- distance[i][j] = (float) maxscore - distance[i][j];
- distance[j][i] = distance[i][j];
- }
- }
- return distance;
- }
-
- abstract public int[][] getMatrix();
-}
--- /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.
+ */
+package jalview.analysis.scoremodels;
+
+import jalview.api.AlignmentViewPanel;
+import jalview.api.analysis.PairwiseScoreModelI;
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityParamsI;
+import jalview.datamodel.AlignmentView;
+import jalview.math.Matrix;
+import jalview.math.MatrixI;
+import jalview.util.Comparison;
+
+import java.util.Arrays;
+
+/**
+ * A class that models a substitution score matrix for any given alphabet of
+ * symbols. Instances of this class are immutable and thread-safe, so the same
+ * object is returned from calls to getInstance().
+ */
+public class ScoreMatrix extends SimilarityScoreModel implements
+ PairwiseScoreModelI
+{
+ private static final char GAP_CHARACTER = Comparison.GAP_DASH;
+
+ /*
+ * an arbitrary score to assign for identity of an unknown symbol
+ * (this is the value on the diagonal in the * column of the NCBI matrix)
+ * (though a case could be made for using the minimum diagonal value)
+ */
+ private static final int UNKNOWN_IDENTITY_SCORE = 1;
+
+ /*
+ * Jalview 2.10.1 treated gaps as X (peptide) or N (nucleotide)
+ * for pairwise scoring; 2.10.2 uses gap score (last column) in
+ * score matrix (JAL-2397)
+ * Set this flag to true (via Groovy) for 2.10.1 behaviour
+ */
+ private static boolean scoreGapAsAny = false;
+
+ public static final short UNMAPPED = (short) -1;
+
+ private static final String BAD_ASCII_ERROR = "Unexpected character %s in getPairwiseScore";
+
+ private static final int MAX_ASCII = 127;
+
+ /*
+ * the name of the model as shown in menus
+ * each score model in use should have a unique name
+ */
+ private String name;
+
+ /*
+ * a description for the model as shown in tooltips
+ */
+ private String description;
+
+ /*
+ * the characters that the model provides scores for
+ */
+ private char[] symbols;
+
+ /*
+ * the score matrix; both dimensions must equal the number of symbols
+ * matrix[i][j] is the substitution score for replacing symbols[i] with symbols[j]
+ */
+ private float[][] matrix;
+
+ /*
+ * quick lookup to convert from an ascii character value to the index
+ * of the corresponding symbol in the score matrix
+ */
+ private short[] symbolIndex;
+
+ /*
+ * true for Protein Score matrix, false for dna score matrix
+ */
+ private boolean peptide;
+
+ private float minValue;
+
+ private float maxValue;
+
+ /**
+ * Constructor given a name, symbol alphabet, and matrix of scores for pairs
+ * of symbols. The matrix should be square and of the same size as the
+ * alphabet, for example 20x20 for a 20 symbol alphabet.
+ *
+ * @param theName
+ * Unique, human readable name for the matrix
+ * @param alphabet
+ * the symbols to which scores apply
+ * @param values
+ * Pairwise scores indexed according to the symbol alphabet
+ */
+ public ScoreMatrix(String theName, char[] alphabet, float[][] values)
+ {
+ this(theName, null, alphabet, values);
+ }
+
+ /**
+ * Constructor given a name, description, symbol alphabet, and matrix of
+ * scores for pairs of symbols. The matrix should be square and of the same
+ * size as the alphabet, for example 20x20 for a 20 symbol alphabet.
+ *
+ * @param theName
+ * Unique, human readable name for the matrix
+ * @param theDescription
+ * descriptive display name suitable for use in menus
+ * @param alphabet
+ * the symbols to which scores apply
+ * @param values
+ * Pairwise scores indexed according to the symbol alphabet
+ */
+ public ScoreMatrix(String theName, String theDescription,
+ char[] alphabet, float[][] values)
+ {
+ if (alphabet.length != values.length)
+ {
+ throw new IllegalArgumentException(
+ "score matrix size must match alphabet size");
+ }
+ for (float[] row : values)
+ {
+ if (row.length != alphabet.length)
+ {
+ throw new IllegalArgumentException(
+ "score matrix size must be square");
+ }
+ }
+
+ this.matrix = values;
+ this.name = theName;
+ this.description = theDescription;
+ this.symbols = alphabet;
+
+ symbolIndex = buildSymbolIndex(alphabet);
+
+ findMinMax();
+
+ /*
+ * crude heuristic for now...
+ */
+ peptide = alphabet.length >= 20;
+ }
+
+ /**
+ * Record the minimum and maximum score values
+ */
+ protected void findMinMax()
+ {
+ float min = Float.MAX_VALUE;
+ float max = -Float.MAX_VALUE;
+ if (matrix != null)
+ {
+ for (float[] row : matrix)
+ {
+ if (row != null)
+ {
+ for (float f : row)
+ {
+ min = Math.min(min, f);
+ max = Math.max(max, f);
+ }
+ }
+ }
+ }
+ minValue = min;
+ maxValue = max;
+ }
+
+ /**
+ * Returns an array A where A[i] is the position in the alphabet array of the
+ * character whose value is i. For example if the alphabet is { 'A', 'D', 'X'
+ * } then A['D'] = A[68] = 1.
+ * <p>
+ * Unmapped characters (not in the alphabet) get an index of -1.
+ * <p>
+ * Mappings are added automatically for lower case symbols (for non case
+ * sensitive scoring), unless they are explicitly present in the alphabet (are
+ * scored separately in the score matrix).
+ * <p>
+ * the gap character (space, dash or dot) included in the alphabet (if any) is
+ * recorded in a field
+ *
+ * @param alphabet
+ * @return
+ */
+ short[] buildSymbolIndex(char[] alphabet)
+ {
+ short[] index = new short[MAX_ASCII + 1];
+ Arrays.fill(index, UNMAPPED);
+ short pos = 0;
+ for (char c : alphabet)
+ {
+ if (c <= MAX_ASCII)
+ {
+ index[c] = pos;
+ }
+
+ /*
+ * also map lower-case character (unless separately mapped)
+ */
+ if (c >= 'A' && c <= 'Z')
+ {
+ short lowerCase = (short) (c + ('a' - 'A'));
+ if (index[lowerCase] == UNMAPPED)
+ {
+ index[lowerCase] = pos;
+ }
+ }
+ pos++;
+ }
+ return index;
+ }
+
+ @Override
+ public String getName()
+ {
+ return name;
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return description;
+ }
+
+ @Override
+ public boolean isDNA()
+ {
+ return !peptide;
+ }
+
+ @Override
+ public boolean isProtein()
+ {
+ return peptide;
+ }
+
+ /**
+ * Returns a copy of the score matrix as used in getPairwiseScore. If using
+ * this matrix directly, callers <em>must</em> also call
+ * <code>getMatrixIndex</code> in order to get the matrix index for each
+ * character (symbol).
+ *
+ * @return
+ * @see #getMatrixIndex(char)
+ */
+ public float[][] getMatrix()
+ {
+ float[][] v = new float[matrix.length][matrix.length];
+ for (int i = 0; i < matrix.length; i++)
+ {
+ v[i] = Arrays.copyOf(matrix[i], matrix[i].length);
+ }
+ return v;
+ }
+
+ /**
+ * Answers the matrix index for a given character, or -1 if unmapped in the
+ * matrix. Use this method only if using <code>getMatrix</code> in order to
+ * compute scores directly (without symbol lookup) for efficiency.
+ *
+ * @param c
+ * @return
+ * @see #getMatrix()
+ */
+ public int getMatrixIndex(char c)
+ {
+ if (c < symbolIndex.length)
+ {
+ return symbolIndex[c];
+ }
+ else
+ {
+ return UNMAPPED;
+ }
+ }
+
+ /**
+ * Returns the pairwise score for substituting c with d. If either c or d is
+ * an unexpected character, returns 1 for identity (c == d), else the minimum
+ * score value in the matrix.
+ */
+ @Override
+ public float getPairwiseScore(char c, char d)
+ {
+ if (c >= symbolIndex.length)
+ {
+ System.err.println(String.format(BAD_ASCII_ERROR, c));
+ return 0;
+ }
+ if (d >= symbolIndex.length)
+ {
+ System.err.println(String.format(BAD_ASCII_ERROR, d));
+ return 0;
+ }
+
+ int cIndex = symbolIndex[c];
+ int dIndex = symbolIndex[d];
+ if (cIndex != UNMAPPED && dIndex != UNMAPPED)
+ {
+ return matrix[cIndex][dIndex];
+ }
+
+ /*
+ * one or both symbols not found in the matrix
+ * currently scoring as 1 (for identity) or the minimum
+ * matrix score value (otherwise)
+ * (a case could be made for using minimum row/column value instead)
+ */
+ return c == d ? UNKNOWN_IDENTITY_SCORE : getMinimumScore();
+ }
+
+ /**
+ * pretty print the matrix
+ */
+ @Override
+ public String toString()
+ {
+ return outputMatrix(false);
+ }
+
+ /**
+ * Print the score matrix, optionally formatted as html, with the alphabet
+ * symbols as column headings and at the start of each row.
+ * <p>
+ * The non-html format should give an output which can be parsed as a score
+ * matrix file
+ *
+ * @param html
+ * @return
+ */
+ public String outputMatrix(boolean html)
+ {
+ StringBuilder sb = new StringBuilder(512);
+
+ /*
+ * heading row with alphabet
+ */
+ if (html)
+ {
+ sb.append("<table border=\"1\">");
+ sb.append(html ? "<tr><th></th>" : "");
+ }
+ else
+ {
+ sb.append("ScoreMatrix ").append(getName()).append("\n");
+ }
+ for (char sym : symbols)
+ {
+ if (html)
+ {
+ sb.append("<th> ").append(sym).append(" </th>");
+ }
+ else
+ {
+ sb.append("\t").append(sym);
+ }
+ }
+ sb.append(html ? "</tr>\n" : "\n");
+
+ /*
+ * table of scores
+ */
+ for (char c1 : symbols)
+ {
+ if (html)
+ {
+ sb.append("<tr><td>");
+ }
+ sb.append(c1).append(html ? "</td>" : "");
+ for (char c2 : symbols)
+ {
+ sb.append(html ? "<td>" : "\t")
+ .append(matrix[symbolIndex[c1]][symbolIndex[c2]])
+ .append(html ? "</td>" : "");
+ }
+ sb.append(html ? "</tr>\n" : "\n");
+ }
+ if (html)
+ {
+ sb.append("</table>");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Answers the number of symbols coded for (also equal to the number of rows
+ * and columns of the score matrix)
+ *
+ * @return
+ */
+ public int getSize()
+ {
+ return symbols.length;
+ }
+
+ /**
+ * Computes an NxN matrix where N is the number of sequences, and entry [i, j]
+ * is sequence[i] pairwise multiplied with sequence[j], as a sum of scores
+ * computed using the current score matrix. For example
+ * <ul>
+ * <li>Sequences:</li>
+ * <li>FKL</li>
+ * <li>R-D</li>
+ * <li>QIA</li>
+ * <li>GWC</li>
+ * <li>Score matrix is BLOSUM62</li>
+ * <li>Gaps treated same as X (unknown)</li>
+ * <li>product [0, 0] = F.F + K.K + L.L = 6 + 5 + 4 = 15</li>
+ * <li>product [1, 1] = R.R + -.- + D.D = 5 + -1 + 6 = 10</li>
+ * <li>product [2, 2] = Q.Q + I.I + A.A = 5 + 4 + 4 = 13</li>
+ * <li>product [3, 3] = G.G + W.W + C.C = 6 + 11 + 9 = 26</li>
+ * <li>product[0, 1] = F.R + K.- + L.D = -3 + -1 + -3 = -8
+ * <li>and so on</li>
+ * </ul>
+ * This method is thread-safe.
+ */
+ @Override
+ public MatrixI findSimilarities(AlignmentView seqstrings,
+ SimilarityParamsI options)
+ {
+ char gapChar = scoreGapAsAny ? (seqstrings.isNa() ? 'N' : 'X')
+ : GAP_CHARACTER;
+ String[] seqs = seqstrings.getSequenceStrings(gapChar);
+ return findSimilarities(seqs, options);
+ }
+
+ /**
+ * Computes pairwise similarities of a set of sequences using the given
+ * parameters
+ *
+ * @param seqs
+ * @param params
+ * @return
+ */
+ protected MatrixI findSimilarities(String[] seqs, SimilarityParamsI params)
+ {
+ double[][] values = new double[seqs.length][];
+ for (int row = 0; row < seqs.length; row++)
+ {
+ values[row] = new double[seqs.length];
+ for (int col = 0; col < seqs.length; col++)
+ {
+ double total = computeSimilarity(seqs[row], seqs[col], params);
+ values[row][col] = total;
+ }
+ }
+ return new Matrix(values);
+ }
+
+ /**
+ * Calculates the pairwise similarity of two strings using the given
+ * calculation parameters
+ *
+ * @param seq1
+ * @param seq2
+ * @param params
+ * @return
+ */
+ protected double computeSimilarity(String seq1, String seq2,
+ SimilarityParamsI params)
+ {
+ int len1 = seq1.length();
+ int len2 = seq2.length();
+ double total = 0;
+
+ int width = Math.max(len1, len2);
+ for (int i = 0; i < width; i++)
+ {
+ if (i >= len1 || i >= len2)
+ {
+ /*
+ * off the end of one sequence; stop if we are only matching
+ * on the shorter sequence length, else treat as trailing gap
+ */
+ if (params.denominateByShortestLength())
+ {
+ break;
+ }
+ }
+
+ char c1 = i >= len1 ? GAP_CHARACTER : seq1.charAt(i);
+ char c2 = i >= len2 ? GAP_CHARACTER : seq2.charAt(i);
+ boolean gap1 = Comparison.isGap(c1);
+ boolean gap2 = Comparison.isGap(c2);
+
+ if (gap1 && gap2)
+ {
+ /*
+ * gap-gap: include if options say so, else ignore
+ */
+ if (!params.includeGappedColumns())
+ {
+ continue;
+ }
+ }
+ else if (gap1 || gap2)
+ {
+ /*
+ * gap-residue: score if options say so
+ */
+ if (!params.includeGaps())
+ {
+ continue;
+ }
+ }
+ float score = getPairwiseScore(c1, c2);
+ total += score;
+ }
+ return total;
+ }
+
+ /**
+ * Answers a hashcode computed from the symbol alphabet and the matrix score
+ * values
+ */
+ @Override
+ public int hashCode()
+ {
+ int hs = Arrays.hashCode(symbols);
+ for (float[] row : matrix)
+ {
+ hs = hs * 31 + Arrays.hashCode(row);
+ }
+ return hs;
+ }
+
+ /**
+ * Answers true if the argument is a ScoreMatrix with the same symbol alphabet
+ * and score values, else false
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof ScoreMatrix))
+ {
+ return false;
+ }
+ ScoreMatrix sm = (ScoreMatrix) obj;
+ if (Arrays.equals(symbols, sm.symbols)
+ && Arrays.deepEquals(matrix, sm.matrix))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the alphabet the matrix scores for, as a string of characters
+ *
+ * @return
+ */
+ String getSymbols()
+ {
+ return new String(symbols);
+ }
+
+ public float getMinimumScore()
+ {
+ return minValue;
+ }
+
+ public float getMaximumScore()
+ {
+ return maxValue;
+ }
+
+ @Override
+ public ScoreModelI getInstance(AlignmentViewPanel avp)
+ {
+ return this;
+ }
+}
--- /dev/null
+package jalview.analysis.scoremodels;
+
+import jalview.api.AlignmentViewPanel;
+import jalview.api.analysis.ScoreModelI;
+import jalview.io.DataSourceType;
+import jalview.io.FileParse;
+import jalview.io.ScoreMatrixFile;
+
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * A class that can register and serve instances of ScoreModelI
+ */
+public class ScoreModels
+{
+ private final ScoreMatrix BLOSUM62;
+
+ private final ScoreMatrix PAM250;
+
+ private final ScoreMatrix DNA;
+
+ private static ScoreModels instance = new ScoreModels();
+
+ private Map<String, ScoreModelI> models;
+
+ public static ScoreModels getInstance()
+ {
+ return instance;
+ }
+
+ /**
+ * Private constructor to enforce use of singleton. Registers Jalview's
+ * "built-in" score models:
+ * <ul>
+ * <li>BLOSUM62</li>
+ * <li>PAM250</li>
+ * <li>PID</li>
+ * <li>DNA</li>
+ * <li>Sequence Feature Similarity</li>
+ * </ul>
+ */
+ private ScoreModels()
+ {
+ /*
+ * using LinkedHashMap keeps models ordered as added
+ */
+ models = new LinkedHashMap<String, ScoreModelI>();
+ BLOSUM62 = loadScoreMatrix("scoreModel/blosum62.scm");
+ PAM250 = loadScoreMatrix("scoreModel/pam250.scm");
+ registerScoreModel(new PIDModel());
+ DNA = loadScoreMatrix("scoreModel/dna.scm");
+ registerScoreModel(new FeatureDistanceModel());
+ }
+
+ /**
+ * Tries to load a score matrix from the given resource file, and if
+ * successful, registers it.
+ *
+ * @param string
+ * @return
+ */
+ ScoreMatrix loadScoreMatrix(String resourcePath)
+ {
+ try
+ {
+ /*
+ * delegate parsing to ScoreMatrixFile
+ */
+ FileParse fp = new FileParse(resourcePath, DataSourceType.CLASSLOADER);
+ ScoreMatrix sm = new ScoreMatrixFile(fp).parseMatrix();
+ registerScoreModel(sm);
+ return sm;
+ } catch (IOException e)
+ {
+ System.err.println("Error reading " + resourcePath + ": "
+ + e.getMessage());
+ }
+ return null;
+ }
+
+ /**
+ * Answers an iterable set of the registered score models. Currently these are
+ * returned in the order in which they were registered.
+ *
+ * @return
+ */
+ public Iterable<ScoreModelI> getModels()
+ {
+ return models.values();
+ }
+
+ /**
+ * Returns an instance of a score model for the given name. If the model is of
+ * 'view dependent' type (e.g. feature similarity), instantiates a new
+ * instance configured for the given view. Otherwise returns a cached instance
+ * of the score model.
+ *
+ * @param name
+ * @param avp
+ * @return
+ */
+ public ScoreModelI getScoreModel(String name, AlignmentViewPanel avp)
+ {
+ ScoreModelI model = models.get(name);
+ return model == null ? null : model.getInstance(avp);
+ }
+
+ public void registerScoreModel(ScoreModelI sm)
+ {
+ ScoreModelI sm2 = models.get(sm.getName());
+ if (sm2 != null)
+ {
+ System.err.println("Warning: replacing score model " + sm2.getName());
+ }
+ models.put(sm.getName(), sm);
+ }
+
+ /**
+ * Returns the default peptide or nucleotide score model, currently BLOSUM62
+ * or DNA
+ *
+ * @param forPeptide
+ * @return
+ */
+ public ScoreMatrix getDefaultModel(boolean forPeptide)
+ {
+ return forPeptide ? BLOSUM62 : DNA;
+ }
+
+ public ScoreMatrix getBlosum62()
+ {
+ return BLOSUM62;
+ }
+
+ public ScoreMatrix getPam250()
+ {
+ return PAM250;
+ }
+}
--- /dev/null
+package jalview.analysis.scoremodels;
+
+import jalview.api.analysis.SimilarityParamsI;
+
+/**
+ * A class to hold parameters that configure the pairwise similarity
+ * calculation. Based on the paper
+ *
+ * <pre>
+ * Quantification of the variation in percentage identity for protein sequence alignments
+ * Raghava, GP and Barton, GJ
+ * BMC Bioinformatics. 2006 Sep 19;7:415
+ * </pre>
+ *
+ * @see https://www.ncbi.nlm.nih.gov/pubmed/16984632
+ */
+public class SimilarityParams implements SimilarityParamsI
+{
+ /**
+ * Based on Jalview's Comparison.PID method, which includes gaps and counts
+ * them as matching; it counts over the length of the shorter sequence
+ */
+ public static final SimilarityParamsI Jalview = new SimilarityParams(
+ true, true, true, true);
+
+ /**
+ * 'SeqSpace' mode PCA calculation includes gaps but does not count them as
+ * matching; it uses the longest sequence length
+ */
+ public static final SimilarityParamsI SeqSpace = new SimilarityParams(
+ true, false, true, true);
+
+ /**
+ * as described in the Raghava-Barton paper
+ * <ul>
+ * <li>ignores gap-gap</li>
+ * <li>does not score gap-residue</li>
+ * <li>includes gap-residue in lengths</li>
+ * <li>matches on longer of two sequences</li>
+ * </ul>
+ */
+ public static final SimilarityParamsI PID1 = new SimilarityParams(false,
+ false, true, false);
+
+ /**
+ * as described in the Raghava-Barton paper
+ * <ul>
+ * <li>ignores gap-gap</li>
+ * <li>ignores gap-residue</li>
+ * <li>matches on longer of two sequences</li>
+ * </ul>
+ */
+ public static final SimilarityParamsI PID2 = new SimilarityParams(false,
+ false, false, false);
+
+ /**
+ * as described in the Raghava-Barton paper
+ * <ul>
+ * <li>ignores gap-gap</li>
+ * <li>ignores gap-residue</li>
+ * <li>matches on shorter of sequences only</li>
+ * </ul>
+ */
+ public static final SimilarityParamsI PID3 = new SimilarityParams(false,
+ false, false, true);
+
+ /**
+ * as described in the Raghava-Barton paper
+ * <ul>
+ * <li>ignores gap-gap</li>
+ * <li>does not score gap-residue</li>
+ * <li>includes gap-residue in lengths</li>
+ * <li>matches on shorter of sequences only</li>
+ * </ul>
+ */
+ public static final SimilarityParamsI PID4 = new SimilarityParams(false,
+ false, true, true);
+
+ private boolean includeGappedColumns;
+
+ private boolean matchGaps;
+
+ private boolean includeGaps;
+
+ private boolean denominateByShortestLength;
+
+ /**
+ * Constructor
+ *
+ * @param includeGapGap
+ * @param matchGapResidue
+ * @param includeGapResidue
+ * if true, gapped positions are counted for normalisation by length
+ * @param shortestLength
+ * if true, the denominator is the shorter sequence length (possibly
+ * including gaps)
+ */
+ public SimilarityParams(boolean includeGapGap, boolean matchGapResidue,
+ boolean includeGapResidue, boolean shortestLength)
+ {
+ includeGappedColumns = includeGapGap;
+ matchGaps = matchGapResidue;
+ includeGaps = includeGapResidue;
+ denominateByShortestLength = shortestLength;
+ }
+
+ @Override
+ public boolean includeGaps()
+ {
+ return includeGaps;
+ }
+
+ @Override
+ public boolean denominateByShortestLength()
+ {
+ return denominateByShortestLength;
+ }
+
+ @Override
+ public boolean includeGappedColumns()
+ {
+ return includeGappedColumns;
+ }
+
+ @Override
+ public boolean matchGaps()
+ {
+ return matchGaps;
+ }
+}
--- /dev/null
+package jalview.analysis.scoremodels;
+
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityParamsI;
+import jalview.datamodel.AlignmentView;
+import jalview.math.MatrixI;
+
+public abstract class SimilarityScoreModel implements ScoreModelI
+{
+
+ /**
+ * Computed similarity scores are converted to distance scores by subtracting
+ * every value from the maximum value. That is, maximum similarity corresponds
+ * to zero distance, and smaller similarities to larger distances.
+ */
+ @Override
+ public MatrixI findDistances(AlignmentView seqData,
+ SimilarityParamsI options)
+ {
+ MatrixI similarities = findSimilarities(seqData, options);
+
+ MatrixI distances = similarityToDistance(similarities);
+
+ return distances;
+ }
+
+ /**
+ * Converts a matrix of similarity scores to distance scores, by reversing the
+ * range of the scores, mapping the maximum to zero. The input matrix is not
+ * modified.
+ *
+ * @param similarities
+ */
+ public static MatrixI similarityToDistance(MatrixI similarities)
+ {
+ MatrixI distances = similarities.copy();
+
+ distances.reverseRange(true);
+
+ return distances;
+ }
+
+}
package jalview.analysis.scoremodels;
import jalview.analysis.AlignSeq;
+import jalview.api.AlignmentViewPanel;
import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityParamsI;
import jalview.datamodel.AlignmentView;
import jalview.datamodel.SequenceI;
+import jalview.math.Matrix;
+import jalview.math.MatrixI;
import jalview.util.Comparison;
-public class SWScoreModel implements ScoreModelI
+/**
+ * A class that computes pairwise similarity scores using the Smith-Waterman
+ * alignment algorithm
+ */
+public class SmithWatermanModel extends SimilarityScoreModel
{
+ private static final String NAME = "Smith Waterman Score";
+
+ private String description;
+
+ /**
+ * Constructor
+ */
+ public SmithWatermanModel()
+ {
+ }
@Override
- public float[][] findDistances(AlignmentView seqData)
+ public MatrixI findSimilarities(AlignmentView seqData,
+ SimilarityParamsI options)
{
SequenceI[] sequenceString = seqData.getVisibleAlignment(
- Comparison.GapChars.charAt(0)).getSequencesArray();
+ Comparison.GAP_SPACE).getSequencesArray();
int noseqs = sequenceString.length;
- float[][] distance = new float[noseqs][noseqs];
+ double[][] distances = new double[noseqs][noseqs];
- float max = -1;
+ double max = -1;
for (int i = 0; i < (noseqs - 1); i++)
{
as.calcScoreMatrix();
as.traceAlignment();
as.printAlignment(System.out);
- distance[i][j] = (float) as.maxscore;
+ distances[i][j] = as.maxscore;
- if (max < distance[i][j])
+ if (max < distances[i][j])
{
- max = distance[i][j];
+ max = distances[i][j];
}
}
}
- for (int i = 0; i < (noseqs - 1); i++)
- {
- for (int j = i; j < noseqs; j++)
- {
- distance[i][j] = max - distance[i][j];
- distance[j][i] = distance[i][j];
- }
- }
-
- return distance;
+ return new Matrix(distances);
}
@Override
public String getName()
{
- return "Smith Waterman Score";
+ return NAME;
}
@Override
return true;
}
- public String toString()
+ @Override
+ public String getDescription()
+ {
+ return description;
+ }
+
+ @Override
+ public ScoreModelI getInstance(AlignmentViewPanel avp)
{
- return "Score between two sequences aligned with Smith Waterman with default Peptide/Nucleotide matrix";
+ return this;
}
}
import jalview.datamodel.SequenceI;
import jalview.renderer.ResidueShaderI;
import jalview.schemes.ColourSchemeI;
+import jalview.viewmodel.ViewportRanges;
import java.awt.Color;
+import java.awt.Font;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
public interface AlignViewportI extends ViewStyleI
{
- int getEndRes();
+ /**
+ * Get the ranges object containing details of the start and end sequences and
+ * residues
+ *
+ * @return
+ */
+ public ViewportRanges getRanges();
/**
* calculate the height for visible annotation, revalidating bounds where
AlignmentAnnotation getAlignmentConsensusAnnotation();
/**
+ * get the container for alignment gap annotation
+ *
+ * @return
+ */
+ AlignmentAnnotation getAlignmentGapAnnotation();
+
+ /**
* get the container for cDNA complement consensus annotation
*
* @return
SearchResultsI getSearchResults();
ContactListI getContactList(AlignmentAnnotation _aa, int column);
+
+ /**
+ * Updates view settings with the given font. You may need to call
+ * AlignmentPanel.fontChanged to update the layout geometry.
+ *
+ * @param setGrid
+ * when true, charWidth/height is set according to font metrics
+ */
+ void setFont(Font newFont, boolean b);
+
+ /**
+ * Answers true if split screen protein and cDNA use the same font
+ *
+ * @return
+ */
+ @Override
+ boolean isProteinFontAsCdna();
+
+ /**
+ * Set the flag for whether split screen protein and cDNA use the same font
+ *
+ * @return
+ */
+ @Override
+ void setProteinFontAsCdna(boolean b);
}
--- /dev/null
+package jalview.api;
+
+public interface AlignmentColsCollectionI extends Iterable<Integer>
+{
+ /**
+ * Answers if the column at the given position is hidden.
+ *
+ * @param c
+ * the column index to check
+ * @return true if the column at the position is hidden
+ */
+ public boolean isHidden(int c);
+}
--- /dev/null
+package jalview.api;
+
+import jalview.datamodel.SequenceI;
+
+public interface AlignmentRowsCollectionI extends Iterable<Integer>
+{
+ /**
+ * Answers if the sequence at the given position is hidden.
+ *
+ * @param r
+ * the row index to check
+ * @return true if the sequence at r is hidden
+ */
+ public boolean isHidden(int r);
+
+ /**
+ * Answers the sequence at the given position in the alignment
+ *
+ * @param r
+ * the row index to locate
+ * @return the sequence
+ */
+ public SequenceI getSequence(int r);
+}
*/
package jalview.api;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceI;
/**
*
* @return
*/
- public ColumnSelection getColumnSelection();
+ public HiddenColumns getHiddenColumns();
/**
* Retrieves hidden sequences from a complex file parser
import jalview.datamodel.SequenceI;
import java.awt.Color;
+import java.awt.Graphics;
import java.util.List;
import java.util.Map;
{
/**
- * compute the perceived colour for a given column position in sequenceI,
- * taking transparency and feature visibility into account.
+ * Computes the feature colour for a given sequence and column position,
+ * taking into account sequence feature locations, feature colour schemes,
+ * render ordering, feature and feature group visibility, and transparency.
+ * <p>
+ * The graphics argument should be provided if transparency is applied
+ * (getTransparency() < 1). With feature transparency, visible features are
+ * written to the graphics context and the composite colour may be read off
+ * from it. In this case, the returned feature colour is not the composite
+ * colour but that of the last feature drawn.
+ * <p>
+ * If no transparency applies, then the graphics argument may be null, and the
+ * returned colour is the one that would be drawn for the feature.
+ * <p>
+ * Returns null if there is no visible feature at the position.
+ * <p>
+ * This is provided to support rendering of feature colours other than on the
+ * sequence alignment, including by structure viewers and the overview window.
+ * Note this method takes no account of whether the sequence or column is
+ * hidden.
*
- * @param col
- * - background colour (due to alignment/group shading schemes, etc).
- * @param sequenceI
- * - sequence providing features
- * @param r
- * - column position
+ * @param sequence
+ * @param column
+ * @param g
* @return
*/
- Color findFeatureColour(Color col, SequenceI sequenceI, int r);
+ Color findFeatureColour(SequenceI sequence, int column, Graphics g);
/**
* trigger the feature discovery process for a newly created feature renderer.
*/
void setVisible(String featureType);
+ /**
+ * Sets the transparency value, between 0 (full transparency) and 1 (no
+ * transparency)
+ *
+ * @param value
+ */
+ void setTransparency(float value);
+
+ /**
+ * Returns the transparency value, between 0 (full transparency) and 1 (no
+ * transparency)
+ *
+ * @return
+ */
+ float getTransparency();
}
package jalview.api;
import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import java.awt.Color;
public interface SequenceRenderer
{
- Color getResidueBoxColour(SequenceI sequenceI, int r);
-
- Color getResidueColour(SequenceI seq, int position, FeatureRenderer fr);
+ Color getResidueColour(SequenceI seq, int position,
+ FeatureColourFinder finder);
}
* @return Sequence<->Structure mapping as int[][]
* @throws SiftsException
*/
- public StringBuffer getMappingOutput(MappingOutputPojo mop)
+ public StringBuilder getMappingOutput(MappingOutputPojo mop)
throws SiftsException;
/**
* @return
*/
void setScaleProteinAsCdna(boolean b);
+
+ /**
+ * Answers true if split screen protein and cDNA use the same font
+ *
+ * @return
+ */
+ boolean isProteinFontAsCdna();
+
+ /**
+ * Set the flag for whether split screen protein and cDNA use the same font
+ *
+ * @return
+ */
+ void setProteinFontAsCdna(boolean b);
}
--- /dev/null
+package jalview.api.analysis;
+
+/**
+ * An interface that describes classes that can compute similarity (aka
+ * substitution) scores for pairs of residues
+ */
+public interface PairwiseScoreModelI
+{
+ /**
+ * Answers a similarity score between two sequence characters (for
+ * substitution of the first by the second). Typically the highest scores are
+ * for identity, and the lowest for substitution of a residue by one with very
+ * different properties.
+ *
+ * @param c
+ * @param d
+ * @return
+ */
+ abstract public float getPairwiseScore(char c, char d);
+ // TODO make this static when Java 8
+
+}
-/*
- * 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.
- */
package jalview.api.analysis;
+import jalview.api.AlignmentViewPanel;
import jalview.datamodel.AlignmentView;
+import jalview.math.MatrixI;
public interface ScoreModelI
{
-
- float[][] findDistances(AlignmentView seqData);
-
+ /**
+ * Answers a name for the score model, suitable for display in menus. Names
+ * should be unique across score models in use.
+ *
+ * @return
+ * @see jalview.analysis.scoremodels.ScoreModels#forName(String)
+ */
String getName();
+ /**
+ * Answers an informative description of the model, suitable for use in
+ * tooltips. Descriptions may be internationalised, and need not be unique
+ * (but should be).
+ *
+ * @return
+ */
+ String getDescription();
+
+ /**
+ * Answers true if this model is applicable for nucleotide data (so should be
+ * shown in menus in that context)
+ *
+ * @return
+ */
boolean isDNA();
+ /**
+ * Answers true if this model is applicable for peptide data (so should be
+ * shown in menus in that context)
+ *
+ * @return
+ */
boolean isProtein();
+ // TODO getName, isDNA, isProtein can be static methods in Java 8
+
+ /**
+ * Returns a distance score for the given sequence regions, that is, a matrix
+ * whose value [i][j] is the distance of sequence i from sequence j by some
+ * measure. The options parameter provides configuration choices for how the
+ * similarity score is calculated.
+ *
+ * @param seqData
+ * @param options
+ * @return
+ */
+
+ MatrixI findDistances(AlignmentView seqData, SimilarityParamsI options);
+
+ /**
+ * Returns a similarity score for the given sequence regions, that is, a
+ * matrix whose value [i][j] is the similarity of sequence i to sequence j by
+ * some measure. The options parameter provides configuration choices for how
+ * the similarity score is calculated.
+ *
+ * @param seqData
+ * @param options
+ * @return
+ */
+ MatrixI findSimilarities(AlignmentView seqData, SimilarityParamsI options);
+
+ /**
+ * Returns a score model object configured for the given alignment view.
+ * Depending on the score model, this may just be a singleton instance, or a
+ * new instance configured with data from the view.
+ *
+ * @param avp
+ * @return
+ */
+ ScoreModelI getInstance(AlignmentViewPanel avp);
}
--- /dev/null
+package jalview.api.analysis;
+
+/**
+ * A description of options when computing percentage identity of two aligned
+ * sequences
+ */
+public interface SimilarityParamsI
+{
+ /**
+ * Answers true if gap-gap aligned positions should be included in the
+ * calculation
+ *
+ * @return
+ */
+ boolean includeGappedColumns();
+
+ /**
+ * Answers true if gap-residue alignment is considered a match
+ *
+ * @return
+ */
+ // TODO is this specific to a PID score only?
+ // score matrix will compute whatever is configured for gap-residue
+ boolean matchGaps();
+
+ /**
+ * Answers true if gaps are included in the calculation. This may affect the
+ * calculated score, the denominator (normalisation factor) of the score, or
+ * both. Gap-gap positions are included if this and includeGappedColumns both
+ * answer true.
+ *
+ * @return
+ */
+ boolean includeGaps();
+
+ /**
+ * Answers true if only the shortest sequence length is used to divide the
+ * total score, false if the longest sequence length
+ *
+ * @return
+ */
+ boolean denominateByShortestLength();
+}
--- /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.
+ */
+package jalview.appletgui;
+
+import jalview.datamodel.SequenceI;
+import jalview.viewmodel.OverviewDimensions;
+import jalview.datamodel.AlignmentI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Panel;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+
+public class OverviewPanel extends Panel implements Runnable,
+ MouseMotionListener, MouseListener
+{
+ private OverviewDimensions od;
+
+ private Image miniMe;
+
+ private Image offscreen;
+
+ private AlignViewport av;
+
+ private AlignmentPanel ap;
+
+ private boolean resizing = false;
+
+ // This is set true if the user resizes whilst
+ // the overview is being calculated
+ private boolean resizeAgain = false;
+
+ // Can set different properties in this seqCanvas than
+ // main visible SeqCanvas
+ private SequenceRenderer sr;
+
+ private FeatureRenderer fr;
+
+ private Frame nullFrame;
+
+ public OverviewPanel(AlignmentPanel alPanel)
+ {
+ this.av = alPanel.av;
+ this.ap = alPanel;
+ setLayout(null);
+ nullFrame = new Frame();
+ nullFrame.addNotify();
+
+ sr = new SequenceRenderer(av);
+ sr.graphics = nullFrame.getGraphics();
+ sr.renderGaps = false;
+ sr.forOverview = true;
+ fr = new FeatureRenderer(av);
+
+ od = new OverviewDimensions(av.getRanges(), av.isShowAnnotation());
+
+ setSize(new Dimension(od.getWidth(), od.getHeight()));
+ addComponentListener(new ComponentAdapter()
+ {
+
+ @Override
+ public void componentResized(ComponentEvent evt)
+ {
+ if ((getWidth() != od.getWidth())
+ || (getHeight() != (od.getHeight())))
+ {
+ updateOverviewImage();
+ }
+ }
+ });
+
+ addMouseMotionListener(this);
+
+ addMouseListener(this);
+
+ updateOverviewImage();
+
+ }
+
+ @Override
+ public void mouseEntered(MouseEvent evt)
+ {
+ }
+
+ @Override
+ public void mouseExited(MouseEvent evt)
+ {
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent evt)
+ {
+ }
+
+ @Override
+ public void mouseMoved(MouseEvent evt)
+ {
+ }
+
+ @Override
+ public void mousePressed(MouseEvent evt)
+ {
+ mouseAction(evt);
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent evt)
+ {
+ mouseAction(evt);
+ }
+
+ @Override
+ public void mouseDragged(MouseEvent evt)
+ {
+ mouseAction(evt);
+ }
+
+ private void mouseAction(MouseEvent evt)
+ {
+ od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment()
+ .getHiddenSequences(), av.getColumnSelection(), av
+ .getRanges());
+ ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
+ ap.paintAlignment(false);
+ }
+
+ /**
+ * Updates the overview image when the related alignment panel is updated
+ */
+ public void updateOverviewImage()
+ {
+ if (resizing)
+ {
+ resizeAgain = true;
+ return;
+ }
+
+ if (av.isShowSequenceFeatures())
+ {
+ fr.transferSettings(ap.seqPanel.seqCanvas.fr);
+ }
+
+ resizing = true;
+
+ if ((getSize().width > 0) && (getSize().height > 0))
+ {
+ od.setWidth(getSize().width);
+ od.setHeight(getSize().height);
+ }
+ setSize(new Dimension(od.getWidth(), od.getHeight()));
+
+ Thread thread = new Thread(this);
+ thread.start();
+ repaint();
+ }
+
+ @Override
+ public void run()
+ {
+ miniMe = null;
+
+ if (av.isShowSequenceFeatures())
+ {
+ fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer());
+ }
+
+ if (getSize().width > 0 && getSize().height > 0)
+ {
+ od.setWidth(getSize().width);
+ od.setHeight(getSize().height);
+ }
+
+ setSize(new Dimension(od.getWidth(), od.getHeight()));
+
+ miniMe = nullFrame.createImage(od.getWidth(), od.getHeight());
+ offscreen = nullFrame.createImage(od.getWidth(), od.getHeight());
+
+ Graphics mg = miniMe.getGraphics();
+<<<<<<< HEAD
+
+ int alwidth = av.getAlignment().getWidth();
+ int alheight = av.getAlignment().getAbsoluteHeight();
+ float sampleCol = alwidth / (float) od.getWidth();
+ float sampleRow = alheight / (float) od.getSequencesHeight();
+=======
+ float sampleCol = (float) alwidth / (float) width;
+ float sampleRow = (float) alheight / (float) sequencesHeight;
+
+ int lastcol = 0, lastrow = 0;
+ int xstart = 0, ystart = 0;
+ Color color = Color.yellow;
+ int row, col, sameRow = 0, sameCol = 0;
+ jalview.datamodel.SequenceI seq;
+ final boolean hasHiddenRows = av.hasHiddenRows(), hasHiddenCols = av
+ .hasHiddenColumns();
+ boolean hiddenRow = false;
+ AlignmentI alignment = av.getAlignment();
+
+ FeatureColourFinder finder = new FeatureColourFinder(fr);
+ for (row = 0; row <= sequencesHeight; row++)
+ {
+ if (resizeAgain)
+ {
+ break;
+ }
+ if ((int) (row * sampleRow) == lastrow)
+ {
+ sameRow++;
+ continue;
+ }
+
+ hiddenRow = false;
+ if (hasHiddenRows)
+ {
+ seq = alignment.getHiddenSequences().getHiddenSequence(lastrow);
+ if (seq == null)
+ {
+ int index = alignment.getHiddenSequences()
+ .findIndexWithoutHiddenSeqs(lastrow);
+
+ seq = alignment.getSequenceAt(index);
+ }
+ else
+ {
+ hiddenRow = true;
+ }
+ }
+ else
+ {
+ seq = alignment.getSequenceAt(lastrow);
+ }
+
+ for (col = 0; col < width; col++)
+ {
+ if ((int) (col * sampleCol) == lastcol
+ && (int) (row * sampleRow) == lastrow)
+ {
+ sameCol++;
+ continue;
+ }
+
+ lastcol = (int) (col * sampleCol);
+
+ if (seq.getLength() > lastcol)
+ {
+ color = sr.getResidueColour(seq, lastcol, finder);
+ }
+ else
+ {
+ color = Color.white;
+ }
+
+ if (hiddenRow
+ || (hasHiddenCols && !av.getColumnSelection().isVisible(
+ lastcol)))
+ {
+ color = color.darker().darker();
+ }
+
+ mg.setColor(color);
+ if (sameCol == 1 && sameRow == 1)
+ {
+ mg.drawLine(xstart, ystart, xstart, ystart);
+ }
+ else
+ {
+ mg.fillRect(xstart, ystart, sameCol, sameRow);
+ }
+>>>>>>> bug/JAL-2436featureRendererThreading
+
+ buildImage(sampleRow, sampleCol, mg);
+
+ if (av.isShowAnnotation())
+ {
+ for (int col = 0; col < od.getWidth() && !resizeAgain; col++)
+ {
+ mg.translate(col, od.getSequencesHeight());
+ ap.annotationPanel.renderer.drawGraph(mg,
+ av.getAlignmentConservationAnnotation(),
+ av.getAlignmentConservationAnnotation().annotations,
+ (int) (sampleCol) + 1, od.getGraphHeight(),
+ (int) (col * sampleCol), (int) (col * sampleCol) + 1);
+ mg.translate(-col, -od.getSequencesHeight());
+ }
+ }
+ System.gc();
+
+ resizing = false;
+
+ setBoxPosition();
+
+ if (resizeAgain)
+ {
+ resizeAgain = false;
+ updateOverviewImage();
+ }
+ }
+
+ /*
+ * Build the overview panel image
+ */
+ private void buildImage(float sampleRow, float sampleCol, Graphics mg)
+ {
+ int lastcol = 0;
+ int lastrow = 0;
+ int xstart = 0;
+ int ystart = 0;
+ Color color = Color.yellow;
+ int sameRow = 0;
+ int sameCol = 0;
+
+ SequenceI seq = null;
+
+ final boolean hasHiddenCols = av.hasHiddenColumns();
+ boolean hiddenRow = false;
+
+ for (int row = 0; row <= od.getSequencesHeight() && !resizeAgain; row++)
+ {
+ if ((int) (row * sampleRow) == lastrow)
+ {
+ sameRow++;
+ }
+ else
+ {
+ // get the sequence which would be at alignment index 'lastrow' if no
+ // columns were hidden, and determine whether it is hidden or not
+ hiddenRow = av.getAlignment().isHidden(lastrow);
+ seq = av.getAlignment().getSequenceAtAbsoluteIndex(lastrow);
+
+ for (int col = 0; col < od.getWidth(); col++)
+ {
+ if ((int) (col * sampleCol) == lastcol
+ && (int) (row * sampleRow) == lastrow)
+ {
+ sameCol++;
+ }
+ else
+ {
+ lastcol = (int) (col * sampleCol);
+
+ color = getColumnColourFromSequence(seq, hiddenRow,
+ hasHiddenCols, lastcol);
+
+ mg.setColor(color);
+ if (sameCol == 1 && sameRow == 1)
+ {
+ mg.drawLine(xstart, ystart, xstart, ystart);
+ }
+ else
+ {
+ mg.fillRect(xstart, ystart, sameCol, sameRow);
+ }
+
+ xstart = col;
+ sameCol = 1;
+ }
+ }
+ lastrow = (int) (row * sampleRow);
+ ystart = row;
+ sameRow = 1;
+ }
+ }
+ }
+
+ /*
+ * Find the colour of a sequence at a specified column position
+ */
+ private Color getColumnColourFromSequence(
+ jalview.datamodel.SequenceI seq, boolean hiddenRow,
+ boolean hasHiddenCols, int lastcol)
+ {
+ Color color;
+ if (seq.getLength() > lastcol)
+ {
+ color = sr.getResidueBoxColour(seq, lastcol);
+
+ if (av.isShowSequenceFeatures())
+ {
+ color = fr.findFeatureColour(color, seq, lastcol);
+ }
+ }
+ else
+ {
+ color = Color.white;
+ }
+
+ if (hiddenRow
+ || (hasHiddenCols && !av.getColumnSelection()
+ .isVisible(lastcol)))
+ {
+ color = color.darker().darker();
+ }
+ return color;
+ }
+
+ /**
+ * Update the overview panel box when the associated alignment panel is
+ * changed
+ *
+ */
+ public void setBoxPosition()
+ {
+ od.setBoxPosition(av.getAlignment()
+ .getHiddenSequences(), av.getColumnSelection(), av.getRanges());
+ repaint();
+ }
+
+ @Override
+ public void update(Graphics g)
+ {
+ paint(g);
+ }
+
+ @Override
+ public void paint(Graphics g)
+ {
+ Graphics og = offscreen.getGraphics();
+ if (miniMe != null)
+ {
+ og.drawImage(miniMe, 0, 0, this);
+ og.setColor(Color.red);
+ od.drawBox(og);
+ g.drawImage(offscreen, 0, 0, this);
+ }
+ }
+
+}
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
return;
}
- int rsize = 0, gSize = sg.getSize();
- SequenceI[] rseqs, seqs = new SequenceI[gSize];
- SequenceFeature[] tfeatures, features = new SequenceFeature[gSize];
+ int gSize = sg.getSize();
+ List<SequenceI> seqs = new ArrayList<SequenceI>();
+ List<SequenceFeature> features = new ArrayList<SequenceFeature>();
for (int i = 0; i < gSize; i++)
{
int end = sg.findEndRes(sg.getSequenceAt(i));
if (start <= end)
{
- seqs[rsize] = sg.getSequenceAt(i);
- features[rsize] = new SequenceFeature(null, null, null, start,
- end, "Jalview");
- rsize++;
+ seqs.add(sg.getSequenceAt(i));
+ features.add(new SequenceFeature(null, null, null, start, end,
+ "Jalview"));
}
}
- rseqs = new SequenceI[rsize];
- tfeatures = new SequenceFeature[rsize];
- System.arraycopy(seqs, 0, rseqs, 0, rsize);
- System.arraycopy(features, 0, tfeatures, 0, rsize);
- features = tfeatures;
- seqs = rseqs;
if (ap.seqPanel.seqCanvas.getFeatureRenderer().amendFeatures(seqs,
features, true, ap))
{
ap.alignFrame.sequenceFeatures.setState(true);
ap.av.setShowSequenceFeatures(true);
- ;
ap.highlightSearchResults(null);
}
}
import jalview.analysis.AlignmentSorter;
import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
+import jalview.analysis.TreeBuilder;
+import jalview.analysis.scoremodels.PIDModel;
+import jalview.analysis.scoremodels.ScoreModels;
import jalview.api.AlignViewControllerGuiI;
import jalview.api.AlignViewControllerI;
import jalview.api.AlignViewportI;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentOrder;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceGroup;
import jalview.util.MappingUtils;
import jalview.util.MessageManager;
import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
import java.awt.BorderLayout;
import java.awt.Canvas;
}
public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs,
- ColumnSelection columnSelection, JalviewLite applet,
+ HiddenColumns hidden, JalviewLite applet,
String title, boolean embedded)
{
- this(al, hiddenSeqs, columnSelection, applet, title, embedded, true);
+ this(al, hiddenSeqs, hidden, applet, title, embedded, true);
}
public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs,
- ColumnSelection columnSelection, JalviewLite applet,
+ HiddenColumns hidden, JalviewLite applet,
String title, boolean embedded, boolean addToDisplay)
{
if (applet != null)
{
viewport.hideSequence(hiddenSeqs);
}
- if (columnSelection != null)
+ if (hidden != null)
{
- viewport.setColumnSelection(columnSelection);
+ viewport.getAlignment().setHiddenColumns(hidden);
}
viewport.setScaleAboveWrapped(scaleAbove.getState());
@Override
public void keyPressed(KeyEvent evt)
{
+ ViewportRanges ranges = viewport.getRanges();
+
if (viewport.cursorMode
&& ((evt.getKeyCode() >= KeyEvent.VK_0 && evt.getKeyCode() <= KeyEvent.VK_9) || (evt
.getKeyCode() >= KeyEvent.VK_NUMPAD0 && evt
new String[] { (viewport.cursorMode ? "on" : "off") }));
if (viewport.cursorMode)
{
- alignPanel.seqPanel.seqCanvas.cursorX = viewport.startRes;
- alignPanel.seqPanel.seqCanvas.cursorY = viewport.startSeq;
+ alignPanel.seqPanel.seqCanvas.cursorX = ranges.getStartRes();
+ alignPanel.seqPanel.seqCanvas.cursorY = ranges.getStartSeq();
}
break;
case KeyEvent.VK_PAGE_UP:
if (viewport.getWrapAlignment())
{
- alignPanel.scrollUp(true);
+ ranges.scrollUp(true);
}
else
{
- alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
- - viewport.endSeq + viewport.startSeq);
+ ranges.pageUp();
}
break;
case KeyEvent.VK_PAGE_DOWN:
if (viewport.getWrapAlignment())
{
- alignPanel.scrollUp(false);
+ ranges.scrollUp(false);
}
else
{
- alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
- + viewport.endSeq - viewport.startSeq);
+ ranges.pageDown();
}
break;
{
delete_actionPerformed();
}
+ else if (source == createGroup)
+ {
+ createGroup_actionPerformed();
+ }
+ else if (source == unGroup)
+ {
+ unGroup_actionPerformed();
+ }
else if (source == grpsFromSelection)
{
makeGrpsFromSelection_actionPerformed();
{
copiedHiddenColumns = new Vector();
int hiddenOffset = viewport.getSelectionGroup().getStartRes();
- for (int[] region : viewport.getColumnSelection().getHiddenColumns())
+ for (int[] region : viewport.getAlignment().getHiddenColumns()
+ .getHiddenRegions())
{
copiedHiddenColumns.addElement(new int[] {
region[0] - hiddenOffset, region[1] - hiddenOffset });
seqs, 0, viewport.getAlignment().getWidth(),
viewport.getAlignment()));
- viewport.setEndSeq(viewport.getAlignment().getHeight());
+ viewport.getRanges().setEndSeq(viewport.getAlignment().getHeight());
viewport.getAlignment().getWidth();
viewport.firePropertyChange("alignment", null, viewport.getAlignment()
.getSequences());
void trimAlignment(boolean trimLeft)
{
+ AlignmentI al = viewport.getAlignment();
+ ViewportRanges ranges = viewport.getRanges();
ColumnSelection colSel = viewport.getColumnSelection();
int column;
}
else
{
- seqs = viewport.getAlignment().getSequencesArray();
+ seqs = al.getSequencesArray();
}
TrimRegionCommand trimRegion;
if (trimLeft)
{
trimRegion = new TrimRegionCommand("Remove Left", true, seqs,
- column, viewport.getAlignment());
- viewport.setStartRes(0);
+ column, al);
+ ranges.setStartRes(0);
}
else
{
trimRegion = new TrimRegionCommand("Remove Right", false, seqs,
- column, viewport.getAlignment());
+ column, al);
}
statusBar.setText(MessageManager.formatMessage(
.toString() }));
addHistoryItem(trimRegion);
- for (SequenceGroup sg : viewport.getAlignment().getGroups())
+ for (SequenceGroup sg : al.getGroups())
{
if ((trimLeft && !sg.adjustForRemoveLeft(column))
|| (!trimLeft && !sg.adjustForRemoveRight(column)))
{
- viewport.getAlignment().deleteGroup(sg);
+ al.deleteGroup(sg);
}
}
- viewport.firePropertyChange("alignment", null, viewport
- .getAlignment().getSequences());
+ viewport.firePropertyChange("alignment", null, al.getSequences());
}
}
public void removeGappedColumnMenuItem_actionPerformed()
{
- int start = 0, end = viewport.getAlignment().getWidth() - 1;
+ AlignmentI al = viewport.getAlignment();
+ ViewportRanges ranges = viewport.getRanges();
+ int start = 0;
+ int end = ranges.getAbsoluteAlignmentWidth() - 1;
SequenceI[] seqs;
if (viewport.getSelectionGroup() != null)
// This is to maintain viewport position on first residue
// of first sequence
- SequenceI seq = viewport.getAlignment().getSequenceAt(0);
- int startRes = seq.findPosition(viewport.startRes);
+ SequenceI seq = al.getSequenceAt(0);
+ int startRes = seq.findPosition(ranges.getStartRes());
// ShiftList shifts;
// viewport.getAlignment().removeGaps(shifts=new ShiftList());
// edit.alColumnChanges=shifts.getInverse();
// if (viewport.hasHiddenColumns)
// viewport.getColumnSelection().compensateForEdits(shifts);
- viewport.setStartRes(seq.findIndex(startRes) - 1);
- viewport.firePropertyChange("alignment", null, viewport.getAlignment()
- .getSequences());
+ ranges.setStartRes(seq.findIndex(startRes) - 1);
+ viewport.firePropertyChange("alignment", null, al.getSequences());
}
public void removeAllGapsMenuItem_actionPerformed()
{
- int start = 0, end = viewport.getAlignment().getWidth() - 1;
+ AlignmentI al = viewport.getAlignment();
+ ViewportRanges ranges = viewport.getRanges();
+ int start = 0;
+ int end = ranges.getAbsoluteAlignmentWidth() - 1;
SequenceI[] seqs;
if (viewport.getSelectionGroup() != null)
// This is to maintain viewport position on first residue
// of first sequence
- SequenceI seq = viewport.getAlignment().getSequenceAt(0);
- int startRes = seq.findPosition(viewport.startRes);
+ SequenceI seq = al.getSequenceAt(0);
+ int startRes = seq.findPosition(ranges.getStartRes());
addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
- viewport.getAlignment()));
+ al));
- viewport.setStartRes(seq.findIndex(startRes) - 1);
+ ranges.setStartRes(seq.findIndex(startRes) - 1);
- viewport.firePropertyChange("alignment", null, viewport.getAlignment()
- .getSequences());
+ viewport.firePropertyChange("alignment", null, al.getSequences());
}
boolean selected = conservationMenuItem.getState();
modifyConservation.setEnabled(selected);
viewport.setConservationSelected(selected);
-
- // viewport.setAbovePIDThreshold(false);
- // abovePIDThreshold.setState(false);
+ viewport.getResidueShading().setConservationApplied(selected);
changeColour(viewport.getGlobalColourScheme());
boolean selected = abovePIDThreshold.getState();
modifyPID.setEnabled(selected);
viewport.setAbovePIDThreshold(selected);
- // conservationMenuItem.setState(false);
- // viewport.setConservationSelected(false);
+ if (!selected)
+ {
+ viewport.getResidueShading().setThreshold(0,
+ viewport.isIgnoreGapsConsensus());
+ }
changeColour(viewport.getGlobalColourScheme());
{
SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
AlignmentSorter.sortByPID(viewport.getAlignment(), viewport
- .getAlignment().getSequenceAt(0), null);
+ .getAlignment().getSequenceAt(0));
addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
viewport.getAlignment()));
public void averageDistanceTreeMenuItem_actionPerformed()
{
- NewTreePanel("AV", "PID", "Average distance tree using PID");
+ newTreePanel(TreeBuilder.AVERAGE_DISTANCE, new PIDModel().getName(),
+ "Average distance tree using PID");
}
public void neighbourTreeMenuItem_actionPerformed()
{
- NewTreePanel("NJ", "PID", "Neighbour joining tree using PID");
+ newTreePanel(TreeBuilder.NEIGHBOUR_JOINING, new PIDModel().getName(),
+ "Neighbour joining tree using PID");
}
protected void njTreeBlosumMenuItem_actionPerformed()
{
- NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
+ newTreePanel(TreeBuilder.NEIGHBOUR_JOINING, ScoreModels.getInstance()
+ .getBlosum62().getName(),
+ "Neighbour joining tree using BLOSUM62");
}
protected void avTreeBlosumMenuItem_actionPerformed()
{
- NewTreePanel("AV", "BL", "Average distance tree using BLOSUM62");
+ newTreePanel(TreeBuilder.AVERAGE_DISTANCE, ScoreModels.getInstance()
+ .getBlosum62().getName(),
+ "Average distance tree using BLOSUM62");
}
- void NewTreePanel(String type, String pwType, String title)
+ void newTreePanel(String type, String pwType, String title)
{
// are the sequences aligned?
if (!viewport.getAlignment().isAligned(false))
.getString("action.make_groups_selection"));
grpsFromSelection.addActionListener(this);
createGroup.setLabel(MessageManager.getString("action.create_group"));
+ createGroup.addActionListener(this);
unGroup.setLabel(MessageManager.getString("action.remove_group"));
+ unGroup.addActionListener(this);
+
annotationColumnSelection.setLabel(MessageManager
.getString("action.select_by_annotation"));
annotationColumnSelection.addActionListener(this);
* @param csel
* - columns to be selected on the alignment
*/
- public void select(SequenceGroup sel, ColumnSelection csel)
+ public void select(SequenceGroup sel, ColumnSelection csel,
+ HiddenColumns hidden)
{
- alignPanel.seqPanel.selection(sel, csel, null);
+ alignPanel.seqPanel.selection(sel, csel, hidden, null);
}
public void scrollTo(int row, int column)
*/
package jalview.appletgui;
-import jalview.analysis.NJTree;
+import jalview.analysis.TreeModel;
import jalview.api.AlignViewportI;
import jalview.api.FeatureSettingsModelI;
import jalview.bin.JalviewLite;
import jalview.commands.CommandI;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SearchResults;
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.Sequence;
import jalview.renderer.ResidueShader;
import jalview.schemes.ColourSchemeProperty;
import jalview.schemes.UserColourScheme;
-import jalview.structure.CommandListener;
import jalview.structure.SelectionSource;
import jalview.structure.StructureSelectionManager;
import jalview.structure.VamsasSource;
import jalview.viewmodel.AlignmentViewport;
import java.awt.Font;
+import java.awt.FontMetrics;
public class AlignViewport extends AlignmentViewport implements
- SelectionSource, VamsasSource, CommandListener
+ SelectionSource
{
boolean cursorMode = false;
boolean validCharWidth = true;
- NJTree currentTree = null;
+ TreeModel currentTree = null;
public jalview.bin.JalviewLite applet;
public AlignViewport(AlignmentI al, JalviewLite applet)
{
- super();
+ super(al);
calculator = new jalview.workers.AlignCalcManager();
this.applet = applet;
- alignment = al;
+
// we always pad gaps
this.setPadGaps(true);
- this.startRes = 0;
- this.endRes = al.getWidth() - 1;
- this.startSeq = 0;
- this.endSeq = al.getHeight() - 1;
+
if (applet != null)
{
// get the width and height scaling factors if they were specified
}
}
}
- setFont(font);
+ setFont(font, true);
MAC = new jalview.util.Platform().isAMac();
showConsensus = applet.getDefaultParameter("showConsensus",
showConsensus);
+ showOccupancy = applet.getDefaultParameter("showOccupancy",
+ showOccupancy);
+
setShowUnconserved(applet.getDefaultParameter("showUnconserved",
getShowUnconserved()));
private float heightScale = 1, widthScale = 1;
- public void setFont(Font f)
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setFont(Font f, boolean setGrid)
{
font = f;
if (nullFrame == null)
nullFrame.addNotify();
}
- java.awt.FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font);
- setCharHeight((int) (heightScale * fm.getHeight()));
- setCharWidth((int) (widthScale * fm.charWidth('M')));
+ if (setGrid)
+ {
+ FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font);
+ setCharHeight((int) (heightScale * fm.getHeight()));
+ setCharWidth((int) (widthScale * fm.charWidth('M')));
+ }
if (isUpperCasebold())
{
Font f2 = new Font(f.getName(), Font.BOLD, f.getSize());
- fm = nullFrame.getGraphics().getFontMetrics(f2);
+ FontMetrics fm = nullFrame.getGraphics().getFontMetrics(f2);
setCharWidth((int) (widthScale * (fm.stringWidth("MMMMMMMMMMM") / 10)));
}
}
public void resetSeqLimits(int height)
{
- setEndSeq(height / getCharHeight());
+ ranges.setEndSeq(height / getCharHeight());
}
- public void setCurrentTree(NJTree tree)
+ public void setCurrentTree(TreeModel tree)
{
currentTree = tree;
}
- public NJTree getCurrentTree()
+ public TreeModel getCurrentTree()
{
return currentTree;
}
{
getStructureSelectionManager().sendSelection(
new SequenceGroup(getSelectionGroup()),
- new ColumnSelection(getColumnSelection()), this);
+ new ColumnSelection(getColumnSelection()),
+ new HiddenColumns(getAlignment().getHiddenColumns()), this);
}
/**
int seqOffset = findComplementScrollTarget(sr);
if (!sr.isEmpty())
{
- complementPanel.setFollowingComplementScroll(true);
+ complementPanel.setToScrollComplementPanel(false);
complementPanel.scrollToCentre(sr, seqOffset);
+ complementPanel.setToScrollComplementPanel(true);
}
}
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceI;
import jalview.structure.StructureSelectionManager;
+import jalview.viewmodel.ViewportListenerI;
+import jalview.viewmodel.ViewportRanges;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.AdjustmentListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
+import java.beans.PropertyChangeEvent;
import java.util.List;
public class AlignmentPanel extends Panel implements AdjustmentListener,
- AlignmentViewPanel
+ AlignmentViewPanel, ViewportListenerI
{
public AlignViewport av;
AnnotationLabels alabels;
+ ViewportRanges vpRanges;
+
// this value is set false when selection area being dragged
boolean fastPaint = true;
{
alignFrame = null;
av = null;
+ vpRanges = null;
seqPanel = null;
seqPanelHolder = null;
sequenceHolderPanel = null;
alignFrame = af;
this.av = av;
+ vpRanges = av.getRanges();
seqPanel = new SeqPanel(av, this);
idPanel = new IdPanel(av, this);
scalePanel = new ScalePanel(av, this);
@Override
public void componentResized(ComponentEvent evt)
{
- setScrollValues(av.getStartRes(), av.getStartSeq());
+ // reset the viewport ranges when the alignment panel is resized
+ // in particular, this initialises the end residue value when Jalview
+ // is initialised
+ if (av.getWrapAlignment())
+ {
+ int widthInRes = seqPanel.seqCanvas
+ .getWrappedCanvasWidth(seqPanel.seqCanvas.getWidth());
+ vpRanges.setViewportWidth(widthInRes);
+ }
+ else
+ {
+ int widthInRes = seqPanel.seqCanvas.getWidth()
+ / av.getCharWidth();
+ int heightInSeq = seqPanel.seqCanvas.getHeight()
+ / av.getCharHeight();
+
+ vpRanges.setViewportWidth(widthInRes);
+ vpRanges.setViewportHeight(heightInSeq);
+ }
+ // setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
if (getSize().height > 0
&& annotationPanelHolder.getSize().height > 0)
{
}
}
});
+ av.getRanges().addPropertyChangeListener(this);
}
@Override
annotationPanel.repaint();
validate();
repaint();
-
- if (overviewPanel != null)
- {
- overviewPanel.updateOverviewImage();
- }
}
public void setIdWidth(int w, int h)
*/
if (centre)
{
- int offset = (av.getEndRes() - av.getStartRes() + 1) / 2 - 1;
+ int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2 - 1;
start = Math.max(start - offset, 0);
- end = Math.min(end + offset, seq.getEnd() - 1);
+ end = end + offset - 1;
+ // end = Math.min(end + offset, seq.getEnd() - 1);
}
if (start < 0)
int start = -1;
if (av.hasHiddenColumns())
{
- start = av.getColumnSelection().findColumnPosition(ostart);
- end = av.getColumnSelection().findColumnPosition(end);
+ AlignmentI al = av.getAlignment();
+ start = al.getHiddenColumns().findColumnPosition(ostart);
+ end = al.getHiddenColumns().findColumnPosition(end);
if (start == end)
{
- if (!scrollToNearest && !av.getColumnSelection().isVisible(ostart))
+ if (!scrollToNearest && !al.getHiddenColumns().isVisible(ostart))
{
// don't scroll - position isn't visible
return false;
// setScrollValues(start, seqIndex);
// }
// logic copied from jalview.gui.AlignmentPanel:
- if ((startv = av.getStartRes()) >= start)
+ if ((startv = vpRanges.getStartRes()) >= start)
{
/*
* Scroll left to make start of search results visible
*/
setScrollValues(start - 1, seqIndex);
}
- else if ((endv = av.getEndRes()) <= end)
+ else if ((endv = vpRanges.getEndRes()) <= end)
{
/*
* Scroll right to make end of search results visible
*/
setScrollValues(startv + 1 + end - endv, seqIndex);
}
- else if ((starts = av.getStartSeq()) > seqIndex)
+ else if ((starts = vpRanges.getStartSeq()) > seqIndex)
{
/*
* Scroll up to make start of search results visible
*/
- setScrollValues(av.getStartRes(), seqIndex);
+ setScrollValues(vpRanges.getStartRes(), seqIndex);
}
- else if ((ends = av.getEndSeq()) <= seqIndex)
+ else if ((ends = vpRanges.getEndSeq()) <= seqIndex)
{
/*
* Scroll down to make end of search results visible
*/
- setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1);
+ setScrollValues(vpRanges.getStartRes(), starts + seqIndex - ends
+ + 1);
}
/*
* Else results are already visible - no need to scroll
}
else
{
- scrollToWrappedVisible(start);
- }
- if (redrawOverview && overviewPanel != null)
- {
- overviewPanel.setBoxPosition();
+ vpRanges.scrollToWrappedVisible(start);
}
+
paintAlignment(redrawOverview);
return true;
}
- void scrollToWrappedVisible(int res)
- {
- int cwidth = seqPanel.seqCanvas
- .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
- if (res <= av.getStartRes() || res >= (av.getStartRes() + cwidth))
- {
- vscroll.setValue(res / cwidth);
- av.startRes = vscroll.getValue() * cwidth;
- }
- }
-
public OverviewPanel getOverviewPanel()
{
return overviewPanel;
public void setWrapAlignment(boolean wrap)
{
- av.startSeq = 0;
- av.startRes = 0;
+ vpRanges.setStartSeq(0);
+ vpRanges.setStartRes(0);
scalePanelHolder.setVisible(!wrap);
hscroll.setVisible(!wrap);
int vextent = 0;
- // return value is true if the scroll is valid
- public boolean scrollUp(boolean up)
+ public void setScrollValues(int xpos, int ypos)
{
- if (up)
+ int x = xpos;
+ int y = ypos;
+
+ if (av.getWrapAlignment())
{
- if (vscroll.getValue() < 1)
- {
- return false;
- }
- setScrollValues(hscroll.getValue(), vscroll.getValue() - 1);
+ setScrollingForWrappedPanel(x);
}
else
{
- if (vextent + vscroll.getValue() >= av.getAlignment().getHeight())
- {
- return false;
- }
- setScrollValues(hscroll.getValue(), vscroll.getValue() + 1);
- }
-
- repaint();
- return true;
- }
+ int width = av.getAlignment().getWidth();
+ int height = av.getAlignment().getHeight();
- public boolean scrollRight(boolean right)
- {
- if (!right)
- {
- if (hscroll.getValue() < 1)
+ if (av.hasHiddenColumns())
{
- return false;
+ width = av.getAlignment().getHiddenColumns()
+ .findColumnPosition(width);
}
- setScrollValues(hscroll.getValue() - 1, vscroll.getValue());
- }
- else
- {
- if (hextent + hscroll.getValue() >= av.getAlignment().getWidth())
+ if (x < 0)
{
- return false;
+ x = 0;
}
- setScrollValues(hscroll.getValue() + 1, vscroll.getValue());
- }
-
- repaint();
- return true;
- }
-
- public void setScrollValues(int x, int y)
- {
- int width = av.getAlignment().getWidth();
- int height = av.getAlignment().getHeight();
-
- if (av.hasHiddenColumns())
- {
- width = av.getColumnSelection().findColumnPosition(width);
- }
- if (x < 0)
- {
- x = 0;
- }
- ;
-
- hextent = seqPanel.seqCanvas.getSize().width / av.getCharWidth();
- vextent = seqPanel.seqCanvas.getSize().height / av.getCharHeight();
-
- if (hextent > width)
- {
- hextent = width;
- }
- if (vextent > height)
- {
- vextent = height;
- }
+ hextent = seqPanel.seqCanvas.getSize().width / av.getCharWidth();
+ vextent = seqPanel.seqCanvas.getSize().height / av.getCharHeight();
- if ((hextent + x) > width)
- {
- System.err.println("hextent was " + hextent + " and x was " + x);
+ if (hextent > width)
+ {
+ hextent = width;
+ }
- x = width - hextent;
- }
+ if (vextent > height)
+ {
+ vextent = height;
+ }
- if ((vextent + y) > height)
- {
- y = height - vextent;
- }
+ if ((hextent + x) > width)
+ {
+ System.err.println("hextent was " + hextent + " and x was " + x);
- if (y < 0)
- {
- y = 0;
- }
+ x = width - hextent;
+ }
- if (x < 0)
- {
- System.err.println("x was " + x);
- x = 0;
- }
+ if ((vextent + y) > height)
+ {
+ y = height - vextent;
+ }
- av.setStartSeq(y);
+ if (y < 0)
+ {
+ y = 0;
+ }
- int endSeq = y + vextent;
- if (endSeq > av.getAlignment().getHeight())
- {
- endSeq = av.getAlignment().getHeight();
- }
+ if (x < 0)
+ {
+ System.err.println("x was " + x);
+ x = 0;
+ }
- av.setEndSeq(endSeq);
- av.setStartRes(x);
- av.setEndRes((x + (seqPanel.seqCanvas.getSize().width / av
- .getCharWidth())) - 1);
+ hscroll.setValues(x, hextent, 0, width);
+ vscroll.setValues(y, vextent, 0, height);
- hscroll.setValues(x, hextent, 0, width);
- vscroll.setValues(y, vextent, 0, height);
+ // AWT scrollbar does not fire adjustmentValueChanged for setValues
+ // so also call adjustment code!
+ adjustHorizontal(x);
+ adjustVertical(y);
- if (overviewPanel != null)
- {
- overviewPanel.setBoxPosition();
+ sendViewPosition();
}
- sendViewPosition();
-
}
+ /**
+ * Respond to adjustment event when horizontal or vertical scrollbar is
+ * changed
+ *
+ * @param evt
+ * adjustment event encoding whether apvscroll, hscroll or vscroll
+ * changed
+ */
@Override
public void adjustmentValueChanged(AdjustmentEvent evt)
{
- int oldX = av.getStartRes();
- int oldY = av.getStartSeq();
-
+ // Note that this event is NOT fired by the AWT scrollbar when setValues is
+ // called. Instead manually call adjustHorizontal and adjustVertical
+ // directly.
if (evt == null || evt.getSource() == apvscroll)
{
annotationPanel.setScrollOffset(apvscroll.getValue(), false);
alabels.setScrollOffset(apvscroll.getValue(), false);
- // annotationPanel.image=null;
- // alabels.image=null;
- // alabels.repaint();
- // annotationPanel.repaint();
}
if (evt == null || evt.getSource() == hscroll)
{
int x = hscroll.getValue();
- av.setStartRes(x);
- av.setEndRes(x + seqPanel.seqCanvas.getSize().width
- / av.getCharWidth() - 1);
+ adjustHorizontal(x);
}
if (evt == null || evt.getSource() == vscroll)
{
int offy = vscroll.getValue();
- if (av.getWrapAlignment())
- {
- int rowSize = seqPanel.seqCanvas
- .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
- av.setStartRes(vscroll.getValue() * rowSize);
- av.setEndRes((vscroll.getValue() + 1) * rowSize);
- }
- else
- {
- av.setStartSeq(offy);
- av.setEndSeq(offy + seqPanel.seqCanvas.getSize().height
- / av.getCharHeight());
- }
+ adjustVertical(offy);
}
- if (overviewPanel != null)
+ }
+
+ private void adjustHorizontal(int x)
+ {
+ int oldX = vpRanges.getStartRes();
+ int oldwidth = vpRanges.getViewportWidth();
+ int width = seqPanel.seqCanvas.getWidth() / av.getCharWidth();
+
+ // if we're scrolling to the position we're already at, stop
+ // this prevents infinite recursion of events when the scroll/viewport
+ // ranges values are the same
+ if ((x == oldX) && (width == oldwidth))
{
- overviewPanel.setBoxPosition();
+ return;
}
+ vpRanges.setViewportStartAndWidth(x, width);
- int scrollX = av.startRes - oldX;
- int scrollY = av.startSeq - oldY;
-
- if (av.getWrapAlignment() || !fastPaint || av.MAC)
+ if (av.getWrapAlignment() || !fastPaint)
{
repaint();
}
- else
+ sendViewPosition();
+ }
+
+ private void adjustVertical(int offy)
+ {
+ int oldX = vpRanges.getStartRes();
+ int oldwidth = vpRanges.getViewportWidth();
+ int oldY = vpRanges.getStartSeq();
+ int oldheight = vpRanges.getViewportHeight();
+
+ if (av.getWrapAlignment())
{
- // Make sure we're not trying to draw a panel
- // larger than the visible window
- if (scrollX > av.endRes - av.startRes)
+ int rowSize = seqPanel.seqCanvas
+ .getWrappedCanvasWidth(seqPanel.seqCanvas.getWidth());
+
+ // if we're scrolling to the position we're already at, stop
+ // this prevents infinite recursion of events when the scroll/viewport
+ // ranges values are the same
+ if ((offy * rowSize == oldX) && (oldwidth == rowSize))
{
- scrollX = av.endRes - av.startRes;
+ return;
}
- else if (scrollX < av.startRes - av.endRes)
+ else if (offy > -1)
{
- scrollX = av.startRes - av.endRes;
+ vpRanges.setViewportStartAndWidth(offy * rowSize, rowSize);
}
+ }
+ else
+ {
+ int height = seqPanel.seqCanvas.getHeight() / av.getCharHeight();
- idPanel.idCanvas.fastPaint(scrollY);
- seqPanel.seqCanvas.fastPaint(scrollX, scrollY);
-
- scalePanel.repaint();
- if (av.isShowAnnotation())
+ // if we're scrolling to the position we're already at, stop
+ // this prevents infinite recursion of events when the scroll/viewport
+ // ranges values are the same
+ if ((offy == oldY) && (height == oldheight))
{
- annotationPanel.fastPaint(av.getStartRes() - oldX);
+ return;
}
+ vpRanges.setViewportStartAndHeight(offy, height);
}
- sendViewPosition();
-
- /*
- * If there is one, scroll the (Protein/cDNA) complementary alignment to
- * match, unless we are ourselves doing that.
- */
- if (isFollowingComplementScroll())
- {
- setFollowingComplementScroll(false);
- }
- else
+ if (av.getWrapAlignment() || !fastPaint)
{
- AlignmentPanel ap = getComplementPanel();
- av.scrollComplementaryAlignment(ap);
+ repaint();
}
-
+ sendViewPosition();
}
/**
* This is like AlignmentI.findIndex(seq) but here we are matching the
* dataset sequence not the aligned sequence
*/
- int sequenceIndex = 0;
boolean matched = false;
for (SequenceI seq : seqs)
{
matched = true;
break;
}
- sequenceIndex++;
}
if (!matched)
{
* Scroll to position but centring the target residue. Also set a state flag
* to prevent adjustmentValueChanged performing this recursively.
*/
- setFollowingComplementScroll(true);
- // this should be scrollToPosition(sr,verticalOffset,
scrollToPosition(sr, seqOffset, true, true);
}
private void sendViewPosition()
{
StructureSelectionManager.getStructureSelectionManager(av.applet)
- .sendViewPosition(this, av.startRes, av.endRes, av.startSeq,
- av.endSeq);
+ .sendViewPosition(this, vpRanges.getStartRes(),
+ vpRanges.getEndRes(), vpRanges.getStartSeq(),
+ vpRanges.getEndSeq());
}
/**
idPanel.idCanvas.setSize(d.width, canvasHeight);
}
- if (av.getWrapAlignment())
- {
- int maxwidth = av.getAlignment().getWidth();
-
- if (av.hasHiddenColumns())
- {
- maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
- }
-
- int canvasWidth = seqPanel.seqCanvas
- .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
-
- if (canvasWidth > 0)
- {
- int max = maxwidth / canvasWidth;
- vscroll.setMaximum(1 + max);
- vscroll.setUnitIncrement(1);
- vscroll.setVisibleAmount(1);
- }
- }
- else
- {
- setScrollValues(av.getStartRes(), av.getStartSeq());
- }
+ setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
seqPanel.seqCanvas.repaint();
idPanel.idCanvas.repaint();
}
+ /*
+ * Set vertical scroll bar parameters for wrapped panel
+ * @param res
+ * the residue to scroll to
+ */
+ private void setScrollingForWrappedPanel(int res)
+ {
+ // get the width of the alignment in residues
+ int maxwidth = av.getAlignment().getWidth();
+ if (av.hasHiddenColumns())
+ {
+ maxwidth = av.getAlignment().getHiddenColumns()
+ .findColumnPosition(maxwidth) - 1;
+ }
+
+ // get the width of the canvas in residues
+ int canvasWidth = seqPanel.seqCanvas
+ .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
+ if (canvasWidth > 0)
+ {
+ // position we want to scroll to is number of canvasWidth's to get there
+ int current = res / canvasWidth;
+
+ // max scroll position: add one because extent is 1 and scrollbar value
+ // can only be set to at most max - extent
+ int max = maxwidth / canvasWidth + 1;
+ vscroll.setUnitIncrement(1);
+ vscroll.setValues(current, 1, 0, max);
+ }
+ }
+
protected Panel sequenceHolderPanel = new Panel();
protected Scrollbar vscroll = new Scrollbar();
/*
* Flag set while scrolling to follow complementary cDNA/protein scroll. When
- * true, suppresses invoking the same method recursively.
+ * false, suppresses invoking the same method recursively.
*/
- private boolean followingComplementScroll;
+ private boolean scrollComplementaryPanel = true;
private void jbInit() throws Exception
{
*
* @param b
*/
- protected void setFollowingComplementScroll(boolean b)
+ protected void setToScrollComplementPanel(boolean b)
+ {
+ this.scrollComplementaryPanel = b;
+ }
+
+ /**
+ * Get whether to scroll complement panel
+ *
+ * @return true if cDNA/protein complement panels should be scrolled
+ */
+ protected boolean isSetToScrollComplementPanel()
{
- this.followingComplementScroll = b;
+ return this.scrollComplementaryPanel;
}
- protected boolean isFollowingComplementScroll()
+ @Override
+ /**
+ * Property change event fired when a change is made to the viewport ranges
+ * object associated with this alignment panel's viewport
+ */
+ public void propertyChange(PropertyChangeEvent evt)
{
- return this.followingComplementScroll;
+ // update this panel's scroll values based on the new viewport ranges values
+ int x = vpRanges.getStartRes();
+ int y = vpRanges.getStartSeq();
+ setScrollValues(x, y);
+
+ // now update any complementary alignment (its viewport ranges object
+ // is different so does not get automatically updated)
+ if (isSetToScrollComplementPanel())
+ {
+ setToScrollComplementPanel(false);
+ av.scrollComplementaryAlignment(getComplementPanel());
+ setToScrollComplementPanel(true);
+ }
+
}
}
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
-import java.util.Hashtable;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Vector;
public class AnnotationColourChooser extends Panel implements
ColourSchemeI oldcs;
- Hashtable oldgroupColours;
+ Map<SequenceGroup, ColourSchemeI> oldgroupColours;
- jalview.datamodel.AlignmentAnnotation currentAnnotation;
+ /*
+ * map from annotation to its menu item display label
+ * - so we know which item to pre-select on restore
+ */
+ private Map<AlignmentAnnotation, String> annotationLabels;
+
+ AlignmentAnnotation currentAnnotation;
boolean adjusting = false;
oldcs = av.getGlobalColourScheme();
if (av.getAlignment().getGroups() != null)
{
- oldgroupColours = new Hashtable();
+ oldgroupColours = new HashMap<SequenceGroup, ColourSchemeI>();
for (SequenceGroup sg : ap.av.getAlignment().getGroups())
{
- if (sg.getColourScheme() != null)
- {
- oldgroupColours.put(sg, sg.getColourScheme());
- }
- else
- {
- oldgroupColours.put(sg, "null");
- }
+ oldgroupColours.put(sg, sg.getColourScheme());
}
}
this.av = av;
// seqAssociated.setState(acg.isSeqAssociated());
}
- Vector<String> list = new Vector<String>();
- int index = 1;
- for (int i = 0; i < anns.length; i++)
- {
- String label = anns[i].label;
- if (anns[i].sequenceRef != null)
- {
- label = label + "_" + anns[i].sequenceRef.getName();
- }
- if (!list.contains(label))
- {
- list.addElement(label);
- }
- else
- {
- list.addElement(label + "_" + (index++));
- }
- }
+ Vector<String> list = getAnnotationItems();
for (int i = 0; i < list.size(); i++)
{
if (oldcs instanceof AnnotationColourGradient)
{
AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
- annotations.select(acg.getAnnotation());
+ String label = annotationLabels.get(acg.getAnnotation());
+ annotations.select(label);
switch (acg.getAboveThreshold())
{
case AnnotationColourGradient.NO_THRESHOLD:
MessageManager
.getString("error.implementation_error_dont_know_threshold_annotationcolourgradient"));
}
- thresholdIsMin.setState(acg.thresholdIsMinMax);
+ thresholdIsMin.setState(acg.isThresholdIsMinMax());
thresholdValue.setText("" + acg.getAnnotationThreshold());
}
validate();
}
+ /**
+ * Builds and returns a list of menu items (display text) for choice of
+ * annotation. Also builds a map between annotations and their display labels.
+ *
+ * @return
+ */
+ protected Vector<String> getAnnotationItems()
+ {
+ // TODO remove duplication with gui.AnnotationRowFilter
+ // TODO add 'per sequence only' option / parameter
+
+ annotationLabels = new HashMap<AlignmentAnnotation, String>();
+ Vector<String> list = new Vector<String>();
+ AlignmentAnnotation[] anns = av.getAlignment().getAlignmentAnnotation();
+ if (anns == null)
+ {
+ return list;
+ }
+ int index = 1;
+ for (int i = 0; i < anns.length; i++)
+ {
+ String label = anns[i].label;
+ if (anns[i].sequenceRef != null)
+ {
+ /*
+ * be helpful and include sequence id in label for
+ * sequence-associated annotation (JAL-2236)
+ */
+ label = label + "_" + anns[i].sequenceRef.getName();
+ }
+ if (!list.contains(label))
+ {
+ list.addElement(label);
+ annotationLabels.put(anns[i], label);
+ }
+ else
+ {
+ label = label + "_" + (index++);
+ list.addElement(label);
+ annotationLabels.put(anns[i], label);
+ }
+ }
+ return list;
+ }
+
private void setDefaultMinMax()
{
minColour.setBackground(av.applet.getDefaultColourParameter(
acg.setPredefinedColours(true);
}
- acg.thresholdIsMinMax = thresholdIsMin.getState();
+ acg.setThresholdIsMinMax(thresholdIsMin.getState());
av.setGlobalColourScheme(acg);
{
for (SequenceGroup sg : ap.av.getAlignment().getGroups())
{
-
if (sg.getColourScheme() == null)
{
continue;
currentAnnotation, minColour.getBackground(), maxColour
.getBackground(), aboveThreshold));
}
-
}
}
{
for (SequenceGroup sg : ap.av.getAlignment().getGroups())
{
- Object cs = oldgroupColours.get(sg);
- if (cs instanceof ColourSchemeI)
- {
- sg.setColourScheme((ColourSchemeI) cs);
- }
- else
- {
- // probably the "null" string we set it to if it was null originally.
- sg.setColourScheme(null);
- }
+ sg.setColourScheme(oldgroupColours.get(sg));
}
}
ap.paintAlignment(true);
-
}
@Override
package jalview.appletgui;
import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.schemes.AnnotationColourGradient;
import jalview.util.MessageManager;
import jalview.viewmodel.annotationfilter.AnnotationFilterParameter;
private int actionOption = ACTION_OPTION_SELECT;
- private ColumnSelection oldColumnSelection;
+ private HiddenColumns oldHiddenColumns;
public AnnotationColumnChooser()
{
{
return;
}
- setOldColumnSelection(av.getColumnSelection());
+ setOldHiddenColumns(av.getAlignment().getHiddenColumns());
adjusting = true;
Vector<String> list = new Vector<String>();
int index = 1;
}
populateThresholdComboBox(threshold);
-
+ AnnotationColumnChooser lastChooser = av
+ .getAnnotationColumnSelectionState();
// restore Object state from the previous session if one exists
- if (av.getAnnotationColumnSelectionState() != null)
+ if (lastChooser != null)
{
- currentSearchPanel = av.getAnnotationColumnSelectionState()
+ currentSearchPanel = lastChooser
.getCurrentSearchPanel();
- currentStructureFilterPanel = av.getAnnotationColumnSelectionState()
+ currentStructureFilterPanel = lastChooser
.getCurrentStructureFilterPanel();
- annotations.select(av.getAnnotationColumnSelectionState()
+ annotations.select(lastChooser
.getAnnotations().getSelectedIndex());
- threshold.select(av.getAnnotationColumnSelectionState()
+ threshold.select(lastChooser
.getThreshold().getSelectedIndex());
- actionOption = av.getAnnotationColumnSelectionState()
+ actionOption = lastChooser
.getActionOption();
+ percentThreshold.setState(lastChooser.percentThreshold.getState());
}
try
thresholdValue.setEnabled(false);
thresholdValue.setColumns(7);
+ thresholdValue.setCaretPosition(0);
ok.addActionListener(this);
cancel.addActionListener(this);
// thresholdPanel.setFont(JvSwingUtils.getLabelFont());
// thresholdPanel.setLayout(new MigLayout("", "[left][right]", "[][]"));
+ percentThreshold.setLabel("As percentage");
+ percentThreshold.addItemListener(this);
+
actionPanel.setBackground(Color.white);
// actionPanel.setFont(JvSwingUtils.getLabelFont());
thresholdPanel.add(getThreshold());
thresholdPanel.add(slider);
thresholdPanel.add(thresholdValue);
+ thresholdPanel.add(percentThreshold);
actionPanel.add(ok);
actionPanel.add(cancel);
@SuppressWarnings("unchecked")
public void reset()
{
- if (this.getOldColumnSelection() != null)
+ if (this.getOldHiddenColumns() != null)
{
av.getColumnSelection().clear();
if (av.getAnnotationColumnSelectionState() != null)
{
- ColumnSelection oldSelection = av
+ HiddenColumns oldHidden = av
.getAnnotationColumnSelectionState()
- .getOldColumnSelection();
- if (oldSelection != null && oldSelection.getHiddenColumns() != null
- && !oldSelection.getHiddenColumns().isEmpty())
+ .getOldHiddenColumns();
+ if (oldHidden != null && oldHidden.getHiddenRegions() != null
+ && !oldHidden.getHiddenRegions().isEmpty())
{
- for (Iterator<int[]> itr = oldSelection.getHiddenColumns()
+ for (Iterator<int[]> itr = oldHidden.getHiddenRegions()
.iterator(); itr.hasNext();)
{
int positions[] = itr.next();
av.hideColumns(positions[0], positions[1]);
}
}
- av.setColumnSelection(oldSelection);
+ av.getAlignment().setHiddenColumns(oldHidden);
}
ap.paintAlignment(true);
}
{
if (!adjusting)
{
- thresholdValue.setText((slider.getValue() / 1000f) + "");
+ setThresholdValueText();
valueChanged(!sliderDragging);
}
}
slider.setEnabled(true);
thresholdValue.setEnabled(true);
+ percentThreshold.setEnabled(true);
if (selectedThresholdItem == AnnotationColourGradient.NO_THRESHOLD)
{
slider.setEnabled(false);
thresholdValue.setEnabled(false);
thresholdValue.setText("");
+ percentThreshold.setEnabled(false);
// build filter params
}
else if (selectedThresholdItem != AnnotationColourGradient.NO_THRESHOLD)
slider.setMinimum((int) (getCurrentAnnotation().graphMin * 1000));
slider.setMaximum((int) (getCurrentAnnotation().graphMax * 1000));
slider.setValue((int) (getCurrentAnnotation().threshold.value * 1000));
- thresholdValue.setText(getCurrentAnnotation().threshold.value + "");
+ setThresholdValueText();
// slider.setMajorTickSpacing((int) (range / 10f));
slider.setEnabled(true);
thresholdValue.setEnabled(true);
+ percentThreshold.setEnabled(true);
adjusting = false;
// build filter params
filterParams
.setThresholdType(AnnotationFilterParameter.ThresholdType.NO_THRESHOLD);
- if (getCurrentAnnotation().graph != AlignmentAnnotation.NO_GRAPH)
+ if (getCurrentAnnotation().isQuantitative())
{
filterParams
.setThresholdValue(getCurrentAnnotation().threshold.value);
ap.paintAlignment(true);
}
- public ColumnSelection getOldColumnSelection()
+ public HiddenColumns getOldHiddenColumns()
{
- return oldColumnSelection;
+ return oldHiddenColumns;
}
- public void setOldColumnSelection(ColumnSelection currentColumnSelection)
+ public void setOldHiddenColumns(HiddenColumns currentHiddenColumns)
{
- if (currentColumnSelection != null)
+ if (currentHiddenColumns != null)
{
- this.oldColumnSelection = new ColumnSelection(currentColumnSelection);
+ this.oldHiddenColumns = new HiddenColumns(currentHiddenColumns);
}
}
{
threshold_actionPerformed(null);
}
+ else if (e.getSource() == percentThreshold)
+ {
+ if (!adjusting)
+ {
+ percentageValue_actionPerformed();
+ }
+
+ }
}
public void selectedAnnotationChanged()
{
String currentView = AnnotationColumnChooser.NO_GRAPH_VIEW;
if (av.getAlignment().getAlignmentAnnotation()[getAnnotations()
- .getSelectedIndex()].graph != AlignmentAnnotation.NO_GRAPH)
+ .getSelectedIndex()].isQuantitative())
{
currentView = AnnotationColumnChooser.GRAPH_VIEW;
}
@Override
public void actionPerformed(ActionEvent evt)
{
- if (evt.getSource() == thresholdValue)
- {
- try
- {
- float f = new Float(thresholdValue.getText()).floatValue();
- slider.setValue((int) (f * 1000));
- adjustmentValueChanged(null);
- } catch (NumberFormatException ex)
- {
- }
- }
- else if (evt.getSource() == ok)
+ if (evt.getSource() == ok)
{
ok_actionPerformed(null);
}
av.calcPanelHeight());
f.height += dif;
ap.seqPanelHolder.setPreferredSize(f);
- ap.setScrollValues(av.getStartRes(), av.getStartSeq());
+ ap.setScrollValues(av.getRanges().getStartRes(), av.getRanges()
+ .getStartSeq());
ap.validate();
// ap.paintAlignment(true);
ap.addNotify();
if (av.hasHiddenColumns())
{
jalview.appletgui.AlignFrame.copiedHiddenColumns = new Vector();
- for (int[] region : av.getColumnSelection().getHiddenColumns())
+ for (int[] region : av.getAlignment().getHiddenColumns()
+ .getHiddenRegions())
{
jalview.appletgui.AlignFrame.copiedHiddenColumns
.addElement(new int[] { region[0], region[1] });
import jalview.util.Comparison;
import jalview.util.MessageManager;
import jalview.util.Platform;
+import jalview.viewmodel.ViewportListenerI;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
public class AnnotationPanel extends Panel implements AwtRenderPanelI,
AdjustmentListener, ActionListener, MouseListener,
- MouseMotionListener
+ MouseMotionListener, ViewportListenerI
{
AlignViewport av;
{
this.av = av;
renderer = new AnnotationRenderer();
+ av.getRanges().addPropertyChangeListener(this);
}
@Override
{
for (int index : av.getColumnSelection().getSelected())
{
- if (av.getColumnSelection().isVisible(index))
+ if (av.getAlignment().getHiddenColumns().isVisible(index))
{
anot[index] = null;
}
{
// TODO: JAL-2001 - provide a fast method to list visible selected
// columns
- if (!av.getColumnSelection().isVisible(index))
+ if (!av.getAlignment().getHiddenColumns().isVisible(index))
{
continue;
}
for (int index : av.getColumnSelection().getSelected())
{
- if (!av.getColumnSelection().isVisible(index))
+ if (!av.getAlignment().getHiddenColumns().isVisible(index))
{
continue;
}
for (int index : av.getColumnSelection().getSelected())
{
- if (!av.getColumnSelection().isVisible(index))
+ if (!av.getAlignment().getHiddenColumns().isVisible(index))
{
continue;
}
}
}
- int column = evt.getX() / av.getCharWidth() + av.getStartRes();
+ int column = evt.getX() / av.getCharWidth()
+ + av.getRanges().getStartRes();
if (av.hasHiddenColumns())
{
- column = av.getColumnSelection().adjustForHiddenColumns(column);
+ column = av.getAlignment().getHiddenColumns()
+ .adjustForHiddenColumns(column);
}
if (row > -1 && column < aa[row].annotations.length
gg.setColor(Color.white);
gg.fillRect(0, 0, getSize().width, getSize().height);
- drawComponent(gg, av.startRes, av.endRes + 1);
+ drawComponent(gg, av.getRanges().getStartRes(), av.getRanges()
+ .getEndRes() + 1);
g.drawImage(image, 0, 0, this);
}
gg.copyArea(0, 0, imgWidth, getSize().height,
-horizontal * av.getCharWidth(), 0);
- int sr = av.startRes, er = av.endRes + 1, transX = 0;
+ int sr = av.getRanges().getStartRes(), er = av.getRanges().getEndRes() + 1, transX = 0;
if (horizontal > 0) // scrollbar pulled right, image to the left
{
return null;
}
}
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ // Respond to viewport range changes (e.g. alignment panel was scrolled)
+ if (evt.getPropertyName().equals("startres")
+ || evt.getPropertyName().equals("endres"))
+ {
+ fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
+ }
+ }
}
import java.awt.Scrollbar;
import java.awt.TextField;
import java.awt.event.ActionEvent;
-import java.util.Vector;
@SuppressWarnings("serial")
public abstract class AnnotationRowFilter extends Panel
protected Scrollbar slider = new Scrollbar(Scrollbar.HORIZONTAL);
+ protected Checkbox percentThreshold = new Checkbox();
+
protected TextField thresholdValue = new TextField(20);
protected Frame frame;
updateView();
}
+ /**
+ * update the text field from the threshold slider. preserves state of
+ * 'adjusting' so safe to call in init.
+ */
+ protected void setThresholdValueText()
+ {
+ boolean oldadj = adjusting;
+ adjusting = true;
+ if (percentThreshold.getState())
+ {
+ double scl = slider.getMaximum() - slider.getMinimum();
+ scl = (slider.getValue() - slider.getMinimum()) / scl;
+ thresholdValue.setText(100f * scl + "");
+ }
+ else
+ {
+ thresholdValue.setText((slider.getValue() / 1000f) + "");
+ }
+ thresholdValue.setCaretPosition(0);
+ adjusting = oldadj;
+ }
+
public void thresholdValue_actionPerformed(ActionEvent e)
{
try
{
float f = Float.parseFloat(thresholdValue.getText());
- slider.setValue((int) (f * 1000));
- updateView();
+ if (percentThreshold.getState())
+ {
+ int pos = slider.getMinimum()
+ + (int) ((slider.getMaximum() - slider.getMinimum()) * f / 100f);
+ slider.setValue(pos);
+ }
+ else
+ {
+ slider.setValue((int) (f * 1000));
+ }
+ valueChanged(false);
} catch (NumberFormatException ex)
{
}
}
+ protected void percentageValue_actionPerformed()
+ {
+ setThresholdValueText();
+ }
+
protected void populateThresholdComboBox(Choice threshold)
{
threshold.addItem(MessageManager
public jalview.api.FeatureRenderer getFeatureRenderer(
AlignmentViewPanel alignment)
{
- AlignmentPanel ap = (AlignmentPanel) alignment;
- if (appletJmolBinding.ap.av.isShowSequenceFeatures())
- {
- if (appletJmolBinding.fr == null)
- {
- appletJmolBinding.fr = new jalview.appletgui.FeatureRenderer(
- appletJmolBinding.ap.av);
- }
-
- appletJmolBinding.fr
- .transferSettings(appletJmolBinding.ap.seqPanel.seqCanvas
- .getFeatureRenderer());
- }
-
- return appletJmolBinding.fr;
+ return appletJmolBinding.ap.getFeatureRenderer();
}
@Override
import jalview.api.FeaturesSourceI;
import jalview.bin.JalviewLite;
import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
import jalview.io.AlignmentFileReaderI;
if (source instanceof ComplexAlignFile)
{
- ColumnSelection colSel = ((ComplexAlignFile) source)
- .getColumnSelection();
+ HiddenColumns colSel = ((ComplexAlignFile) source)
+ .getHiddenColumns();
SequenceI[] hiddenSeqs = ((ComplexAlignFile) source)
.getHiddenSequences();
boolean showSeqFeatures = ((ComplexAlignFile) source)
@Override
public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
{
- AlignmentPanel ap = (AlignmentPanel) alignment;
- if (ap.av.isShowSequenceFeatures())
+ AlignmentPanel alignPanel = (AlignmentPanel) alignment;
+ if (alignPanel.av.isShowSequenceFeatures())
{
- return ap.getFeatureRenderer();
+ return alignPanel.getFeatureRenderer();
}
else
{
import java.awt.Choice;
import java.awt.Color;
import java.awt.Dimension;
+import java.awt.FlowLayout;
import java.awt.Font;
+import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.awt.event.TextEvent;
+import java.awt.event.TextListener;
import java.util.Hashtable;
+import java.util.List;
/**
* DOCUMENT ME!
public class FeatureRenderer extends
jalview.renderer.seqfeatures.FeatureRenderer
{
+ /*
+ * creating a new feature defaults to the type and group as
+ * the last one created
+ */
+ static String lastFeatureAdded = "feature_1";
+
+ static String lastFeatureGroupAdded = "Jalview";
// Holds web links for feature groups and feature types
// in the form label|link
}
- static String lastFeatureAdded;
-
- static String lastFeatureGroupAdded;
-
- static String lastDescriptionAdded;
-
int featureIndex = 0;
boolean deleteFeature = false;
}
- boolean amendFeatures(final SequenceI[] sequences,
- final SequenceFeature[] features, boolean newFeatures,
+ /**
+ * Shows a dialog allowing the user to create, or amend or delete, sequence
+ * features. If null in the supplied feature(s), feature type and group
+ * default to those for the last feature created (with initial defaults of
+ * "feature_1" and "Jalview").
+ *
+ * @param sequences
+ * @param features
+ * @param create
+ * @param ap
+ * @return
+ */
+ boolean amendFeatures(final List<SequenceI> sequences,
+ final List<SequenceFeature> features, boolean create,
final AlignmentPanel ap)
{
- Panel bigPanel = new Panel(new BorderLayout());
+ final Panel bigPanel = new Panel(new BorderLayout());
final TextField name = new TextField(16);
- final TextField source = new TextField(16);
+ final TextField group = new TextField(16);
final TextArea description = new TextArea(3, 35);
final TextField start = new TextField(8);
final TextField end = new TextField(8);
Button deleteButton = new Button("Delete");
deleteFeature = false;
+ name.addTextListener(new TextListener()
+ {
+ @Override
+ public void textValueChanged(TextEvent e)
+ {
+ warnIfTypeHidden(ap.alignFrame, name.getText());
+ }
+ });
+ group.addTextListener(new TextListener()
+ {
+ @Override
+ public void textValueChanged(TextEvent e)
+ {
+ warnIfGroupHidden(ap.alignFrame, group.getText());
+ }
+ });
colourPanel = new FeatureColourPanel();
colourPanel.setSize(110, 15);
final FeatureRenderer fr = this;
// /////////////////////////////////////
// /MULTIPLE FEATURES AT SELECTED RESIDUE
- if (!newFeatures && features.length > 1)
+ if (!create && features.size() > 1)
{
panel = new Panel(new GridLayout(4, 1));
tmp = new Panel();
tmp.add(new Label("Select Feature: "));
overlaps = new Choice();
- for (int i = 0; i < features.length; i++)
+ for (SequenceFeature sf : features)
{
- String item = features[i].getType() + "/" + features[i].getBegin()
- + "-" + features[i].getEnd();
-
- if (features[i].getFeatureGroup() != null)
+ String item = sf.getType() + "/" + sf.getBegin() + "-"
+ + sf.getEnd();
+ if (sf.getFeatureGroup() != null)
{
- item += " (" + features[i].getFeatureGroup() + ")";
+ item += " (" + sf.getFeatureGroup() + ")";
}
-
overlaps.addItem(item);
}
if (index != -1)
{
featureIndex = index;
- name.setText(features[index].getType());
- description.setText(features[index].getDescription());
- source.setText(features[index].getFeatureGroup());
- start.setText(features[index].getBegin() + "");
- end.setText(features[index].getEnd() + "");
+ SequenceFeature sf = features.get(index);
+ name.setText(sf.getType());
+ description.setText(sf.getDescription());
+ group.setText(sf.getFeatureGroup());
+ start.setText(sf.getBegin() + "");
+ end.setText(sf.getEnd() + "");
SearchResultsI highlight = new SearchResults();
- highlight.addResult(sequences[0], features[index].getBegin(),
- features[index].getEnd());
+ highlight.addResult(sequences.get(0), sf.getBegin(),
+ sf.getEnd());
ap.seqPanel.seqCanvas.highlightSearchResults(highlight);
FeatureColourI col = getFeatureStyle(name.getText());
if (col == null)
{
- Color generatedColour = ColorUtils
- .createColourFromName(name.getText());
+ Color generatedColour = ColorUtils.createColourFromName(name
+ .getText());
col = new FeatureColour(generatedColour);
}
tmp = new Panel();
panel.add(tmp);
tmp.add(new Label(MessageManager.getString("label.group:"), Label.RIGHT));
- tmp.add(source);
+ tmp.add(group);
tmp = new Panel();
panel.add(tmp);
Label.RIGHT));
panel.add(new ScrollPane().add(description));
- if (!newFeatures)
+ if (!create)
{
bigPanel.add(panel, BorderLayout.SOUTH);
bigPanel.add(panel, BorderLayout.CENTER);
}
- if (lastFeatureAdded == null)
- {
- if (features[0].type != null)
- {
- lastFeatureAdded = features[0].type;
- }
- else
- {
- lastFeatureAdded = "feature_1";
- }
- }
-
- if (lastFeatureGroupAdded == null)
- {
- if (features[0].featureGroup != null)
- {
- lastFeatureGroupAdded = features[0].featureGroup;
- }
- else
- {
- lastFeatureAdded = "Jalview";
- }
- }
-
- String title = newFeatures ? MessageManager
+ /*
+ * use defaults for type and group (and update them on Confirm) only
+ * if feature type has not been supplied by the caller
+ * (e.g. for Amend, or create features from Find)
+ */
+ SequenceFeature firstFeature = features.get(0);
+ boolean useLastDefaults = firstFeature.getType() == null;
+ String featureType = useLastDefaults ? lastFeatureAdded : firstFeature
+ .getType();
+ String featureGroup = useLastDefaults ? lastFeatureGroupAdded
+ : firstFeature.getFeatureGroup();
+
+ String title = create ? MessageManager
.getString("label.create_new_sequence_features")
: MessageManager.formatMessage("label.amend_delete_features",
- new String[] { sequences[0].getName() });
+ new String[] { sequences.get(0).getName() });
final JVDialog dialog = new JVDialog(ap.alignFrame, title, true, 385,
240);
dialog.setMainPanel(bigPanel);
- if (newFeatures)
- {
- name.setText(lastFeatureAdded);
- source.setText(lastFeatureGroupAdded);
- }
- else
+ name.setText(featureType);
+ group.setText(featureGroup);
+
+ if (!create)
{
dialog.ok.setLabel(MessageManager.getString("label.amend"));
dialog.buttonPanel.add(deleteButton, 1);
dialog.setVisible(false);
}
});
- name.setText(features[0].getType());
- source.setText(features[0].getFeatureGroup());
}
- start.setText(features[0].getBegin() + "");
- end.setText(features[0].getEnd() + "");
- description.setText(features[0].getDescription());
+ start.setText(firstFeature.getBegin() + "");
+ end.setText(firstFeature.getEnd() + "");
+ description.setText(firstFeature.getDescription());
// lookup (or generate) the feature colour
FeatureColourI fcol = getFeatureStyle(name.getText());
// simply display the feature color in a box
FeaturesFile ffile = new FeaturesFile();
- if (dialog.accept)
- {
- // This ensures that the last sequence
- // is refreshed and new features are rendered
- lastSeq = null;
- lastFeatureAdded = name.getText().trim();
- lastFeatureGroupAdded = source.getText().trim();
- lastDescriptionAdded = description.getText().replace('\n', ' ');
- }
-
- if (lastFeatureGroupAdded != null && lastFeatureGroupAdded.length() < 1)
+ /*
+ * only update default type and group if we used defaults
+ */
+ String enteredType = name.getText().trim();
+ if (dialog.accept && useLastDefaults)
{
- lastFeatureGroupAdded = null;
+ lastFeatureAdded = enteredType;
+ lastFeatureGroupAdded = group.getText().trim();
}
- if (!newFeatures)
+ if (!create)
{
-
- SequenceFeature sf = features[featureIndex];
+ SequenceFeature sf = features.get(featureIndex);
if (dialog.accept)
{
- sf.type = lastFeatureAdded;
- sf.featureGroup = lastFeatureGroupAdded;
- sf.description = lastDescriptionAdded;
+ sf.type = enteredType;
+ sf.featureGroup = group.getText().trim();
+ if (sf.featureGroup != null && sf.featureGroup.length() < 1)
+ {
+ sf.featureGroup = null;
+ }
+ sf.description = description.getText().replace('\n', ' ');
if (!colourPanel.isGcol)
{
// update colour - otherwise its already done.
sf.end = Integer.parseInt(end.getText());
} catch (NumberFormatException ex)
{
+ //
}
+ boolean typeOrGroupChanged = (!featureType.equals(sf.type) || !featureGroup
+ .equals(sf.featureGroup));
ffile.parseDescriptionHTML(sf, false);
- setVisible(lastFeatureAdded); // if user edited name then make sure new
- // type is visible
+ if (typeOrGroupChanged)
+ {
+ featuresAdded();
+ }
}
if (deleteFeature)
{
- sequences[0].deleteFeature(sf);
+ sequences.get(0).deleteFeature(sf);
+ // ensure Feature Settings reflects removal of feature / group
+ featuresAdded();
}
-
}
else
{
+ /*
+ * adding feature(s)
+ */
if (dialog.accept && name.getText().length() > 0)
{
- for (int i = 0; i < sequences.length; i++)
+ for (int i = 0; i < sequences.size(); i++)
{
- features[i].type = lastFeatureAdded;
- features[i].featureGroup = lastFeatureGroupAdded;
- features[i].description = lastDescriptionAdded;
- sequences[i].addSequenceFeature(features[i]);
- ffile.parseDescriptionHTML(features[i], false);
+ features.get(i).type = enteredType;
+ features.get(i).featureGroup = group.getText().trim();
+ features.get(i).description = description.getText()
+ .replace('\n', ' ');
+ sequences.get(i).addSequenceFeature(features.get(i));
+ ffile.parseDescriptionHTML(features.get(i), false);
}
Color newColour = colourPanel.getBackground();
// setColour(lastFeatureAdded, fcol);
- if (lastFeatureGroupAdded != null)
- {
- setGroupVisibility(lastFeatureGroupAdded, true);
- }
- setColour(lastFeatureAdded, new FeatureColour(newColour)); // was fcol
- setVisible(lastFeatureAdded);
- findAllFeatures(false); // different to original applet behaviour ?
- // findAllFeatures();
+ setColour(enteredType, new FeatureColour(newColour)); // was fcol
+ featuresAdded();
}
else
{
return true;
}
+
+ protected void warnIfGroupHidden(Frame frame, String group)
+ {
+ if (featureGroups.containsKey(group) && !featureGroups.get(group))
+ {
+ String msg = MessageManager.formatMessage("label.warning_hidden",
+ MessageManager.getString("label.group"), group);
+ showWarning(frame, msg);
+ }
+ }
+
+ protected void warnIfTypeHidden(Frame frame, String type)
+ {
+ if (getRenderOrder().contains(type))
+ {
+ if (!showFeatureOfType(type))
+ {
+ String msg = MessageManager.formatMessage("label.warning_hidden",
+ MessageManager.getString("label.feature_type"), type);
+ showWarning(frame, msg);
+ }
+ }
+ }
+
+ /**
+ * @param frame
+ * @param msg
+ */
+ protected void showWarning(Frame frame, String msg)
+ {
+ JVDialog d = new JVDialog(frame, "", true, 350, 200);
+ Panel mp = new Panel();
+ d.ok.setLabel(MessageManager.getString("action.ok"));
+ d.cancel.setVisible(false);
+ mp.setLayout(new FlowLayout());
+ mp.add(new Label(msg));
+ d.setMainPanel(mp);
+ d.setVisible(true);
+ }
}
import java.awt.event.WindowEvent;
import java.util.Arrays;
import java.util.Enumeration;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.Vector;
public class FeatureSettings extends Panel implements ItemListener,
{
fr.findAllFeatures(true); // was default - now true to make all visible
}
+ groupPanel = new Panel();
discoverAllFeatureData();
add(lowerPanel, BorderLayout.SOUTH);
- if (groupPanel != null)
- {
- groupPanel.setLayout(new GridLayout(
- (fr.getFeatureGroupsSize()) / 4 + 1, 4)); // JBPNote - this was
- // scaled on number of
- // visible groups. seems
- // broken
- groupPanel.validate();
+ groupPanel.setLayout(new GridLayout(
+ (fr.getFeatureGroupsSize()) / 4 + 1, 4)); // JBPNote - this was
+ // scaled on number of
+ // visible groups. seems
+ // broken
+ groupPanel.validate();
+
+ add(groupPanel, BorderLayout.NORTH);
- add(groupPanel, BorderLayout.NORTH);
- }
frame = new Frame();
frame.add(this);
final FeatureSettings me = this;
if (fr.getAllFeatureColours() != null
&& fr.getAllFeatureColours().size() > 0)
{
- rebuildGroups();
+ // rebuildGroups();
}
resetTable(false);
}
/**
- * rebuilds the group panel
+ * Answers the visibility of the given group, and adds a checkbox for it if
+ * there is not one already
*/
- public void rebuildGroups()
+ public boolean checkGroupState(String group)
{
- boolean rdrw = false;
- if (groupPanel == null)
- {
- groupPanel = new Panel();
- }
- else
- {
- rdrw = true;
- groupPanel.removeAll();
- }
- // TODO: JAL-964 - smoothly incorporate new group entries if panel already
- // displayed and new groups present
- for (String group : fr.getFeatureGroups())
- {
- boolean vis = fr.checkGroupVisibility(group, false);
- Checkbox check = new MyCheckbox(group, vis, false);
- check.addMouseListener(this);
- check.setFont(new Font("Serif", Font.BOLD, 12));
- check.addItemListener(groupItemListener);
- // note - visibility seems to correlate with displayed. ???wtf ??
- check.setVisible(vis);
- groupPanel.add(check);
- }
- if (rdrw)
+ boolean visible = fr.checkGroupVisibility(group, true);
+
+ /*
+ * is there already a checkbox for this group?
+ */
+ for (int g = 0; g < groupPanel.getComponentCount(); g++)
{
- groupPanel.validate();
+ if (((Checkbox) groupPanel.getComponent(g)).getLabel().equals(group))
+ {
+ ((Checkbox) groupPanel.getComponent(g)).setState(visible);
+ return visible;
+ }
}
+
+ /*
+ * add a new checkbox
+ */
+ Checkbox check = new MyCheckbox(group, visible, false);
+ check.addMouseListener(this);
+ check.setFont(new Font("Serif", Font.BOLD, 12));
+ check.addItemListener(groupItemListener);
+ groupPanel.add(check);
+
+ groupPanel.validate();
+ return visible;
}
// This routine adds and removes checkboxes depending on
SequenceFeature[] tmpfeatures;
String group = null, type;
Vector<String> visibleChecks = new Vector<String>();
+ Set<String> foundGroups = new HashSet<String>();
AlignmentI alignment = av.getAlignment();
+
for (int i = 0; i < alignment.getHeight(); i++)
{
if (alignment.getSequenceAt(i).getSequenceFeatures() == null)
while (index < tmpfeatures.length)
{
group = tmpfeatures[index].featureGroup;
+ foundGroups.add(group);
- if (group == null || fr.checkGroupVisibility(group, true))
+ if (group == null || checkGroupState(group))
{
type = tmpfeatures[index].getType();
if (!visibleChecks.contains(type))
}
}
+ /*
+ * remove any checkboxes for groups not present
+ */
+ pruneGroups(foundGroups);
+
Component[] comps;
int cSize = featurePanel.getComponentCount();
MyCheckbox check;
}
/**
+ * Remove from the groups panel any checkboxes for groups that are not in the
+ * foundGroups set. This enables removing a group from the display when the
+ * last feature in that group is deleted.
+ *
+ * @param foundGroups
+ */
+ protected void pruneGroups(Set<String> foundGroups)
+ {
+ for (int g = 0; g < groupPanel.getComponentCount(); g++)
+ {
+ Checkbox checkbox = (Checkbox) groupPanel.getComponent(g);
+ if (!foundGroups.contains(checkbox.getLabel()))
+ {
+ groupPanel.remove(checkbox);
+ }
+ }
+ }
+
+ /**
* update the checklist of feature types with the given type
*
* @param groupsChanged
public void adjustmentValueChanged(AdjustmentEvent evt)
{
fr.setTransparency((100 - transparency.getValue()) / 100f);
- ap.seqPanel.seqCanvas.repaint();
-
+ ap.paintAlignment(true);
}
class MyCheckbox extends Checkbox
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Vector;
public class Finder extends Panel implements ActionListener
public void createNewGroup_actionPerformed()
{
- SequenceI[] seqs = new SequenceI[searchResults.getSize()];
- SequenceFeature[] features = new SequenceFeature[searchResults
- .getSize()];
+ List<SequenceI> seqs = new ArrayList<SequenceI>();
+ List<SequenceFeature> features = new ArrayList<SequenceFeature>();
+ String searchString = textfield.getText().trim();
- int i = 0;
for (SearchResultMatchI match : searchResults.getResults())
{
- seqs[i] = match.getSequence().getDatasetSequence();
-
- features[i] = new SequenceFeature(textfield.getText().trim(),
+ seqs.add(match.getSequence().getDatasetSequence());
+ features.add(new SequenceFeature(searchString,
"Search Results", null, match.getStart(), match.getEnd(),
- "Search Results");
- i++;
+ "Search Results"));
}
if (ap.seqPanel.seqCanvas.getFeatureRenderer().amendFeatures(seqs,
*/
package jalview.appletgui;
-import jalview.api.ViewStyleI;
import jalview.util.MessageManager;
import java.awt.BorderLayout;
private Checkbox scaleAsCdna = new Checkbox();
+ private Checkbox fontAsCdna = new Checkbox();
+
private Button ok = new Button();
private Button cancel = new Button();
private Font oldFont;
+ private Font oldComplementFont;
+
private int oldCharWidth = 0;
+ /*
+ * the state of 'scale protein to cDNA' on opening the dialog
+ */
private boolean oldScaleProtein = false;
+ /*
+ * the state of 'same font for protein and cDNA' on opening the dialog
+ */
+ boolean oldMirrorFont;
+
private Font lastSelected = null;
private int lastSelStyle = 0;
private Frame frame;
+ boolean inSplitFrame = false;
+
/**
* Constructor for a TreePanel font chooser
*
{
this.ap = ap;
oldFont = ap.av.getFont();
- oldCharWidth = ap.av.getViewStyle().getCharWidth();
- oldScaleProtein = ap.av.getViewStyle().isScaleProteinAsCdna();
+ oldCharWidth = ap.av.getCharWidth();
+ oldScaleProtein = ap.av.isScaleProteinAsCdna();
+ oldMirrorFont = ap.av.isProteinFontAsCdna();
try
{
this.frame = new Frame();
frame.add(this);
jalview.bin.JalviewLite.addFrame(frame,
- MessageManager.getString("action.change_font"), 440, 115);
+ MessageManager.getString("action.change_font"), 440, 145);
init = false;
}
/**
* Actions on change of font name, size or style.
*/
+ @Override
public void itemStateChanged(ItemEvent evt)
{
final Object source = evt.getSource();
{
scaleAsCdna_actionPerformed();
}
+ else if (source == fontAsCdna)
+ {
+ mirrorFont_actionPerformed();
+ }
+ }
+
+ /**
+ * Action on checking or unchecking 'use same font across split screen'
+ * option. When checked, the font settings are copied to the other half of the
+ * split screen. When unchecked, the other half is restored to its initial
+ * settings.
+ */
+ protected void mirrorFont_actionPerformed()
+ {
+ boolean selected = fontAsCdna.getState();
+ ap.av.setProteinFontAsCdna(selected);
+ ap.av.getCodingComplement().setProteinFontAsCdna(selected);
+
+ if (!selected)
+ {
+ ap.av.getCodingComplement().setFont(oldComplementFont, true);
+ }
+ changeFont();
}
/**
if (ap != null)
{
ap.av.setScaleProteinAsCdna(oldScaleProtein);
+ ap.av.setProteinFontAsCdna(oldMirrorFont);
+
if (ap.av.getCodingComplement() != null)
{
ap.av.getCodingComplement().setScaleProteinAsCdna(oldScaleProtein);
- ap.alignFrame.getSplitFrame().repaint();
+ ap.av.getCodingComplement().setProteinFontAsCdna(oldMirrorFont);
+ ap.av.getCodingComplement().setFont(oldComplementFont, true);
+ SplitFrame splitFrame = ap.alignFrame.getSplitFrame();
+ splitFrame.adjustLayout();
+ splitFrame.getComplement(ap.alignFrame).alignPanel.fontChanged();
+ splitFrame.repaint();
}
- ap.av.setFont(oldFont);
- ViewStyleI style = ap.av.getViewStyle();
- if (style.getCharWidth() != oldCharWidth)
+ ap.av.setFont(oldFont, true);
+ if (ap.av.getCharWidth() != oldCharWidth)
{
- style.setCharWidth(oldCharWidth);
- ap.av.setViewStyle(style);
+ ap.av.setCharWidth(oldCharWidth);
}
ap.paintAlignment(true);
}
}
else if (ap != null)
{
- ap.av.setFont(newFont);
+ ap.av.setFont(newFont, true);
ap.fontChanged();
+
+ /*
+ * and change font in other half of split frame if any
+ */
+ if (inSplitFrame)
+ {
+ if (fontAsCdna.getState())
+ {
+ ap.av.getCodingComplement().setFont(newFont, true);
+ }
+ SplitFrame splitFrame = ap.alignFrame.getSplitFrame();
+ splitFrame.adjustLayout();
+ splitFrame.getComplement(ap.alignFrame).alignPanel.fontChanged();
+ splitFrame.repaint();
+ }
}
// remember last selected
lastSelected = newFont;
scaleAsCdna.addItemListener(this);
scaleAsCdna.setState(ap.av.isScaleProteinAsCdna());
+ fontAsCdna.setLabel(MessageManager.getString("label.font_as_cdna"));
+ fontAsCdna.setFont(VERDANA_11PT);
+ fontAsCdna.addItemListener(this);
+ fontAsCdna.setState(ap.av.isProteinFontAsCdna());
+
ok.setFont(VERDANA_11PT);
ok.setLabel(MessageManager.getString("action.ok"));
ok.addActionListener(new ActionListener()
stylePanel.add(fontStyle, BorderLayout.CENTER);
sizePanel.add(sizeLabel, BorderLayout.WEST);
sizePanel.add(fontSize, BorderLayout.CENTER);
- scalePanel.add(scaleAsCdna, BorderLayout.CENTER);
+ scalePanel.add(scaleAsCdna, BorderLayout.NORTH);
+ scalePanel.add(fontAsCdna, BorderLayout.SOUTH);
okCancelPanel.add(ok, null);
okCancelPanel.add(cancel, null);
this.add(optionsPanel, BorderLayout.NORTH);
if (ap.alignFrame.getSplitFrame() != null)
{
+ inSplitFrame = true;
+ oldComplementFont = ((AlignViewport) ap.av.getCodingComplement())
+ .getFont();
this.add(scalePanel, BorderLayout.CENTER);
}
this.add(okCancelPanel, BorderLayout.SOUTH);
ap.av.setScaleProteinAsCdna(scaleAsCdna.getState());
ap.av.getCodingComplement().setScaleProteinAsCdna(
scaleAsCdna.getState());
- ap.alignFrame.getSplitFrame().adjustLayout();
- ap.paintAlignment(true);
- ap.alignFrame.getSplitFrame().repaint();
+ changeFont();
}
}
package jalview.appletgui;
import jalview.datamodel.SequenceI;
+import jalview.viewmodel.ViewportListenerI;
+import jalview.viewmodel.ViewportRanges;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Panel;
+import java.beans.PropertyChangeEvent;
import java.util.List;
-public class IdCanvas extends Panel
+public class IdCanvas extends Panel implements ViewportListenerI
{
protected AlignViewport av;
setLayout(null);
this.av = av;
PaintRefresher.Register(this, av.getSequenceSetId());
+ av.getRanges().addPropertyChangeListener(this);
}
public void drawIdString(Graphics gg, boolean hiddenRows, SequenceI s,
return;
}
+ ViewportRanges ranges = av.getRanges();
+
gg.copyArea(0, 0, getSize().width, imgHeight, 0,
-vertical * av.getCharHeight());
- int ss = av.startSeq, es = av.endSeq, transY = 0;
+ int ss = ranges.getStartSeq(), es = ranges.getEndSeq(), transY = 0;
if (vertical > 0) // scroll down
{
ss = es - vertical;
- if (ss < av.startSeq) // ie scrolling too fast, more than a page at a time
+ if (ss < ranges.getStartSeq()) // ie scrolling too fast, more than a page
+ // at a
+ // time
{
- ss = av.startSeq;
+ ss = ranges.getStartSeq();
}
else
{
- transY = imgHeight - vertical * av.getCharHeight();
+ transY = imgHeight - ((vertical + 1) * av.getCharHeight());
}
}
else if (vertical < 0)
{
es = ss - vertical;
- if (es > av.endSeq)
+ if (es > ranges.getEndSeq())
{
- es = av.endSeq;
+ es = ranges.getEndSeq();
}
}
gg.setFont(italic);
gg.fillRect(0, 0, getSize().width, getSize().height);
- drawIds(av.startSeq, av.endSeq);
+ drawIds(av.getRanges().getStartSeq(), av.getRanges().getEndSeq());
g.drawImage(image, 0, 0, this);
}
if (av.hasHiddenColumns())
{
- maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+ maxwidth = av.getAlignment().getHiddenColumns()
+ .findColumnPosition(maxwidth) - 1;
}
int annotationHeight = 0;
int cHeight = alheight * avcharHeight + hgap + annotationHeight;
- int rowSize = av.getEndRes() - av.getStartRes();
+ int rowSize = av.getRanges().getEndRes()
+ - av.getRanges().getStartRes();
// Draw the rest of the panels
- for (int ypos = hgap, row = av.startRes; (ypos <= getSize().height)
+ for (int ypos = hgap, row = av.getRanges().getStartRes(); (ypos <= getSize().height)
&& (row < maxwidth); ypos += cHeight, row += rowSize)
{
for (int i = starty; i < alheight; i++)
{
// Now draw the id strings
SequenceI seq;
- for (int i = starty; i < endy; i++)
+ for (int i = starty; i <= endy; i++)
{
seq = av.getAlignment().getSequenceAt(i);
}
return false;
}
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ // Respond to viewport range changes (e.g. alignment panel was scrolled)
+ if (evt.getPropertyName().equals("startseq")
+ || evt.getPropertyName().equals("endseq"))
+ {
+ fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
+ }
+ }
}
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
return;
}
- if (mouseDragging && e.getY() < 0 && av.getStartSeq() > 0)
+ if (mouseDragging && e.getY() < 0 && av.getRanges().getStartSeq() > 0)
{
scrollThread = new ScrollThread(true);
}
if (mouseDragging && e.getY() >= getSize().height
- && av.getAlignment().getHeight() > av.getEndSeq())
+ && av.getAlignment().getHeight() > av.getRanges().getEndSeq())
{
scrollThread = new ScrollThread(false);
}
// 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++)
{
int index = av.getAlignment().findIndex(list.get(0));
// do we need to scroll the panel?
- if (av.getStartSeq() > index || av.getEndSeq() < index)
+ if (av.getRanges().getStartSeq() > index
+ || av.getRanges().getEndSeq() < index)
{
- alignPanel.setScrollValues(av.getStartRes(), index);
+ av.getRanges().setStartSeq(index);
}
}
running = true;
while (running)
{
- if (alignPanel.scrollUp(up))
+ if (av.getRanges().scrollUp(up))
{
// scroll was ok, so add new sequence to selection
- int seq = av.getStartSeq();
+ int seq = av.getRanges().getStartSeq();
if (!up)
{
- seq = av.getEndSeq();
+ seq = av.getRanges().getEndSeq();
}
if (seq < lastid)
--- /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.
+ */
+package jalview.appletgui;
+
+import jalview.renderer.OverviewRenderer;
+import jalview.viewmodel.OverviewDimensions;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Image;
+
+public class OverviewCanvas extends Component
+{
+ // This is set true if the alignment view changes whilst
+ // the overview is being calculated
+ private volatile boolean restart = false;
+
+ private volatile boolean updaterunning = false;
+
+ private OverviewDimensions od;
+
+ private Image miniMe;
+
+ private Image offscreen;
+
+ private AlignViewport av;
+
+ // Can set different properties in this seqCanvas than
+ // main visible SeqCanvas
+ private SequenceRenderer sr;
+
+ private jalview.renderer.seqfeatures.FeatureRenderer fr;
+
+ private Frame nullFrame;
+
+ public OverviewCanvas(OverviewDimensions overviewDims,
+ AlignViewport alignvp)
+ {
+ od = overviewDims;
+ av = alignvp;
+
+ nullFrame = new Frame();
+ nullFrame.addNotify();
+
+ sr = new SequenceRenderer(av);
+ sr.graphics = nullFrame.getGraphics();
+ sr.renderGaps = false;
+ sr.forOverview = true;
+ fr = new jalview.renderer.seqfeatures.FeatureRenderer(av);
+ }
+
+ /**
+ * Update the overview dimensions object used by the canvas (e.g. if we change
+ * from showing hidden columns to hiding them or vice versa)
+ *
+ * @param overviewDims
+ */
+ public void resetOviewDims(OverviewDimensions overviewDims)
+ {
+ od = overviewDims;
+ }
+
+ /**
+ * Signals to drawing code that the associated alignment viewport has changed
+ * and a redraw will be required
+ */
+ public boolean restartDraw()
+ {
+ synchronized (this)
+ {
+ if (updaterunning)
+ {
+ restart = true;
+ }
+ else
+ {
+ updaterunning = true;
+ }
+ return restart;
+ }
+ }
+
+ public void draw(boolean showSequenceFeatures, boolean showAnnotation,
+ FeatureRenderer transferRenderer)
+ {
+ miniMe = null;
+
+ if (showSequenceFeatures)
+ {
+ fr.transferSettings(transferRenderer);
+ }
+
+ setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
+
+ OverviewRenderer or = new OverviewRenderer(sr, fr, od);
+ miniMe = nullFrame.createImage(od.getWidth(), od.getHeight());
+ offscreen = nullFrame.createImage(od.getWidth(), od.getHeight());
+
+ miniMe = or.draw(od.getRows(av.getAlignment()),
+ od.getColumns(av.getAlignment()));
+
+ Graphics mg = miniMe.getGraphics();
+
+ // checks for conservation annotation to make sure overview works for DNA
+ // too
+ if (showAnnotation)
+ {
+ mg.translate(0, od.getSequencesHeight());
+ or.drawGraph(mg, av.getAlignmentConservationAnnotation(),
+ av.getCharWidth(), od.getGraphHeight(),
+ od.getColumns(av.getAlignment()));
+ mg.translate(0, -od.getSequencesHeight());
+ }
+ System.gc();
+
+ if (restart)
+ {
+ restart = false;
+ draw(showSequenceFeatures, showAnnotation, transferRenderer);
+ }
+ else
+ {
+ updaterunning = false;
+ }
+ }
+
+ @Override
+ public void update(Graphics g)
+ {
+ paint(g);
+ }
+
+ @Override
+ public void paint(Graphics g)
+ {
+ Graphics og = offscreen.getGraphics();
+ if (miniMe != null)
+ {
+ og.drawImage(miniMe, 0, 0, this);
+ og.setColor(Color.red);
+ od.drawBox(og);
+ g.drawImage(offscreen, 0, 0, this);
+ }
+ }
+
+}
*/
package jalview.appletgui;
-import jalview.datamodel.AlignmentI;
-
-import java.awt.Color;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.viewmodel.OverviewDimensions;
+import jalview.viewmodel.OverviewDimensionsHideHidden;
+import jalview.viewmodel.OverviewDimensionsShowHidden;
+import jalview.viewmodel.ViewportListenerI;
+
+import java.awt.BorderLayout;
+import java.awt.CheckboxMenuItem;
import java.awt.Dimension;
-import java.awt.Frame;
-import java.awt.Graphics;
-import java.awt.Image;
import java.awt.Panel;
+import java.awt.PopupMenu;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
public class OverviewPanel extends Panel implements Runnable,
- MouseMotionListener, MouseListener
+ MouseMotionListener, MouseListener, ViewportListenerI
{
- Image miniMe;
-
- Image offscreen;
-
- AlignViewport av;
-
- AlignmentPanel ap;
-
- float scalew = 1f;
+ private OverviewDimensions od;
- float scaleh = 1f;
+ private OverviewCanvas oviewCanvas;
- public int width, sequencesHeight;
+ private AlignViewport av;
- int graphHeight = 20;
+ private AlignmentPanel ap;
- int boxX = -1, boxY = -1, boxWidth = -1, boxHeight = -1;
+ private boolean showHidden = true;
- boolean resizing = false;
+ private boolean updateRunning = false;
- // Can set different properties in this seqCanvas than
- // main visible SeqCanvas
- SequenceRenderer sr;
-
- FeatureRenderer fr;
-
- Frame nullFrame;
-
- public OverviewPanel(AlignmentPanel ap)
+ public OverviewPanel(AlignmentPanel alPanel)
{
- this.av = ap.av;
- this.ap = ap;
+ this.av = alPanel.av;
+ this.ap = alPanel;
setLayout(null);
- nullFrame = new Frame();
- nullFrame.addNotify();
- sr = new SequenceRenderer(av);
- sr.graphics = nullFrame.getGraphics();
- sr.renderGaps = false;
- sr.forOverview = true;
- fr = new FeatureRenderer(av);
+ od = new OverviewDimensionsShowHidden(av.getRanges(),
+ (av.isShowAnnotation() && av.getSequenceConsensusHash() != null));
- // scale the initial size of overviewpanel to shape of alignment
- float initialScale = (float) av.getAlignment().getWidth()
- / (float) av.getAlignment().getHeight();
+ oviewCanvas = new OverviewCanvas(od, av);
+ setLayout(new BorderLayout());
+ add(oviewCanvas, BorderLayout.CENTER);
- if (av.getSequenceConsensusHash() == null)
- {
- graphHeight = 0;
- }
+ setSize(new Dimension(od.getWidth(), od.getHeight()));
- if (av.getAlignment().getWidth() > av.getAlignment().getHeight())
- {
- // wider
- width = 400;
- sequencesHeight = (int) (400f / initialScale);
- if (sequencesHeight < 40)
- {
- sequencesHeight = 40;
- }
- }
- else
- {
- // taller
- width = (int) (400f * initialScale);
- sequencesHeight = 300;
- if (width < 120)
- {
- width = 120;
- }
- }
+ av.getRanges().addPropertyChangeListener(this);
- setSize(new Dimension(width, sequencesHeight + graphHeight));
addComponentListener(new ComponentAdapter()
{
@Override
public void componentResized(ComponentEvent evt)
{
- if (getSize().width != width
- || getSize().height != sequencesHeight + graphHeight)
+ if ((getWidth() != od.getWidth())
+ || (getHeight() != (od.getHeight())))
{
updateOverviewImage();
}
@Override
public void mouseClicked(MouseEvent evt)
{
+ if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
+ {
+ showPopupMenu(evt);
+ }
}
@Override
@Override
public void mousePressed(MouseEvent evt)
{
- boxX = evt.getX();
- boxY = evt.getY();
- checkValid();
+ mouseAction(evt);
}
@Override
public void mouseReleased(MouseEvent evt)
{
- boxX = evt.getX();
- boxY = evt.getY();
- checkValid();
+ mouseAction(evt);
}
@Override
public void mouseDragged(MouseEvent evt)
{
- boxX = evt.getX();
- boxY = evt.getY();
- checkValid();
+ mouseAction(evt);
}
- void checkValid()
+ private void mouseAction(MouseEvent evt)
{
- if (boxY < 0)
- {
- boxY = 0;
- }
-
- if (boxY > (sequencesHeight - boxHeight))
+ if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
{
- boxY = sequencesHeight - boxHeight + 1;
- }
-
- if (boxX < 0)
- {
- boxX = 0;
- }
-
- if (boxX > (width - boxWidth))
- {
- if (av.hasHiddenColumns())
+ if (!Platform.isAMac())
{
- // Try smallest possible box
- boxWidth = (int) ((av.endRes - av.startRes + 1) * av.getCharWidth() * scalew);
+ showPopupMenu(evt);
}
- boxX = width - boxWidth;
- }
-
- int col = (int) (boxX / scalew / av.getCharWidth());
- int row = (int) (boxY / scaleh / av.getCharHeight());
-
- if (av.hasHiddenColumns())
- {
- if (!av.getColumnSelection().isVisible(col))
- {
- return;
- }
-
- col = av.getColumnSelection().findColumnPosition(col);
}
-
- if (av.hasHiddenRows())
+ else
{
- row = av.getAlignment().getHiddenSequences()
- .findIndexWithoutHiddenSeqs(row);
+ od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment()
+ .getHiddenSequences(), av.getAlignment().getHiddenColumns());
+ ap.paintAlignment(false);
}
-
- ap.setScrollValues(col, row);
- ap.paintAlignment(false);
}
/**
- * DOCUMENT ME!
+ * Updates the overview image when the related alignment panel is updated
*/
public void updateOverviewImage()
{
- if (resizing)
+ if ((getSize().width > 0) && (getSize().height > 0))
{
- resizeAgain = true;
- return;
+ od.setWidth(getSize().width);
+ od.setHeight(getSize().height);
}
+ setSize(new Dimension(od.getWidth(), od.getHeight()));
- if (av.isShowSequenceFeatures())
+ synchronized (this)
{
- fr.transferSettings(ap.seqPanel.seqCanvas.fr);
- }
-
- resizing = true;
+ if (updateRunning)
+ {
+ oviewCanvas.restartDraw();
+ return;
+ }
- if ((getSize().width > 0) && (getSize().height > 0))
- {
- width = getSize().width;
- sequencesHeight = getSize().height - graphHeight;
+ updateRunning = true;
}
- setSize(new Dimension(width, sequencesHeight + graphHeight));
-
Thread thread = new Thread(this);
thread.start();
repaint();
+ updateRunning = false;
}
- // This is set true if the user resizes whilst
- // the overview is being calculated
- boolean resizeAgain = false;
-
@Override
public void run()
{
- miniMe = null;
- int alwidth = av.getAlignment().getWidth();
- int alheight = av.getAlignment().getHeight()
- + av.getAlignment().getHiddenSequences().getSize();
-
- if (av.isShowSequenceFeatures())
- {
- fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer());
- }
-
- if (getSize().width > 0 && getSize().height > 0)
- {
- width = getSize().width;
- sequencesHeight = getSize().height - graphHeight;
- }
-
- setSize(new Dimension(width, sequencesHeight + graphHeight));
-
- int fullsizeWidth = alwidth * av.getCharWidth();
- int fullsizeHeight = alheight * av.getCharHeight();
-
- scalew = (float) width / (float) fullsizeWidth;
- scaleh = (float) sequencesHeight / (float) fullsizeHeight;
-
- miniMe = nullFrame.createImage(width, sequencesHeight + graphHeight);
- offscreen = nullFrame.createImage(width, sequencesHeight + graphHeight);
-
- Graphics mg = miniMe.getGraphics();
- float sampleCol = (float) alwidth / (float) width;
- float sampleRow = (float) alheight / (float) sequencesHeight;
-
- int lastcol = 0, lastrow = 0;
- int xstart = 0, ystart = 0;
- Color color = Color.yellow;
- int row, col, sameRow = 0, sameCol = 0;
- jalview.datamodel.SequenceI seq;
- final boolean hasHiddenRows = av.hasHiddenRows(), hasHiddenCols = av
- .hasHiddenColumns();
- boolean hiddenRow = false;
- AlignmentI alignment = av.getAlignment();
- for (row = 0; row <= sequencesHeight; row++)
- {
- if (resizeAgain)
- {
- break;
- }
- if ((int) (row * sampleRow) == lastrow)
- {
- sameRow++;
- continue;
- }
-
- hiddenRow = false;
- if (hasHiddenRows)
- {
- seq = alignment.getHiddenSequences().getHiddenSequence(lastrow);
- if (seq == null)
- {
- int index = alignment.getHiddenSequences()
- .findIndexWithoutHiddenSeqs(lastrow);
-
- seq = alignment.getSequenceAt(index);
- }
- else
- {
- hiddenRow = true;
- }
- }
- else
- {
- seq = alignment.getSequenceAt(lastrow);
- }
-
- for (col = 0; col < width; col++)
- {
- if ((int) (col * sampleCol) == lastcol
- && (int) (row * sampleRow) == lastrow)
- {
- sameCol++;
- continue;
- }
-
- lastcol = (int) (col * sampleCol);
-
- if (seq.getLength() > lastcol)
- {
- color = sr.getResidueBoxColour(seq, lastcol);
-
- if (av.isShowSequenceFeatures())
- {
- color = fr.findFeatureColour(color, seq, lastcol);
- }
- }
- else
- {
- color = Color.white; // White
- }
-
- if (hiddenRow
- || (hasHiddenCols && !av.getColumnSelection().isVisible(
- lastcol)))
- {
- color = color.darker().darker();
- }
-
- mg.setColor(color);
- if (sameCol == 1 && sameRow == 1)
- {
- mg.drawLine(xstart, ystart, xstart, ystart);
- }
- else
- {
- mg.fillRect(xstart, ystart, sameCol, sameRow);
- }
-
- xstart = col;
- sameCol = 1;
- }
- lastrow = (int) (row * sampleRow);
- ystart = row;
- sameRow = 1;
- }
-
- if (av.getAlignmentConservationAnnotation() != null)
- {
- for (col = 0; col < width; col++)
- {
- if (resizeAgain)
- {
- break;
- }
- lastcol = (int) (col * sampleCol);
- {
- mg.translate(col, sequencesHeight);
- ap.annotationPanel.renderer.drawGraph(mg,
- av.getAlignmentConservationAnnotation(),
- av.getAlignmentConservationAnnotation().annotations,
- (int) (sampleCol) + 1, graphHeight,
- (int) (col * sampleCol), (int) (col * sampleCol) + 1);
- mg.translate(-col, -sequencesHeight);
- }
- }
- }
- System.gc();
-
- resizing = false;
-
+ oviewCanvas.draw(av.isShowSequenceFeatures(),
+ (av.isShowAnnotation() && av
+ .getAlignmentConservationAnnotation() != null),
+ ap.seqPanel.seqCanvas.getFeatureRenderer());
setBoxPosition();
-
- if (resizeAgain)
- {
- resizeAgain = false;
- updateOverviewImage();
- }
}
- public void setBoxPosition()
+ /**
+ * Update the overview panel box when the associated alignment panel is
+ * changed
+ *
+ */
+ private void setBoxPosition()
{
- int fullsizeWidth = av.getAlignment().getWidth() * av.getCharWidth();
- int fullsizeHeight = (av.getAlignment().getHeight() + av.getAlignment()
- .getHiddenSequences().getSize())
- * av.getCharHeight();
-
- int startRes = av.getStartRes();
- int endRes = av.getEndRes();
-
- if (av.hasHiddenColumns())
- {
- startRes = av.getColumnSelection().adjustForHiddenColumns(startRes);
- endRes = av.getColumnSelection().adjustForHiddenColumns(endRes);
- }
-
- int startSeq = av.startSeq;
- int endSeq = av.endSeq;
-
- if (av.hasHiddenRows())
- {
- startSeq = av.getAlignment().getHiddenSequences()
- .adjustForHiddenSeqs(startSeq);
-
- endSeq = av.getAlignment().getHiddenSequences()
- .adjustForHiddenSeqs(endSeq);
-
- }
-
- scalew = (float) width / (float) fullsizeWidth;
- scaleh = (float) sequencesHeight / (float) fullsizeHeight;
-
- boxX = (int) (startRes * av.getCharWidth() * scalew);
- boxY = (int) (startSeq * av.getCharHeight() * scaleh);
+ od.setBoxPosition(av.getAlignment()
+.getHiddenSequences(), av
+ .getAlignment().getHiddenColumns());
+ repaint();
+ }
- if (av.hasHiddenColumns())
- {
- boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
- }
- else
+ /*
+ * Displays the popup menu and acts on user input
+ */
+ private void showPopupMenu(MouseEvent e)
+ {
+ PopupMenu popup = new PopupMenu();
+ ItemListener menuListener = new ItemListener()
{
- boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
- }
-
- boxHeight = (int) ((endSeq - startSeq) * av.getCharHeight() * scaleh);
-
- repaint();
+ @Override
+ public void itemStateChanged(ItemEvent e)
+ {
+ toggleHiddenColumns();
+ }
+ };
+ CheckboxMenuItem item = new CheckboxMenuItem(
+ MessageManager.getString("label.togglehidden"));
+ item.setState(showHidden);
+ popup.add(item);
+ item.addItemListener(menuListener);
+ this.add(popup);
+ popup.show(this, e.getX(), e.getY());
}
@Override
- public void update(Graphics g)
+ public void propertyChange(PropertyChangeEvent evt)
{
- paint(g);
+ setBoxPosition();
}
- @Override
- public void paint(Graphics g)
+ /*
+ * Toggle overview display between showing hidden columns and hiding hidden columns
+ */
+ private void toggleHiddenColumns()
{
- Graphics og = offscreen.getGraphics();
- if (miniMe != null)
+ if (showHidden)
{
- og.drawImage(miniMe, 0, 0, this);
- og.setColor(Color.red);
- og.drawRect(boxX, boxY, boxWidth, boxHeight);
- og.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);
- g.drawImage(offscreen, 0, 0, this);
+ showHidden = false;
+ od = new OverviewDimensionsHideHidden(av.getRanges(),
+ (av.isShowAnnotation() && av
+ .getAlignmentConservationAnnotation() != null));
}
+ else
+ {
+ showHidden = true;
+ od = new OverviewDimensionsShowHidden(av.getRanges(),
+ (av.isShowAnnotation() && av
+ .getAlignmentConservationAnnotation() != null));
+ }
+ oviewCanvas.resetOviewDims(od);
+ updateOverviewImage();
}
-
}
*/
package jalview.appletgui;
+import jalview.analysis.scoremodels.ScoreModels;
+import jalview.analysis.scoremodels.SimilarityParams;
+import jalview.api.analysis.ScoreModelI;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentView;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SeqCigar;
import jalview.datamodel.SequenceI;
import jalview.util.MessageManager;
int top = 0;
- public PCAPanel(AlignViewport av)
+ public PCAPanel(AlignViewport viewport)
{
try
{
zCombobox.addItem("dim " + i);
}
- this.av = av;
- boolean selected = av.getSelectionGroup() != null
- && av.getSelectionGroup().getSize() > 0;
- AlignmentView seqstrings = av.getAlignmentView(selected);
- boolean nucleotide = av.getAlignment().isNucleotide();
+ this.av = viewport;
+ boolean selected = viewport.getSelectionGroup() != null
+ && viewport.getSelectionGroup().getSize() > 0;
+ AlignmentView seqstrings = viewport.getAlignmentView(selected);
+ boolean nucleotide = viewport.getAlignment().isNucleotide();
SequenceI[] seqs;
if (!selected)
{
- seqs = av.getAlignment().getSequencesArray();
+ seqs = viewport.getAlignment().getSequencesArray();
}
else
{
- seqs = av.getSelectionGroup().getSequencesInOrder(av.getAlignment());
+ seqs = viewport.getSelectionGroup().getSequencesInOrder(viewport.getAlignment());
}
SeqCigar sq[] = seqstrings.getSequences();
int length = sq[0].getWidth();
return;
}
}
- pcaModel = new PCAModel(seqstrings, seqs, nucleotide);
- rc = new RotatableCanvas(av);
+ ScoreModelI scoreModel = ScoreModels.getInstance().getDefaultModel(
+ !nucleotide);
+ pcaModel = new PCAModel(seqstrings, seqs, nucleotide, scoreModel,
+ SimilarityParams.SeqSpace);
+
+ rc = new RotatableCanvas(viewport);
embedMenuIfNeeded(rc);
add(rc, BorderLayout.CENTER);
/**
* DOCUMENT ME!
*/
+ @Override
public void run()
{
// TODO progress indicator
rc.paint(rc.getGraphics());
}
+ @Override
public void actionPerformed(ActionEvent evt)
{
if (evt.getSource() == inputData)
}
}
+ @Override
public void itemStateChanged(ItemEvent evt)
{
if (evt.getSource() == xCombobox)
if (!pcaModel.isNucleotide())
{
pcaModel.setNucleotide(true);
+ ScoreModelI scoreModel = ScoreModels.getInstance().getDefaultModel(
+ false);
+ pcaModel.setScoreModel(scoreModel);
new Thread(this).start();
}
}
if (pcaModel.isNucleotide())
{
pcaModel.setNucleotide(false);
+ ScoreModelI scoreModel = ScoreModels.getInstance().getDefaultModel(
+ true);
+ pcaModel.setScoreModel(scoreModel);
new Thread(this).start();
}
}
}
;
Object[] alAndColsel = pcaModel.getSeqtrings()
- .getAlignmentAndColumnSelection(gc);
+ .getAlignmentAndHiddenColumns(gc);
if (alAndColsel != null && alAndColsel[0] != null)
{
AlignFrame af = new AlignFrame(al, av.applet,
"Original Data for PCA", false);
- af.viewport.setHiddenColumns((ColumnSelection) alAndColsel[1]);
+ af.viewport.getAlignment().setHiddenColumns(
+ (HiddenColumns) alAndColsel[1]);
}
}
package jalview.appletgui;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceGroup;
import jalview.renderer.ScaleRenderer;
import jalview.renderer.ScaleRenderer.ScaleMark;
import jalview.util.MessageManager;
+import jalview.viewmodel.ViewportListenerI;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
import java.util.List;
public class ScalePanel extends Panel implements MouseMotionListener,
- MouseListener
+ MouseListener, ViewportListenerI
{
protected int offy = 4;
addMouseListener(this);
addMouseMotionListener(this);
+ av.getRanges().addPropertyChangeListener(this);
}
@Override
public void mousePressed(MouseEvent evt)
{
- int x = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int x = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes();
final int res;
if (av.hasHiddenColumns())
{
- res = av.getColumnSelection().adjustForHiddenColumns(x);
+ res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(x);
}
else
{
});
pop.add(item);
- if (av.getColumnSelection().hasManyHiddenColumns())
+ if (av.getAlignment().getHiddenColumns().hasManyHiddenColumns())
{
item = new MenuItem(MessageManager.getString("action.reveal_all"));
item.addActionListener(new ActionListener()
{
mouseDragging = false;
- int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int res = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
if (res > av.getAlignment().getWidth())
{
if (av.hasHiddenColumns())
{
- res = av.getColumnSelection().adjustForHiddenColumns(res);
+ res = av.getAlignment().getHiddenColumns()
+ .adjustForHiddenColumns(res);
}
if (!stretchingGroup)
mouseDragging = true;
ColumnSelection cs = av.getColumnSelection();
- int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int res = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
res = Math.max(0, res);
- res = cs.adjustForHiddenColumns(res);
+ res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res);
res = Math.min(res, av.getAlignment().getWidth() - 1);
min = Math.min(res, min);
max = Math.max(res, max);
return;
}
- int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int res = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
- res = av.getColumnSelection().adjustForHiddenColumns(res);
+ res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res);
reveal = null;
- for (int[] region : av.getColumnSelection().getHiddenColumns())
+ for (int[] region : av.getAlignment().getHiddenColumns()
+ .getHiddenRegions())
{
if (res + 1 == region[0] || res - 1 == region[1])
{
@Override
public void paint(Graphics g)
{
- drawScale(g, av.getStartRes(), av.getEndRes(), getSize().width,
+ drawScale(g, av.getRanges().getStartRes(), av.getRanges().getEndRes(),
+ getSize().width,
getSize().height);
}
// Fill the selected columns
ColumnSelection cs = av.getColumnSelection();
+ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
int avCharWidth = av.getCharWidth();
int avcharHeight = av.getCharHeight();
if (cs != null)
{
gg.setColor(new Color(220, 0, 0));
- boolean hasHiddenColumns = cs.hasHiddenColumns();
+ boolean hasHiddenColumns = hidden.hasHiddenColumns();
for (int sel : cs.getSelected())
{
// TODO: JAL-2001 - provide a fast method to list visible selected in a
// given range
if (hasHiddenColumns)
{
- if (cs.isVisible(sel))
+ if (hidden.isVisible(sel))
{
- sel = cs.findColumnPosition(sel);
+ sel = hidden.findColumnPosition(sel);
}
else
{
if (av.getShowHiddenMarkers())
{
int widthx = 1 + endx - startx;
- for (int i = 0; i < cs.getHiddenColumns().size(); i++)
+ for (int i = 0; i < hidden.getHiddenRegions().size(); i++)
{
- res = cs.findHiddenRegionPosition(i) - startx;
+ res = hidden.findHiddenRegionPosition(i) - startx;
if (res < 0 || res > widthx)
{
}
}
+ @Override
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ // Respond to viewport change events (e.g. alignment panel was scrolled)
+ repaint();
+ }
+
}
package jalview.appletgui;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.renderer.ScaleRenderer;
import jalview.renderer.ScaleRenderer.ScaleMark;
import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportListenerI;
+import jalview.viewmodel.ViewportRanges;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Panel;
+import java.beans.PropertyChangeEvent;
-public class SeqCanvas extends Panel
+public class SeqCanvas extends Panel implements ViewportListenerI
{
FeatureRenderer fr;
sr = new SequenceRenderer(av);
PaintRefresher.Register(this, av.getSequenceSetId());
updateViewport();
+
+ av.getRanges().addPropertyChangeListener(this);
}
int avcharHeight = 0, avcharWidth = 0;
ypos += avcharHeight;
if (av.hasHiddenColumns())
{
- startx = av.getColumnSelection().adjustForHiddenColumns(startx);
- endx = av.getColumnSelection().adjustForHiddenColumns(endx);
+ startx = av.getAlignment().getHiddenColumns()
+ .adjustForHiddenColumns(startx);
+ endx = av.getAlignment().getHiddenColumns()
+ .adjustForHiddenColumns(endx);
}
int maxwidth = av.getAlignment().getWidth();
if (av.hasHiddenColumns())
{
- maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+ maxwidth = av.getAlignment().getHiddenColumns()
+ .findColumnPosition(maxwidth) - 1;
}
// WEST SCALE
if (av.hasHiddenColumns())
{
- endx = av.getColumnSelection().adjustForHiddenColumns(endx);
+ endx = av.getAlignment().getHiddenColumns()
+ .adjustForHiddenColumns(endx);
}
SequenceI seq;
return;
}
+ ViewportRanges ranges = av.getRanges();
+
updateViewport();
// Its possible on certain browsers that the call to fastpaint
// is faster than it can paint, so this check here catches
// this possibility
- if (lastsr + horizontal != av.startRes)
+ if (lastsr + horizontal != ranges.getStartRes())
{
- horizontal = av.startRes - lastsr;
+ horizontal = ranges.getStartRes() - lastsr;
}
- lastsr = av.startRes;
+ lastsr = ranges.getStartRes();
fastPaint = true;
gg.copyArea(horizontal * avcharWidth, vertical * avcharHeight, imgWidth
imgHeight - vertical * avcharHeight, -horizontal * avcharWidth,
-vertical * avcharHeight);
- int sr = av.startRes, er = av.endRes, ss = av.startSeq, es = av.endSeq, transX = 0, transY = 0;
+ int sr = ranges.getStartRes(), er = ranges.getEndRes(), ss = ranges
+ .getStartSeq(), es = ranges
+ .getEndSeq(), transX = 0, transY = 0;
if (horizontal > 0) // scrollbar pulled right, image to the left
{
else if (vertical > 0) // scroll down
{
ss = es - vertical;
- if (ss < av.startSeq) // ie scrolling too fast, more than a page at a time
+ if (ss < ranges.getStartSeq()) // ie scrolling too fast, more than a page
+ // at a
+ // time
{
- ss = av.startSeq;
+ ss = ranges.getStartSeq();
}
else
{
- transY = imgHeight - vertical * avcharHeight;
+ transY = imgHeight - ((vertical + 1) * avcharHeight);
}
}
else if (vertical < 0)
{
es = ss - vertical;
- if (es > av.endSeq)
+ if (es > ranges.getEndSeq())
{
- es = av.endSeq;
+ es = ranges.getEndSeq();
}
}
gg.setColor(Color.white);
gg.fillRect(0, 0, imgWidth, imgHeight);
+ ViewportRanges ranges = av.getRanges();
+
if (av.getWrapAlignment())
{
- drawWrappedPanel(gg, imgWidth, imgHeight, av.startRes);
+ drawWrappedPanel(gg, imgWidth, imgHeight, ranges.getStartRes());
}
else
{
- drawPanel(gg, av.startRes, av.endRes, av.startSeq, av.endSeq, 0);
+ drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(),
+ ranges.getStartSeq(), ranges.getEndSeq(), 0);
}
g.drawImage(img, 0, 0, this);
av.setWrappedWidth(cWidth);
- av.endRes = av.startRes + cWidth;
+ av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth - 1);
int endx;
int ypos = hgap;
if (av.hasHiddenColumns())
{
- maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+ maxwidth = av.getAlignment().getHiddenColumns()
+ .findColumnPosition(maxwidth) - 1;
}
while ((ypos <= canvasHeight) && (startRes < maxwidth))
}
if (av.hasHiddenColumns() && av.getShowHiddenMarkers())
{
+ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
g.setColor(Color.blue);
int res;
- for (int i = 0; i < av.getColumnSelection().getHiddenColumns()
+ for (int i = 0; i < hidden.getHiddenRegions()
.size(); i++)
{
- res = av.getColumnSelection().findHiddenRegionPosition(i)
+ res = hidden.findHiddenRegionPosition(i)
- startRes;
if (res < 0 || res > endx - startRes)
g.setClip(0, 0, cWidth * avcharWidth, canvasHeight);
}
- drawPanel(g, startRes, endx, 0, al.getHeight(), ypos);
+ drawPanel(g, startRes, endx, 0, al.getHeight() - 1, ypos);
g.setClip(null);
if (av.isShowAnnotation())
if (av.hasHiddenColumns())
{
- for (int[] region : av.getColumnSelection().getHiddenColumns())
+ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+ for (int[] region : hidden.getHiddenRegions())
{
int hideStart = region[0];
int hideEnd = region[1];
g1.setColor(Color.blue);
g1.drawLine((blockEnd - blockStart + 1) * avcharWidth - 1,
0 + offset, (blockEnd - blockStart + 1) * avcharWidth
- - 1, (endSeq - startSeq) * avcharHeight
+ - 1, (endSeq - startSeq + 1) * avcharHeight
+ offset);
}
// / First draw the sequences
// ///////////////////////////
- for (int i = startSeq; i < endSeq; i++)
+ for (int i = startSeq; i <= endSeq; i++)
{
nextSeq = av.getAlignment().getSequenceAt(i);
if (av.isShowSequenceFeatures())
{
fr.drawSequence(g, nextSeq, startRes, endRes, offset
- + ((i - startSeq) * avcharHeight));
+ + ((i - startSeq) * avcharHeight), false);
}
// / Highlight search Results once all sequences have been drawn
int bottom = -1;
int alHeight = av.getAlignment().getHeight() - 1;
- for (i = startSeq; i < endSeq; i++)
+ for (i = startSeq; i <= endSeq; i++)
{
sx = (group.getStartRes() - startRes) * avcharWidth;
sy = offset + ((i - startSeq) * avcharHeight);
repaint();
}
+ @Override
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ if (!av.getWrapAlignment())
+ {
+ if (evt.getPropertyName().equals("startres")
+ || evt.getPropertyName().equals("endres"))
+ {
+ // Make sure we're not trying to draw a panel
+ // larger than the visible window
+ ViewportRanges vpRanges = av.getRanges();
+ int scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
+ if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
+ {
+ scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
+ }
+ else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
+ {
+ scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
+ }
+ fastPaint(scrollX, 0);
+ }
+ else if (evt.getPropertyName().equals("startseq")
+ || evt.getPropertyName().equals("endseq"))
+ {
+ fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
+ }
+ }
+
+ }
+
}
import jalview.commands.EditCommand.Action;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SearchResultMatchI;
import jalview.datamodel.SearchResults;
import jalview.datamodel.SearchResultsI;
import jalview.structure.SequenceListener;
import jalview.structure.StructureSelectionManager;
import jalview.structure.VamsasSource;
+import jalview.util.Comparison;
import jalview.util.MappingUtils;
import jalview.util.MessageManager;
import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
import java.util.Vector;
public class SeqPanel extends Panel implements MouseMotionListener,
seqCanvas.cursorX += dx;
seqCanvas.cursorY += dy;
if (av.hasHiddenColumns()
- && !av.getColumnSelection().isVisible(seqCanvas.cursorX))
+ && !av.getAlignment().getHiddenColumns()
+ .isVisible(seqCanvas.cursorX))
{
int original = seqCanvas.cursorX - dx;
int maxWidth = av.getAlignment().getWidth();
- while (!av.getColumnSelection().isVisible(seqCanvas.cursorX)
+ while (!av.getAlignment().getHiddenColumns()
+ .isVisible(seqCanvas.cursorX)
&& seqCanvas.cursorX < maxWidth && seqCanvas.cursorX > 0)
{
seqCanvas.cursorX += dx;
}
if (seqCanvas.cursorX >= maxWidth
- || !av.getColumnSelection().isVisible(seqCanvas.cursorX))
+ || !av.getAlignment().getHiddenColumns()
+ .isVisible(seqCanvas.cursorX))
{
seqCanvas.cursorX = original;
}
endEditing();
if (av.getWrapAlignment())
{
- ap.scrollToWrappedVisible(seqCanvas.cursorX);
+ av.getRanges().scrollToWrappedVisible(seqCanvas.cursorX);
}
else
{
- while (seqCanvas.cursorY < av.startSeq)
+ ViewportRanges ranges = av.getRanges();
+ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+ while (seqCanvas.cursorY < ranges.getStartSeq())
{
- ap.scrollUp(true);
+ ranges.scrollUp(true);
}
- while (seqCanvas.cursorY + 1 > av.endSeq)
+ while (seqCanvas.cursorY > ranges.getEndSeq())
{
- ap.scrollUp(false);
+ ranges.scrollUp(false);
}
- while (seqCanvas.cursorX < av.getColumnSelection()
- .adjustForHiddenColumns(av.startRes))
+ while (seqCanvas.cursorX < hidden.adjustForHiddenColumns(ranges
+ .getStartRes()))
{
- if (!ap.scrollRight(false))
+ if (!ranges.scrollRight(false))
{
break;
}
}
- while (seqCanvas.cursorX > av.getColumnSelection()
- .adjustForHiddenColumns(av.endRes))
+ while (seqCanvas.cursorX > hidden.adjustForHiddenColumns(ranges
+ .getEndRes()))
{
- if (!ap.scrollRight(true))
+ if (!ranges.scrollRight(true))
{
break;
}
*
* @param sequence
* aligned sequence object
- * @param res
+ * @param column
* alignment column
* @param seq
* index of sequence in alignment
- * @return position of res in sequence
+ * @return position of column in sequence or -1 if at gap
*/
- void setStatusMessage(SequenceI sequence, int res, int seq)
+ void setStatusMessage(SequenceI sequence, int column, int seq)
{
// TODO remove duplication of identical gui method
StringBuilder text = new StringBuilder(32);
/*
* Try to translate the display character to residue name (null for gap).
*/
- final String displayChar = String.valueOf(sequence.getCharAt(res));
+ final String displayChar = String.valueOf(sequence.getCharAt(column));
if (av.getAlignment().isNucleotide())
{
residue = ResidueProperties.nucleotideName.get(displayChar);
int pos = -1;
if (residue != null)
{
- pos = sequence.findPosition(res);
+ pos = sequence.findPosition(column);
text.append(" (").append(Integer.toString(pos)).append(")");
}
av.setSelectionGroup(null);
}
- SequenceFeature[] features = findFeaturesAtRes(sequence,
- sequence.findPosition(findRes(evt)));
+ int column = findRes(evt);
+ boolean isGapped = Comparison.isGap(sequence.getCharAt(column));
+ List<SequenceFeature> features = findFeaturesAtRes(sequence,
+ sequence.findPosition(column));
+ if (isGapped)
+ {
+ removeAdjacentFeatures(features, column + 1, sequence);
+ }
- if (features != null && features.length > 0)
+ if (!features.isEmpty())
{
SearchResultsI highlight = new SearchResults();
- highlight.addResult(sequence, features[0].getBegin(),
- features[0].getEnd());
+ highlight.addResult(sequence, features.get(0).getBegin(), features
+ .get(0).getEnd());
seqCanvas.highlightSearchResults(highlight);
- }
- if (features != null && features.length > 0)
- {
seqCanvas.getFeatureRenderer().amendFeatures(
- new SequenceI[] { sequence }, features, false, ap);
+ Collections.singletonList(sequence), features, false, ap);
seqCanvas.highlightSearchResults(null);
}
@Override
public void mouseReleased(MouseEvent evt)
{
+ boolean didDrag = mouseDragging; // did we come here after a drag
mouseDragging = false;
mouseWheelPressed = false;
- ap.paintAlignment(true);
if (!editingSeqs)
{
- doMouseReleasedDefineMode(evt);
+ doMouseReleasedDefineMode(evt, didDrag);
return;
}
}
wrappedBlock = y / cHeight;
- wrappedBlock += av.getStartRes() / cwidth;
+ wrappedBlock += av.getRanges().getStartRes() / cwidth;
res = wrappedBlock * cwidth + x / av.getCharWidth();
}
else
{
- res = (x / av.getCharWidth()) + av.getStartRes();
+ res = (x / av.getCharWidth()) + av.getRanges().getStartRes();
}
if (av.hasHiddenColumns())
{
- res = av.getColumnSelection().adjustForHiddenColumns(res);
+ res = av.getAlignment().getHiddenColumns()
+ .adjustForHiddenColumns(res);
}
return res;
}
else
{
- seq = Math.min((y / av.getCharHeight()) + av.getStartSeq(), av
+ seq = Math.min((y / av.getCharHeight())
+ + av.getRanges().getStartSeq(),
+ av
.getAlignment().getHeight() - 1);
if (seq < 0)
{
{
if (av.isFollowHighlight())
{
+ // don't allow highlight of protein/cDNA to also scroll a complementary
+ // panel,as this sets up a feedback loop (scrolling panel 1 causes moused
+ // over residue to change abruptly, causing highlighted residue in panel 2
+ // to change, causing a scroll in panel 1 etc)
+ ap.setToScrollComplementPanel(false);
if (ap.scrollToPosition(results, true))
{
ap.alignFrame.repaint();
}
+ ap.setToScrollComplementPanel(true);
}
setStatusMessage(results);
seqCanvas.highlightSearchResults(results);
@Override
public void mouseMoved(MouseEvent evt)
{
- int res = findRes(evt);
+ final int column = findRes(evt);
int seq = findSeq(evt);
- if (seq >= av.getAlignment().getHeight() || seq < 0 || res < 0)
+ if (seq >= av.getAlignment().getHeight() || seq < 0 || column < 0)
{
if (tooltip != null)
{
}
SequenceI sequence = av.getAlignment().getSequenceAt(seq);
- if (res > sequence.getLength())
+ if (column > sequence.getLength())
{
if (tooltip != null)
{
return;
}
- int respos = sequence.findPosition(res);
- if (ssm != null)
+ final char ch = sequence.getCharAt(column);
+ boolean isGapped = Comparison.isGap(ch);
+ // find residue at column (or nearest if at a gap)
+ int respos = sequence.findPosition(column);
+
+ if (ssm != null && !isGapped)
{
- mouseOverSequence(sequence, res, respos);
+ mouseOverSequence(sequence, column, respos);
}
StringBuilder text = new StringBuilder();
text.append("Sequence ").append(Integer.toString(seq + 1))
.append(" ID: ").append(sequence.getName());
- String obj = null;
- final String ch = String.valueOf(sequence.getCharAt(res));
- if (av.getAlignment().isNucleotide())
+ if (!isGapped)
{
- obj = ResidueProperties.nucleotideName.get(ch);
- if (obj != null)
+ if (av.getAlignment().isNucleotide())
{
- text.append(" Nucleotide: ").append(obj);
+ String base = ResidueProperties.nucleotideName.get(ch);
+ text.append(" Nucleotide: ").append(base == null ? ch : base);
}
- }
- else
- {
- obj = "X".equalsIgnoreCase(ch) ? "X" : ResidueProperties.aa2Triplet
- .get(ch);
- if (obj != null)
+ else
{
- text.append(" Residue: ").append(obj);
+ String residue = (ch == 'x' || ch == 'X') ? "X"
+ : ResidueProperties.aa2Triplet
+ .get(String.valueOf(ch));
+ text.append(" Residue: ").append(residue == null ? ch : residue);
}
- }
-
- if (obj != null)
- {
text.append(" (").append(Integer.toString(respos)).append(")");
}
{
for (int g = 0; g < groups.length; g++)
{
- if (groups[g].getStartRes() <= res && groups[g].getEndRes() >= res)
+ if (groups[g].getStartRes() <= column && groups[g].getEndRes() >= column)
{
if (!groups[g].getName().startsWith("JTreeGroup")
&& !groups[g].getName().startsWith("JGroup"))
}
}
- // use aa to see if the mouse pointer is on a
- SequenceFeature[] allFeatures = findFeaturesAtRes(sequence,
- sequence.findPosition(res));
-
- int index = 0;
- while (index < allFeatures.length)
+ /*
+ * add feature details to tooltip, including any that straddle
+ * a gapped position
+ */
+ if (av.isShowSequenceFeatures())
{
- SequenceFeature sf = allFeatures[index];
-
- tooltipText.append(sf.getType() + " " + sf.begin + ":" + sf.end);
-
- if (sf.getDescription() != null)
+ List<SequenceFeature> allFeatures = findFeaturesAtRes(sequence,
+ sequence.findPosition(column));
+ if (isGapped)
{
- tooltipText.append(" " + sf.getDescription());
+ removeAdjacentFeatures(allFeatures, column + 1, sequence);
}
-
- if (sf.getValue("status") != null)
+ for (SequenceFeature sf : allFeatures)
{
- String status = sf.getValue("status").toString();
- if (status.length() > 0)
+ tooltipText.append(sf.getType() + " " + sf.begin + ":" + sf.end);
+
+ if (sf.getDescription() != null)
{
- tooltipText.append(" (" + sf.getValue("status") + ")");
+ tooltipText.append(" " + sf.getDescription());
}
- }
- tooltipText.append("\n");
- index++;
+ if (sf.getValue("status") != null)
+ {
+ String status = sf.getValue("status").toString();
+ if (status.length() > 0)
+ {
+ tooltipText.append(" (" + sf.getValue("status") + ")");
+ }
+ }
+ tooltipText.append("\n");
+ }
}
if (tooltip == null)
}
}
- SequenceFeature[] findFeaturesAtRes(SequenceI sequence, int res)
+ /**
+ * Removes from the list of features any that start after, or end before, the
+ * given column position. This allows us to retain only those features
+ * adjacent to a gapped position that straddle the position. Contact features
+ * that 'straddle' the position are also removed, since they are not 'at' the
+ * position.
+ *
+ * @param features
+ * @param column
+ * alignment column (1..)
+ * @param sequence
+ */
+ protected void removeAdjacentFeatures(List<SequenceFeature> features,
+ int column, SequenceI sequence)
+ {
+ // TODO should this be an AlignViewController method (shared by gui)?
+ ListIterator<SequenceFeature> it = features.listIterator();
+ while (it.hasNext())
+ {
+ SequenceFeature sf = it.next();
+ if (sf.isContactFeature()
+ || sequence.findIndex(sf.getBegin()) > column
+ || sequence.findIndex(sf.getEnd()) < column)
+ {
+ it.remove();
+ }
+ }
+ }
+
+ List<SequenceFeature> findFeaturesAtRes(SequenceI sequence, int res)
{
- Vector tmp = new Vector();
+ List<SequenceFeature> result = new ArrayList<SequenceFeature>();
SequenceFeature[] features = sequence.getSequenceFeatures();
if (features != null)
{
if ((features[i].getBegin() <= res)
&& (features[i].getEnd() >= res))
{
- tmp.addElement(features[i]);
+ result.add(features[i]);
}
}
}
- features = new SequenceFeature[tmp.size()];
- tmp.copyInto(features);
-
- return features;
+ return result;
}
Tooltip tooltip;
fontSize = 1;
}
- av.setFont(new Font(av.font.getName(), av.font.getStyle(), fontSize));
+ av.setFont(
+ new Font(av.font.getName(), av.font.getStyle(), fontSize),
+ true);
av.setCharWidth(oldWidth);
}
else
if (av.hasHiddenColumns())
{
fixedColumns = true;
- int y1 = av.getColumnSelection().getHiddenBoundaryLeft(startres);
- int y2 = av.getColumnSelection().getHiddenBoundaryRight(startres);
+ int y1 = av.getAlignment().getHiddenColumns()
+ .getHiddenBoundaryLeft(startres);
+ int y2 = av.getAlignment().getHiddenColumns()
+ .getHiddenBoundaryRight(startres);
if ((insertGap && startres > y1 && lastres < y1)
|| (!insertGap && startres < y2 && lastres > y2))
{
if (sg.getSize() == av.getAlignment().getHeight())
{
- if ((av.hasHiddenColumns() && startres < av
- .getColumnSelection().getHiddenBoundaryRight(startres)))
+ if ((av.hasHiddenColumns() && startres < av.getAlignment()
+ .getHiddenColumns().getHiddenBoundaryRight(startres)))
{
endEditing();
return;
stretchGroup = av.getSelectionGroup();
- if (stretchGroup == null)
+ if (stretchGroup == null || !stretchGroup.contains(sequence, res))
{
stretchGroup = av.getAlignment().findGroup(sequence, res);
- av.setSelectionGroup(stretchGroup);
- }
-
- if (stretchGroup == null
- || !stretchGroup.getSequences(null).contains(sequence)
- || stretchGroup.getStartRes() > res
- || stretchGroup.getEndRes() < res)
- {
- stretchGroup = null;
-
- SequenceGroup[] allGroups = av.getAlignment().findAllGroups(sequence);
-
- if (allGroups != null)
+ if (stretchGroup != null)
{
- for (int i = 0; i < allGroups.length; i++)
- {
- if (allGroups[i].getStartRes() <= res
- && allGroups[i].getEndRes() >= res)
- {
- stretchGroup = allGroups[i];
- break;
- }
- }
+ // only update the current selection if the popup menu has a group to
+ // focus on
+ av.setSelectionGroup(stretchGroup);
}
- av.setSelectionGroup(stretchGroup);
}
// DETECT RIGHT MOUSE BUTTON IN AWT
if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
{
- SequenceFeature[] allFeatures = findFeaturesAtRes(sequence,
+ List<SequenceFeature> allFeatures = findFeaturesAtRes(sequence,
sequence.findPosition(res));
Vector<String> links = null;
- if (allFeatures != null)
+ for (SequenceFeature sf : allFeatures)
{
- for (int i = 0; i < allFeatures.length; i++)
+ if (sf.links != null)
{
- if (allFeatures[i].links != null)
+ if (links == null)
{
- if (links == null)
- {
- links = new Vector<String>();
- }
- for (int j = 0; j < allFeatures[i].links.size(); j++)
- {
- links.addElement(allFeatures[i].links.elementAt(j));
- }
+ links = new Vector<String>();
+ }
+ for (int j = 0; j < sf.links.size(); j++)
+ {
+ links.addElement(sf.links.elementAt(j));
}
}
}
}
}
- public void doMouseReleasedDefineMode(MouseEvent evt)
+ public void doMouseReleasedDefineMode(MouseEvent evt, boolean afterDrag)
{
if (stretchGroup == null)
{
// but defer colourscheme update until hidden sequences are passed in
boolean vischange = stretchGroup.recalcConservation(true);
// here we rely on stretchGroup == av.getSelection()
- needOverviewUpdate |= vischange && av.isSelectionDefinedGroup();
+ needOverviewUpdate |= vischange && av.isSelectionDefinedGroup()
+ && afterDrag;
if (stretchGroup.cs != null)
{
stretchGroup.cs.alignmentChanged(stretchGroup,
oldSeq = -1;
}
- if (res > av.endRes || res < av.startRes || y < av.startSeq
- || y > av.endSeq)
+ if (res > av.getRanges().getEndRes()
+ || res < av.getRanges().getStartRes()
+ || y < av.getRanges().getStartSeq()
+ || y > av.getRanges().getEndSeq())
{
mouseExited(evt);
}
if (evt != null)
{
- if (mouseDragging && evt.getY() < 0 && av.getStartSeq() > 0)
+ if (mouseDragging && evt.getY() < 0
+ && av.getRanges().getStartSeq() > 0)
{
- running = ap.scrollUp(true);
+ running = av.getRanges().scrollUp(true);
}
if (mouseDragging && evt.getY() >= getSize().height
- && av.getAlignment().getHeight() > av.getEndSeq())
+ && av.getAlignment().getHeight() > av.getRanges()
+ .getEndSeq())
{
- running = ap.scrollUp(false);
+ running = av.getRanges().scrollUp(false);
}
if (mouseDragging && evt.getX() < 0)
{
- running = ap.scrollRight(false);
+ running = av.getRanges().scrollRight(false);
}
else if (mouseDragging && evt.getX() >= getSize().width)
{
- running = ap.scrollRight(true);
+ running = av.getRanges().scrollRight(true);
}
}
*/
@Override
public void selection(SequenceGroup seqsel, ColumnSelection colsel,
- SelectionSource source)
+ HiddenColumns hidden, SelectionSource source)
{
// TODO: fix this hack - source of messages is align viewport, but SeqPanel
// handles selection messages...
* Check for selection in a view of which this one is a dna/protein
* complement.
*/
- if (selectionFromTranslation(seqsel, colsel, source))
+ if (selectionFromTranslation(seqsel, colsel, hidden, source))
{
return;
}
}
else
{
- av.getColumnSelection().setElementsFrom(colsel);
+ av.getColumnSelection().setElementsFrom(colsel,
+ av.getAlignment().getHiddenColumns());
}
}
repaint |= av.isColSelChanged(true);
}
if (copycolsel
&& av.hasHiddenColumns()
- && (av.getColumnSelection() == null || av.getColumnSelection()
- .getHiddenColumns() == null))
+ && (av.getColumnSelection() == null || av.getAlignment()
+ .getHiddenColumns().getHiddenRegions() == null))
{
System.err.println("Bad things");
}
public void scrollTo(int row, int column)
{
- row = row < 0 ? ap.av.startSeq : row;
- column = column < 0 ? ap.av.startRes : column;
+ row = row < 0 ? ap.av.getRanges().getStartSeq() : row;
+ column = column < 0 ? ap.av.getRanges().getStartRes() : column;
ap.scrollTo(column, column, row, true, true);
}
public void scrollToRow(int row)
{
- row = row < 0 ? ap.av.startSeq : row;
- ap.scrollTo(ap.av.startRes, ap.av.startRes, row, true, true);
+ row = row < 0 ? ap.av.getRanges().getStartSeq() : row;
+ ap.scrollTo(ap.av.getRanges().getStartRes(), ap.av.getRanges()
+ .getStartRes(), row, true, true);
}
/**
public void scrollToColumn(int column)
{
- column = column < 0 ? ap.av.startRes : column;
- ap.scrollTo(column, column, ap.av.startSeq, true, true);
+ column = column < 0 ? ap.av.getRanges().getStartRes() : column;
+ ap.scrollTo(column, column, ap.av.getRanges().getStartSeq(), true, true);
}
/**
* @param source
*/
protected boolean selectionFromTranslation(SequenceGroup seqsel,
- ColumnSelection colsel, SelectionSource source)
+ ColumnSelection colsel, HiddenColumns hidden,
+ SelectionSource source)
{
if (!(source instanceof AlignViewportI))
{
/*
* Map column selection
*/
- ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
- av);
+ // ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
+ // av);
+ ColumnSelection cs = new ColumnSelection();
+ HiddenColumns hs = new HiddenColumns();
+ MappingUtils.mapColumnSelection(colsel, hidden, sourceAv, av, cs, hs);
av.setColumnSelection(cs);
+ av.getAlignment().setHiddenColumns(hs);
ap.scalePanelHolder.repaint();
ap.repaint();
*/
package jalview.appletgui;
-import jalview.api.FeatureRenderer;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.renderer.ResidueShaderI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import java.awt.Color;
import java.awt.Font;
this.renderGaps = renderGaps;
}
- @Override
- public Color getResidueBoxColour(SequenceI seq, int i)
+ protected Color getResidueBoxColour(SequenceI seq, int i)
{
allGroups = av.getAlignment().findAllGroups(seq);
*
* @param seq
* @param position
- * @param fr
+ * @param finder
* @return
*/
@Override
public Color getResidueColour(final SequenceI seq, int position,
- FeatureRenderer fr)
+ FeatureColourFinder finder)
{
// TODO replace 8 or so code duplications with calls to this method
// (refactored as needed)
Color col = getResidueBoxColour(seq, position);
- if (fr != null)
+ if (finder != null)
{
- col = fr.findFeatureColour(col, seq, position);
+ col = finder.findFeatureColour(col, seq, position);
}
return col;
}
void getBoxColour(ResidueShaderI shader, SequenceI seq, int i)
{
- if (shader != null)
+ if (shader.getColourScheme() != null)
{
resBoxColour = shader.findColour(seq.getCharAt(i), i, seq);
}
package jalview.appletgui;
import jalview.analysis.Conservation;
-import jalview.analysis.NJTree;
+import jalview.analysis.TreeModel;
import jalview.api.AlignViewportI;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceGroup;
import java.awt.event.MouseMotionListener;
import java.util.Enumeration;
import java.util.Hashtable;
+import java.util.List;
import java.util.Vector;
public class TreeCanvas extends Panel implements MouseListener,
MouseMotionListener
{
- NJTree tree;
+ TreeModel tree;
ScrollPane scrollPane;
selected.addOrRemove(sequence, true);
}
- public void setTree(NJTree tree)
+ public void setTree(TreeModel tree2)
{
- this.tree = tree;
- tree.findHeight(tree.getTopNode());
+ this.tree = tree2;
+ tree2.findHeight(tree2.getTopNode());
// Now have to calculate longest name based on the leaves
- Vector<SequenceNode> leaves = tree.findLeaves(tree.getTopNode());
+ Vector<SequenceNode> leaves = tree2.findLeaves(tree2.getTopNode());
boolean has_placeholders = false;
longestName = "";
}
public void drawNode(Graphics g, SequenceNode node, float chunk,
- float scale, int width, int offx, int offy)
+ double scale, int width, int offx, int offy)
{
if (node == null)
{
{
// Drawing leaf node
- float height = node.height;
- float dist = node.dist;
+ double height = node.height;
+ double dist = node.dist;
int xstart = (int) ((height - dist) * scale) + offx;
int xend = (int) (height * scale) + offx;
drawNode(g, (SequenceNode) node.right(), chunk, scale, width, offx,
offy);
- float height = node.height;
- float dist = node.dist;
+ double height = node.height;
+ double dist = node.dist;
int xstart = (int) ((height - dist) * scale) + offx;
int xend = (int) (height * scale) + offx;
g.fillRect(xend - 2, ypos - 2, 4, 4);
}
- int ystart = (int) (((SequenceNode) node.left()).ycount * chunk)
- + offy;
- int yend = (int) (((SequenceNode) node.right()).ycount * chunk)
+ int ystart = (int) (node.left() == null ? 0 : (((SequenceNode) node
+ .left()).ycount * chunk))
+ offy;
+ int yend = (int) (node.right() == null ? 0 : (((SequenceNode) node
+ .right()).ycount * chunk)) + offy;
Rectangle pos = new Rectangle(xend - 2, ypos - 2, 5, 5);
nodeHash.put(node, pos);
SequenceNode top = tree.getTopNode();
- float wscale = (float) (width * .8 - offx * 2) / tree.getMaxHeight();
+ double wscale = (float) (width * .8 - offx * 2) / tree.getMaxHeight();
if (top.count == 0)
{
top.count = ((SequenceNode) top.left()).count
}
public void pickNode(Rectangle pickBox, SequenceNode node, float chunk,
- float scale, int width, int offx, int offy)
+ double scale, int width, int offx, int offy)
{
if (node == null)
{
if (node.left() == null && node.right() == null)
{
- float height = node.height;
+ double height = node.height;
// float dist = node.dist;
// int xstart = (int) ( (height - dist) * scale) + offx;
// for
// scrollbar
- float wscale = (width - labelLength - offx * 2) / tree.getMaxHeight();
+ double wscale = (width - labelLength - offx * 2) / tree.getMaxHeight();
SequenceNode top = tree.getTopNode();
threshold = (float) (x - offx)
/ (float) (getSize().width - labelLength - 2 * offx);
- tree.getGroups().removeAllElements();
- tree.groupNodes(tree.getTopNode(), threshold);
+ List<SequenceNode> groups = tree.groupNodes(threshold);
setColor(tree.getTopNode(), Color.black);
av.setSelectionGroup(null);
codingComplement.clearSequenceColours();
}
- colourGroups();
+ colourGroups(groups);
}
}
}
- void colourGroups()
+ void colourGroups(List<SequenceNode> groups)
{
- for (int i = 0; i < tree.getGroups().size(); i++)
+ for (int i = 0; i < groups.size(); i++)
{
Color col = new Color((int) (Math.random() * 255),
(int) (Math.random() * 255), (int) (Math.random() * 255));
- setColor(tree.getGroups().elementAt(i), col.brighter());
+ setColor(groups.get(i), col.brighter());
- Vector<SequenceNode> l = tree.findLeaves(tree.getGroups()
- .elementAt(i));
+ Vector<SequenceNode> l = tree.findLeaves(groups.get(i));
Vector<SequenceI> sequences = new Vector<SequenceI>();
for (int j = 0; j < l.size(); j++)
*/
package jalview.appletgui;
+import jalview.analysis.AverageDistanceTree;
import jalview.analysis.NJTree;
+import jalview.analysis.TreeBuilder;
+import jalview.analysis.TreeModel;
+import jalview.analysis.scoremodels.ScoreModels;
+import jalview.analysis.scoremodels.SimilarityParams;
import jalview.api.analysis.ScoreModelI;
-import jalview.api.analysis.ViewBasedAnalysisI;
import jalview.datamodel.Alignment;
-import jalview.datamodel.AlignmentView;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceI;
import jalview.io.NewickFile;
-import jalview.schemes.ResidueProperties;
import jalview.util.MessageManager;
import java.awt.BorderLayout;
TreeCanvas treeCanvas;
- NJTree tree;
+ TreeModel tree;
AlignmentPanel ap;
AlignViewport av;
- public NJTree getTree()
+ public TreeModel getTree()
{
return tree;
}
+ @Override
public void finalize() throws Throwable
{
ap = null;
/**
* Creates a new TreePanel object.
- *
- * @param av
- * DOCUMENT ME!
- * @param seqVector
- * DOCUMENT ME!
- * @param type
- * DOCUMENT ME!
- * @param pwtype
- * DOCUMENT ME!
- * @param s
- * DOCUMENT ME!
- * @param e
- * DOCUMENT ME!
*/
- public TreePanel(AlignmentPanel ap, String type, String pwtype)
+ public TreePanel(AlignmentPanel alignPanel, String type, String pwtype)
{
try
{
ex.printStackTrace();
}
- initTreePanel(ap, type, pwtype, null);
+ initTreePanel(alignPanel, type, pwtype, null);
}
/**
* Creates a new TreePanel object.
*
- * @param av
- * DOCUMENT ME!
- * @param seqVector
- * DOCUMENT ME!
- * @param newtree
- * DOCUMENT ME!
- * @param type
- * DOCUMENT ME!
- * @param pwtype
- * DOCUMENT ME!
*/
public TreePanel(AlignmentPanel ap, String type, String pwtype,
NewickFile newtree)
// yields unaligned seqs)
// or create a selection box around columns in alignment view
// test Alignment(SeqCigar[])
- if (tree.seqData != null)
+ if (tree.getOriginalData() != null)
{
char gc = '-';
try
} catch (Exception ex)
{
}
- ;
- Object[] alAndColsel = tree.seqData
- .getAlignmentAndColumnSelection(gc);
+
+ Object[] alAndColsel = tree.getOriginalData()
+ .getAlignmentAndHiddenColumns(gc);
if (alAndColsel != null && alAndColsel[0] != null)
{
AlignFrame af = new AlignFrame(al, av.applet,
"Original Data for Tree", false);
- af.viewport.setHiddenColumns((ColumnSelection) alAndColsel[1]);
+ af.viewport.getAlignment().setHiddenColumns(
+ (HiddenColumns) alAndColsel[1]);
}
}
else
this.newtree = newtree;
}
+ @Override
public void run()
{
if (newtree != null)
{
- if (odata == null)
- {
- tree = new NJTree(av.getAlignment().getSequencesArray(), newtree);
- }
- else
- {
- tree = new NJTree(av.getAlignment().getSequencesArray(), odata,
- newtree);
- }
-
+ tree = new TreeModel(av.getAlignment().getSequencesArray(), odata,
+ newtree);
}
else
{
- int start, end;
- SequenceI[] seqs;
- boolean selview = av.getSelectionGroup() != null
- && av.getSelectionGroup().getSize() > 1;
- AlignmentView seqStrings = av.getAlignmentView(selview);
- if (!selview)
- {
- start = 0;
- end = av.getAlignment().getWidth();
- seqs = av.getAlignment().getSequencesArray();
- }
- else
- {
- start = av.getSelectionGroup().getStartRes();
- end = av.getSelectionGroup().getEndRes() + 1;
- seqs = av.getSelectionGroup().getSequencesInOrder(
- av.getAlignment());
- }
- ScoreModelI sm = ResidueProperties.getScoreModel(pwtype);
- if (sm instanceof ViewBasedAnalysisI)
- {
- try
- {
- sm = sm.getClass().newInstance();
- ((ViewBasedAnalysisI) sm)
- .configureFromAlignmentView(treeCanvas.ap);
- } catch (Exception q)
- {
- System.err.println("Couldn't create a scoremodel instance for "
- + sm.getName());
- q.printStackTrace();
- }
- tree = new NJTree(seqs, seqStrings, type, pwtype, sm, start, end);
- }
- else
- {
- tree = new NJTree(seqs, seqStrings, type, pwtype, null, start,
- end);
- }
+ ScoreModelI sm1 = ScoreModels.getInstance().getScoreModel(pwtype,
+ treeCanvas.ap);
+ ScoreModelI sm = sm1;
+ TreeBuilder njtree = type.equals(TreeBuilder.NEIGHBOUR_JOINING) ? new NJTree(
+ av, sm, SimilarityParams.Jalview)
+ : new AverageDistanceTree(av, sm, SimilarityParams.Jalview);
+ tree = new TreeModel(njtree);
}
tree.reCount(tree.getTopNode());
}
}
+ @Override
public void actionPerformed(ActionEvent evt)
{
if (evt.getSource() == newickOutput)
}
}
+ @Override
public void itemStateChanged(ItemEvent evt)
{
if (evt.getSource() == fitToWindow)
*/
package jalview.appletgui;
+import jalview.analysis.AAFrequency;
import jalview.api.FeatureColourI;
import jalview.datamodel.SequenceGroup;
import jalview.renderer.ResidueShader;
+import jalview.schemes.Blosum62ColourScheme;
import jalview.schemes.ColourSchemeI;
import jalview.schemes.FeatureColour;
+import jalview.schemes.PIDColourScheme;
import jalview.schemes.ResidueProperties;
import jalview.schemes.UserColourScheme;
import jalview.util.MessageManager;
return;
}
- Color[] newColours = new Color[24];
- for (int i = 0; i < 24; i++)
- {
- newColours[i] = oldColours.elementAt(i);
- buttonPanel.getComponent(i).setBackground(newColours[i]);
- }
-
- UserColourScheme ucs = new UserColourScheme(newColours);
-
if (ap != null)
{
if (seqGroup != null)
{
- seqGroup.cs = new ResidueShader(ucs);
+ seqGroup.cs = new ResidueShader(oldColourScheme);
+ if (oldColourScheme instanceof PIDColourScheme
+ || oldColourScheme instanceof Blosum62ColourScheme)
+ {
+ seqGroup.cs.setConsensus(AAFrequency.calculate(
+ seqGroup.getSequences(ap.av.getHiddenRepSequences()), 0,
+ ap.av.getAlignment().getWidth()));
+ }
}
else
{
- ap.av.setGlobalColourScheme(ucs);
+ ap.av.setGlobalColourScheme(oldColourScheme);
}
ap.paintAlignment(true);
}
- else if (jmol != null)
- {
- jmol.setJalviewColourScheme(ucs);
- }
- else if (pdbcanvas != null)
- {
- pdbcanvas.pdb.setColours(ucs);
- }
frame.setVisible(false);
}
import jalview.datamodel.PDBEntry;
import jalview.gui.UserDefinedColours;
+import jalview.schemes.ColourSchemeLoader;
import jalview.schemes.ColourSchemes;
import jalview.schemes.UserColourScheme;
import jalview.structure.StructureImportSettings;
String file = st.nextToken();
try
{
- UserColourScheme ucs = ColourSchemes.loadColourScheme(file);
+ UserColourScheme ucs = ColourSchemeLoader.loadColourScheme(file);
if (ucs != null)
{
if (coloursFound.length() > 0)
data = aparser.getValue("tree", true);
if (data != null)
{
- jalview.io.NewickFile fin = null;
try
{
System.out.println("CMD [-tree " + data
+ "] executed successfully!");
- fin = new NewickFile(data,
+ NewickFile nf = new NewickFile(data,
AppletFormatAdapter.checkProtocol(data));
- if (fin != null)
- {
- af.getViewport().setCurrentTree(
- af.ShowNewickTree(fin, data).getTree());
- }
+ af.getViewport().setCurrentTree(
+ af.showNewickTree(nf, data).getTree());
} catch (IOException ex)
{
System.err.println("Couldn't add tree " + data);
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentOrder;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceGroup;
@Override
public void run()
{
- alf.select(sel, csel);
+ alf.select(sel, csel, alf.getAlignViewport().getAlignment()
+ .getHiddenColumns());
}
});
}
SequenceI repseq = alignFrame.viewport.getAlignment()
.getSequenceAt(0);
alignFrame.viewport.getAlignment().setSeqrep(repseq);
- ColumnSelection cs = new ColumnSelection();
+ HiddenColumns cs = new HiddenColumns();
cs.hideInsertionsFor(repseq);
- alignFrame.viewport.setColumnSelection(cs);
+ alignFrame.viewport.getAlignment().setHiddenColumns(cs);
alignFrame.alignPanel.fontChanged();
alignFrame.alignPanel.setScrollValues(0, 0);
result = true;
HiddenSequences hiddenSequences;
+ HiddenColumns hiddenCols;
+
public Hashtable alignmentProperties;
private List<AlignedCodonFrame> codonFrameList;
{
groups = Collections.synchronizedList(new ArrayList<SequenceGroup>());
hiddenSequences = new HiddenSequences(this);
- codonFrameList = new ArrayList<AlignedCodonFrame>();
+ hiddenCols = new HiddenColumns();
+ codonFrameList = new ArrayList<>();
nucleotide = Comparison.isNucleotide(seqs);
public Alignment(SeqCigar[] alseqs)
{
SequenceI[] seqs = SeqCigar.createAlignmentSequences(alseqs,
- gapCharacter, new ColumnSelection(), null);
+ gapCharacter, new HiddenColumns(), null);
initAlignment(seqs);
}
return AlignmentUtils.getSequencesByName(this);
}
- /**
- * DOCUMENT ME!
- *
- * @param i
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
+
@Override
public SequenceI getSequenceAt(int i)
{
return null;
}
+ @Override
+ public SequenceI getSequenceAtAbsoluteIndex(int i)
+ {
+ SequenceI seq = null;
+ if (getHiddenSequences().getSize() > 0)
+ {
+ seq = getHiddenSequences().getHiddenSequence(i);
+ if (seq == null)
+ {
+ // didn't find the sequence in the hidden sequences, get it from the
+ // alignment
+ int index = getHiddenSequences().findIndexWithoutHiddenSeqs(i);
+ seq = getSequenceAt(index);
+ }
+ }
+ else
+ {
+ seq = getSequenceAt(i);
+ }
+ return seq;
+ }
+
/**
* Adds a sequence to the alignment. Recalculates maxLength and size. Note
* this currently does not recalculate whether or not the alignment is
}
}
- /**
- * DOCUMENT ME!
- *
- * @param s
- * DOCUMENT ME!
- */
@Override
public void deleteSequence(SequenceI s)
{
- deleteSequence(findIndex(s));
+ synchronized (sequences)
+ {
+ deleteSequence(findIndex(s));
+ }
}
- /**
- * DOCUMENT ME!
- *
- * @param i
- * DOCUMENT ME!
- */
@Override
public void deleteSequence(int i)
{
- if (i > -1 && i < getHeight())
+ synchronized (sequences)
{
- synchronized (sequences)
+ if (i > -1 && i < getHeight())
{
sequences.remove(i);
hiddenSequences.adjustHeightSequenceDeleted(i);
}
}
+ @Override
+ public void deleteHiddenSequence(int i)
+ {
+ synchronized (sequences)
+ {
+ if (i > -1 && i < getHeight())
+ {
+ sequences.remove(i);
+ }
+ }
+ }
+
/*
* (non-Javadoc)
*
@Override
public SequenceGroup[] findAllGroups(SequenceI s)
{
- ArrayList<SequenceGroup> temp = new ArrayList<SequenceGroup>();
+ ArrayList<SequenceGroup> temp = new ArrayList<>();
synchronized (groups)
{
return;
}
}
- sg.setContext(this);
+ sg.setContext(this, true);
groups.add(sg);
}
}
}
for (SequenceGroup sg : groups)
{
- sg.setContext(null);
+ sg.setContext(null, false);
}
groups.clear();
}
{
removeAnnotationForGroup(g);
groups.remove(g);
- g.setContext(null);
+ g.setContext(null, false);
}
}
}
return -1;
}
- /**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
+
@Override
public int getHeight()
{
return sequences.size();
}
- /**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
+ @Override
+ public int getAbsoluteHeight()
+ {
+ return sequences.size() + getHiddenSequences().getSize();
+ }
+
@Override
public int getWidth()
{
return true;
}
+ @Override
+ public boolean isHidden(int alignmentIndex)
+ {
+ return (getHiddenSequences().getHiddenSequence(alignmentIndex) != null);
+ }
+
/**
* Delete all annotations, including auto-calculated if the flag is set true.
* Returns true if at least one annotation was deleted, else false.
}
else if (dataset == null && data != null)
{
+ if (data == this)
+ {
+ throw new IllegalArgumentException("Circular dataset reference");
+ }
if (!(data instanceof Alignment))
{
throw new Error(
currentSeq = currentSeq.createDatasetSequence();
}
}
- if (seqs.contains(currentSeq))
- {
- return;
- }
- List<SequenceI> toProcess = new ArrayList<SequenceI>();
+
+ List<SequenceI> toProcess = new ArrayList<>();
toProcess.add(currentSeq);
while (toProcess.size() > 0)
{
// use a queue ?
SequenceI curDs = toProcess.remove(0);
- if (seqs.contains(curDs))
+
+ if (!seqs.add(curDs))
{
continue;
}
- seqs.add(curDs);
// iterate over database references, making sure we add forward referenced
// sequences
if (curDs.getDBRefs() != null)
return;
}
// try to avoid using SequenceI.equals at this stage, it will be expensive
- Set<SequenceI> seqs = new LinkedIdentityHashSet<SequenceI>();
+ Set<SequenceI> seqs = new LinkedIdentityHashSet<>();
for (int i = 0; i < getHeight(); i++)
{
}
@Override
+ public HiddenColumns getHiddenColumns()
+ {
+ return hiddenCols;
+ }
+
+ @Override
public CigarArray getCompactAlignment()
{
synchronized (sequences)
{
return null;
}
- List<AlignedCodonFrame> cframes = new ArrayList<AlignedCodonFrame>();
+ List<AlignedCodonFrame> cframes = new ArrayList<>();
for (AlignedCodonFrame acf : getCodonFrames())
{
if (acf.involvesSequence(seq))
if (sqs != null)
{
// avoid self append deadlock by
- List<SequenceI> toappendsq = new ArrayList<SequenceI>();
+ List<SequenceI> toappendsq = new ArrayList<>();
synchronized (sqs)
{
for (SequenceI addedsq : sqs)
@Override
public Iterable<AlignmentAnnotation> findAnnotation(String calcId)
{
- List<AlignmentAnnotation> aa = new ArrayList<AlignmentAnnotation>();
+ List<AlignmentAnnotation> aa = new ArrayList<>();
AlignmentAnnotation[] alignmentAnnotation = getAlignmentAnnotation();
if (alignmentAnnotation != null)
{
return aa;
}
- /**
- * Returns an iterable collection of any annotations that match on given
- * sequence ref, calcId and label (ignoring null values).
- */
@Override
public Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq,
String calcId, String label)
{
- ArrayList<AlignmentAnnotation> aa = new ArrayList<AlignmentAnnotation>();
+ ArrayList<AlignmentAnnotation> aa = new ArrayList<>();
for (AlignmentAnnotation ann : getAlignmentAnnotation())
{
- if (ann.getCalcId() != null && ann.getCalcId().equals(calcId)
- && ann.sequenceRef != null && ann.sequenceRef == seq
- && ann.label != null && ann.label.equals(label))
+ if ((calcId == null || (ann.getCalcId() != null && ann.getCalcId()
+ .equals(calcId)))
+ && (seq == null || (ann.sequenceRef != null && ann.sequenceRef == seq))
+ && (label == null || (ann.label != null && ann.label
+ .equals(label))))
{
aa.add(ann);
}
@Override
public Set<String> getSequenceNames()
{
- Set<String> names = new HashSet<String>();
+ Set<String> names = new HashSet<>();
for (SequenceI seq : getSequences())
{
names.add(seq.getName());
}
return new int[] { startPos, endPos };
}
+ @Override
+ public void setHiddenColumns(HiddenColumns cols)
+ {
+ hiddenCols = cols;
+ }
Map<Object, ContactMatrixI> contactmaps = new HashMap<Object, ContactMatrixI>();
@Override
*/
private Map<Integer, Annotation> sequenceMapping;
- /** DOCUMENT ME!! */
+ /**
+ * lower range for quantitative data
+ */
public float graphMin;
- /** DOCUMENT ME!! */
+ /**
+ * Upper range for quantitative data
+ */
public float graphMax;
/**
@Override
public String toString()
{
+ if (annotations == null)
+ {
+ return "";
+ }
StringBuilder buffer = new StringBuilder(256);
for (int i = 0; i < annotations.length; i++)
* @param colSel
*/
public AlignmentAnnotation(AlignmentAnnotation alignmentAnnotation,
- ColumnSelection colSel)
+ HiddenColumns hidden)
{
this(alignmentAnnotation);
if (annotations == null)
{
return;
}
- colSel.makeVisibleAnnotation(this);
+ hidden.makeVisibleAnnotation(this);
}
public void setPadGaps(boolean padgaps, char gapchar)
{
return counter++;
}
+
+ /**
+ *
+ * @return true for rows that have a range of values in their annotation set
+ */
+ public boolean isQuantitative()
+ {
+ return graphMin < graphMax;
+ }
}
public interface AlignmentI extends AnnotatedCollectionI
{
/**
- * Calculates the number of sequences in an alignment
+ * Calculates the number of sequences in an alignment, excluding hidden
+ * sequences
*
* @return Number of sequences in alignment
*/
int getHeight();
/**
+ * Calculates the number of sequences in an alignment, including hidden
+ * sequences
+ *
+ * @return Number of sequences in alignment
+ */
+ int getAbsoluteHeight();
+
+ /**
*
* Calculates the maximum width of the alignment, including gaps.
*
boolean isAligned(boolean includeHidden);
/**
+ * Answers if the sequence at alignmentIndex is hidden
+ *
+ * @param alignmentIndex
+ * the index to check
+ * @return true if the sequence is hidden
+ */
+ boolean isHidden(int alignmentIndex);
+
+ /**
* Gets sequences as a Synchronized collection
*
* @return All sequences in alignment.
SequenceI getSequenceAt(int i);
/**
+ * Find a specific sequence in this alignment.
+ *
+ * @param i
+ * Index of required sequence in full alignment, i.e. if all columns
+ * were visible
+ *
+ * @return SequenceI at given index.
+ */
+ SequenceI getSequenceAtAbsoluteIndex(int i);
+
+ /**
* Returns a map of lists of sequences keyed by sequence name.
*
* @return
SequenceI replaceSequenceAt(int i, SequenceI seq);
/**
- * Deletes a sequence from the alignment
+ * Deletes a sequence from the alignment. Updates hidden sequences to account
+ * for the removed sequence. Do NOT use this method to delete sequences which
+ * are just hidden.
*
* @param s
* Sequence to be deleted.
void deleteSequence(SequenceI s);
/**
- * Deletes a sequence from the alignment.
+ * Deletes a sequence from the alignment. Updates hidden sequences to account
+ * for the removed sequence. Do NOT use this method to delete sequences which
+ * are just hidden.
*
* @param i
* Index of sequence to be deleted.
void deleteSequence(int i);
/**
+ * Deletes a sequence in the alignment which has been hidden.
+ *
+ * @param i
+ * Index of sequence to be deleted
+ */
+ void deleteHiddenSequence(int i);
+
+ /**
* Finds sequence in alignment using sequence name as query.
*
* @param name
/**
* Returns the first group (in the order in which groups were added) that
- * includes the given sequence and aligned position (base 0), or null if none
- * found
+ * includes the given sequence instance and aligned position (base 0), or null
+ * if none found
*
* @param seq
+ * - must be contained in the alignment (not a dataset sequence)
* @param position
*
* @return
HiddenSequences getHiddenSequences();
+ HiddenColumns getHiddenColumns();
+
/**
* Compact representation of alignment
*
ContactListI getContactListFor(AlignmentAnnotation _aa, int column);
AlignmentAnnotation addContactList(ContactMatrixI cm);
+
+ public void setHiddenColumns(HiddenColumns cols);
}
* the view
*/
public AlignmentView(AlignmentI alignment,
- ColumnSelection columnSelection, SequenceGroup selection,
+ HiddenColumns hidden,
+ SequenceGroup selection,
boolean hasHiddenColumns, boolean selectedRegionOnly,
boolean recordGroups)
{
// refactored from AlignViewport.getAlignmentView(selectedOnly);
this(new jalview.datamodel.CigarArray(alignment,
- (hasHiddenColumns ? columnSelection : null),
+ (hasHiddenColumns ? hidden : null),
(selectedRegionOnly ? selection : null)),
(selectedRegionOnly && selection != null) ? selection
.getStartRes() : 0);
* char
* @return Object[] { SequenceI[], ColumnSelection}
*/
- public Object[] getAlignmentAndColumnSelection(char gapCharacter)
+ public Object[] getAlignmentAndHiddenColumns(char gapCharacter)
{
- ColumnSelection colsel = new ColumnSelection();
+ HiddenColumns hidden = new HiddenColumns();
return new Object[] {
- SeqCigar.createAlignmentSequences(sequences, gapCharacter, colsel,
- contigs), colsel };
+ SeqCigar.createAlignmentSequences(sequences, gapCharacter, hidden,
+ contigs), hidden };
}
/**
if (contigs != null && contigs.length > 0)
{
SequenceI[] alignment = new SequenceI[sequences.length];
- ColumnSelection columnselection = new ColumnSelection();
+ // ColumnSelection columnselection = new ColumnSelection();
+ HiddenColumns hidden = new HiddenColumns();
if (contigs != null && contigs.length > 0)
{
int start = 0;
}
}
// mark hidden segment as hidden in the new alignment
- columnselection.hideColumns(nwidth, nwidth + contigs[contig + 2]
+ hidden.hideColumns(nwidth, nwidth + contigs[contig + 2]
- 1);
nwidth += contigs[contig + 2];
}
}
}
}
- return new Object[] { alignment, columnselection };
+ return new Object[] { alignment, hidden };
}
else
{
}
if (nvismsa[0] != null)
{
- return new Object[] { nvismsa[0], new ColumnSelection() };
+ return new Object[] { nvismsa[0], new HiddenColumns() };
}
else
{
- return getAlignmentAndColumnSelection(gapCharacter);
+ return getAlignmentAndHiddenColumns(gapCharacter);
}
}
}
if (start < fwidth)
{
viscontigs[nvis] = start;
- viscontigs[nvis + 1] = fwidth; // end is inclusive
+ viscontigs[nvis + 1] = fwidth - 1; // end is inclusive
nvis += 2;
}
return viscontigs;
}
else
{
- return new int[] { 0, width };
+ return new int[] { 0, width - 1 };
}
}
}
public static void testSelectionViews(AlignmentI alignment,
- ColumnSelection csel, SequenceGroup selection)
+ HiddenColumns hidden, SequenceGroup selection)
{
System.out.println("Testing standard view creation:\n");
AlignmentView view = null;
{
System.out
.println("View with no hidden columns, no limit to selection, no groups to be collected:");
- view = new AlignmentView(alignment, csel, selection, false, false,
+ view = new AlignmentView(alignment, hidden, selection, false, false,
false);
summariseAlignmentView(view, System.out);
{
System.out
.println("View with no hidden columns, no limit to selection, and all groups to be collected:");
- view = new AlignmentView(alignment, csel, selection, false, false,
+ view = new AlignmentView(alignment, hidden, selection, false, false,
true);
summariseAlignmentView(view, System.out);
} catch (Exception e)
{
System.out
.println("View with no hidden columns, limited to selection and no groups to be collected:");
- view = new AlignmentView(alignment, csel, selection, false, true,
+ view = new AlignmentView(alignment, hidden, selection, false, true,
false);
summariseAlignmentView(view, System.out);
} catch (Exception e)
{
System.out
.println("View with no hidden columns, limited to selection, and all groups to be collected:");
- view = new AlignmentView(alignment, csel, selection, false, true,
+ view = new AlignmentView(alignment, hidden, selection, false, true,
true);
summariseAlignmentView(view, System.out);
} catch (Exception e)
{
System.out
.println("View *with* hidden columns, no limit to selection, no groups to be collected:");
- view = new AlignmentView(alignment, csel, selection, true, false,
+ view = new AlignmentView(alignment, hidden, selection, true, false,
false);
summariseAlignmentView(view, System.out);
} catch (Exception e)
{
System.out
.println("View *with* hidden columns, no limit to selection, and all groups to be collected:");
- view = new AlignmentView(alignment, csel, selection, true, false,
+ view = new AlignmentView(alignment, hidden, selection, true, false,
true);
summariseAlignmentView(view, System.out);
} catch (Exception e)
{
System.out
.println("View *with* hidden columns, limited to selection and no groups to be collected:");
- view = new AlignmentView(alignment, csel, selection, true, true,
+ view = new AlignmentView(alignment, hidden, selection, true, true,
false);
summariseAlignmentView(view, System.out);
} catch (Exception e)
{
System.out
.println("View *with* hidden columns, limited to selection, and all groups to be collected:");
- view = new AlignmentView(alignment, csel, selection, true, true, true);
+ view = new AlignmentView(alignment, hidden, selection, true, true,
+ true);
summariseAlignmentView(view, System.out);
} catch (Exception e)
{
--- /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.
+ */
+package jalview.datamodel;
+
+import jalview.api.AlignmentColsCollectionI;
+
+import java.util.Iterator;
+
+public class AllColsCollection implements AlignmentColsCollectionI
+{
+ int start;
+ int end;
+
+ HiddenColumns hidden;
+
+ public AllColsCollection(int s, int e, AlignmentI al)
+ {
+ start = s;
+ end = e;
+ hidden = al.getHiddenColumns();
+ }
+
+ @Override
+ public Iterator<Integer> iterator()
+ {
+ return new AllColsIterator(start,end,hidden);
+ }
+
+ @Override
+ public boolean isHidden(int c)
+ {
+ return !hidden.isVisible(c);
+ }
+}
--- /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.
+ */
+package jalview.datamodel;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * An iterator which iterates over all columns or rows in an alignment, whether
+ * hidden or visible.
+ *
+ * @author kmourao
+ *
+ */
+public class AllColsIterator implements Iterator<Integer>
+{
+ private int last;
+
+ private int next;
+
+ private int current;
+
+ public AllColsIterator(int firstcol, int lastcol, HiddenColumns hiddenCols)
+ {
+ last = lastcol;
+ next = firstcol;
+ current = firstcol;
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return next <= last;
+ }
+
+ @Override
+ public Integer next()
+ {
+ if (next > last)
+ {
+ throw new NoSuchElementException();
+ }
+ current = next;
+ next++;
+
+ return current;
+ }
+
+ @Override
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+}
+
--- /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.
+ */
+package jalview.datamodel;
+
+import jalview.api.AlignmentRowsCollectionI;
+
+import java.util.Iterator;
+
+public class AllRowsCollection implements AlignmentRowsCollectionI
+{
+ int start;
+
+ int end;
+
+ AlignmentI alignment;
+
+ HiddenSequences hidden;
+
+ public AllRowsCollection(int s, int e, AlignmentI al)
+ {
+ start = s;
+ end = e;
+ alignment = al;
+ hidden = al.getHiddenSequences();
+ }
+
+ @Override
+ public Iterator<Integer> iterator()
+ {
+ return new AllRowsIterator(start, end, alignment);
+ }
+
+ @Override
+ public boolean isHidden(int seq)
+ {
+ return hidden.isHidden(seq);
+ }
+
+ @Override
+ public SequenceI getSequence(int seq)
+ {
+ return alignment.getSequenceAtAbsoluteIndex(seq);
+ }
+}
+
--- /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.
+ */
+package jalview.datamodel;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * An iterator which iterates over all columns or rows in an alignment, whether
+ * hidden or visible.
+ *
+ * @author kmourao
+ *
+ */
+public class AllRowsIterator implements Iterator<Integer>
+{
+ private int last;
+
+ private int next;
+
+ private int current;
+
+ private AlignmentI al;
+
+ public AllRowsIterator(int firstrow, int lastrow, AlignmentI alignment)
+ {
+ last = lastrow;
+ current = firstrow;
+ next = firstrow;
+ al = alignment;
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return next <= last;
+ }
+
+ @Override
+ public Integer next()
+ {
+ if (next > last)
+ {
+ throw new NoSuchElementException();
+ }
+ current = next;
+ next++;
+
+ return current;
+ }
+
+ @Override
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+}
+
+
*/
Iterable<AlignmentAnnotation> findAnnotation(String calcId);
+ /**
+ * Returns an iterable collection of any annotations that match on given
+ * sequence ref, calcId and label (ignoring null values).
+ *
+ * @param seq
+ * null or reference sequence to select annotation for
+ * @param calcId
+ * null or the calcId to select annotation for
+ * @param label
+ * null or the label to select annotation for
+ */
Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq,
String calcId, String label);
*/
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);
+ }
}
*/
package jalview.datamodel;
+import jalview.analysis.scoremodels.ScoreMatrix;
import jalview.schemes.ResidueProperties;
-import jalview.schemes.ScoreMatrix;
/**
* Encode a sequence as a numeric vector using either classic residue binary
{
int nores = (isNa) ? ResidueProperties.maxNucleotideIndex
: ResidueProperties.maxProteinIndex;
- // Set all matrix to 0
+
dbinary = new double[getSequence().length * nores];
- for (int i = 0; i < dbinary.length; i++)
- {
- dbinary[i] = 0.0;
- }
return nores;
}
/**
* ancode using substitution matrix given in matrix
*
- * @param matrix
+ * @param smtrx
*/
- public void matrixEncode(final ScoreMatrix matrix)
+ public void matrixEncode(final ScoreMatrix smtrx)
throws InvalidSequenceTypeException
{
- if (isNa != matrix.isDNA())
+ if (isNa != smtrx.isDNA())
{
throw new InvalidSequenceTypeException("matrix "
- + matrix.getClass().getCanonicalName()
+ + smtrx.getClass().getCanonicalName()
+ " is not a valid matrix for "
+ (isNa ? "nucleotide" : "protein") + "sequences");
}
- matrixEncode(matrix.isDNA() ? ResidueProperties.nucleotideIndex
- : ResidueProperties.aaIndex, matrix.getMatrix());
+ matrixEncode(smtrx.isDNA() ? ResidueProperties.nucleotideIndex
+ : ResidueProperties.aaIndex, smtrx.getMatrix());
}
- private void matrixEncode(final int[] aaIndex, final int[][] matrix)
+ private void matrixEncode(final int[] aaIndex, final float[][] matrix)
{
- // Set all matrix to 0
- // dbinary = new double[getSequence().length * 21];
-
int nores = initMatrixGetNoRes();
- // for (int i = 0; i < dbinary.length; i++) {
- // dbinary[i] = 0.0;
- // }
for (int i = 0, iSize = getSequence().length; i < iSize; i++)
{
int aanum = nores - 1;
* @param columnSelection
* @param selectionGroup
*/
- public CigarArray(AlignmentI alignment, ColumnSelection columnSelection,
+ public CigarArray(AlignmentI alignment, HiddenColumns hidden,
SequenceGroup selectionGroup)
{
this(constructSeqCigarArray(alignment, selectionGroup));
constructFromAlignment(alignment,
- columnSelection != null ? columnSelection.getHiddenColumns()
+ hidden != null ? hidden.getHiddenRegions()
: null, selectionGroup);
}
}
/**
- * @see Cigar.getSequenceAndDeletions
+ * @see CigarBase.getSequenceAndDeletions
* @param GapChar
* char
* @return Object[][]
*/
package jalview.datamodel;
-import jalview.util.Comparison;
-import jalview.util.ShiftList;
import jalview.viewmodel.annotationfilter.AnnotationFilterParameter;
import jalview.viewmodel.annotationfilter.AnnotationFilterParameter.SearchableAnnotationField;
import java.util.BitSet;
import java.util.Collections;
import java.util.List;
-import java.util.Vector;
/**
* Data class holding the selected columns and hidden column ranges for a view.
IntList selection = new IntList();
- /*
- * list of hidden column [start, end] ranges; the list is maintained in
- * ascending start column order
- */
- Vector<int[]> hiddenColumns;
-
/**
* Add a column to the selection
*
return selection.getMinColumn();
}
- /**
- * propagate shift in alignment columns to column selection
- *
- * @param start
- * beginning of edit
- * @param left
- * shift in edit (+ve for removal, or -ve for inserts)
- */
- public List<int[]> compensateForEdit(int start, int change)
- {
- List<int[]> deletedHiddenColumns = null;
- selection.compensateForEdits(start, change);
-
- if (hiddenColumns != null)
- {
- deletedHiddenColumns = new ArrayList<int[]>();
- int hSize = hiddenColumns.size();
- for (int i = 0; i < hSize; i++)
- {
- int[] region = hiddenColumns.elementAt(i);
- if (region[0] > start && start + change > region[1])
- {
- deletedHiddenColumns.add(region);
-
- hiddenColumns.removeElementAt(i);
- i--;
- hSize--;
- continue;
- }
-
- if (region[0] > start)
- {
- region[0] -= change;
- region[1] -= change;
- }
-
- if (region[0] < 0)
- {
- region[0] = 0;
- }
-
- }
-
- this.revealHiddenColumns(0);
- }
-
- return deletedHiddenColumns;
- }
-
- /**
- * propagate shift in alignment columns to column selection special version of
- * compensateForEdit - allowing for edits within hidden regions
- *
- * @param start
- * beginning of edit
- * @param left
- * shift in edit (+ve for removal, or -ve for inserts)
- */
- private void compensateForDelEdits(int start, int change)
- {
-
- selection.compensateForEdits(start, change);
-
- if (hiddenColumns != null)
- {
- for (int i = 0; i < hiddenColumns.size(); i++)
- {
- int[] region = hiddenColumns.elementAt(i);
- if (region[0] >= start)
- {
- region[0] -= change;
- }
- if (region[1] >= start)
- {
- region[1] -= change;
- }
- if (region[1] < region[0])
- {
- hiddenColumns.removeElementAt(i--);
- }
-
- if (region[0] < 0)
- {
- region[0] = 0;
- }
- if (region[1] < 0)
- {
- region[1] = 0;
- }
- }
- }
- }
-
- /**
- * Adjust hidden column boundaries based on a series of column additions or
- * deletions in visible regions.
- *
- * @param shiftrecord
- * @return
- */
- public ShiftList compensateForEdits(ShiftList shiftrecord)
- {
- if (shiftrecord != null)
- {
- final List<int[]> shifts = shiftrecord.getShifts();
- if (shifts != null && shifts.size() > 0)
- {
- int shifted = 0;
- for (int i = 0, j = shifts.size(); i < j; i++)
- {
- int[] sh = shifts.get(i);
- // compensateForEdit(shifted+sh[0], sh[1]);
- compensateForDelEdits(shifted + sh[0], sh[1]);
- shifted -= sh[1];
- }
- }
- return shiftrecord.getInverse();
- }
- return null;
- }
-
- /**
- * removes intersection of position,length ranges in deletions from the
- * start,end regions marked in intervals.
- *
- * @param shifts
- * @param intervals
- * @return
- */
- private boolean pruneIntervalVector(final List<int[]> shifts,
- Vector<int[]> intervals)
- {
- boolean pruned = false;
- int i = 0, j = intervals.size() - 1, s = 0, t = shifts.size() - 1;
- int hr[] = intervals.elementAt(i);
- int sr[] = shifts.get(s);
- while (i <= j && s <= t)
- {
- boolean trailinghn = hr[1] >= sr[0];
- if (!trailinghn)
- {
- if (i < j)
- {
- hr = intervals.elementAt(++i);
- }
- else
- {
- i++;
- }
- continue;
- }
- int endshift = sr[0] + sr[1]; // deletion ranges - -ve means an insert
- if (endshift < hr[0] || endshift < sr[0])
- { // leadinghc disjoint or not a deletion
- if (s < t)
- {
- sr = shifts.get(++s);
- }
- else
- {
- s++;
- }
- continue;
- }
- boolean leadinghn = hr[0] >= sr[0];
- boolean leadinghc = hr[0] < endshift;
- boolean trailinghc = hr[1] < endshift;
- if (leadinghn)
- {
- if (trailinghc)
- { // deleted hidden region.
- intervals.removeElementAt(i);
- pruned = true;
- j--;
- if (i <= j)
- {
- hr = intervals.elementAt(i);
- }
- continue;
- }
- if (leadinghc)
- {
- hr[0] = endshift; // clip c terminal region
- leadinghn = !leadinghn;
- pruned = true;
- }
- }
- if (!leadinghn)
- {
- if (trailinghc)
- {
- if (trailinghn)
- {
- hr[1] = sr[0] - 1;
- pruned = true;
- }
- }
- else
- {
- // sr contained in hr
- if (s < t)
- {
- sr = shifts.get(++s);
- }
- else
- {
- s++;
- }
- continue;
- }
- }
- }
- return pruned; // true if any interval was removed or modified by
- // operations.
- }
-
- /**
- * remove any hiddenColumns or selected columns and shift remaining based on a
- * series of position, range deletions.
- *
- * @param deletions
- */
- public void pruneDeletions(ShiftList deletions)
- {
- if (deletions != null)
- {
- final List<int[]> shifts = deletions.getShifts();
- if (shifts != null && shifts.size() > 0)
- {
- // delete any intervals intersecting.
- if (hiddenColumns != null)
- {
- pruneIntervalVector(shifts, hiddenColumns);
- if (hiddenColumns != null && hiddenColumns.size() == 0)
- {
- hiddenColumns = null;
- }
- }
- if (selection != null && selection.size() > 0)
- {
- selection.pruneColumnList(shifts);
- if (selection != null && selection.size() == 0)
- {
- selection = null;
- }
- }
- // and shift the rest.
- this.compensateForEdits(deletions);
- }
- }
- }
-
- /**
- * This Method is used to return all the HiddenColumn regions
- *
- * @return empty list or List of hidden column intervals
- */
- public List<int[]> getHiddenColumns()
- {
- return hiddenColumns == null ? Collections.<int[]> emptyList()
- : hiddenColumns;
- }
-
- /**
- * Return absolute column index for a visible column index
- *
- * @param column
- * int column index in alignment view (count from zero)
- * @return alignment column index for column
- */
- public int adjustForHiddenColumns(int column)
- {
- int result = column;
- if (hiddenColumns != null)
- {
- for (int i = 0; i < hiddenColumns.size(); i++)
- {
- int[] region = hiddenColumns.elementAt(i);
- if (result >= region[0])
- {
- result += region[1] - region[0] + 1;
- }
- }
- }
- return result;
- }
-
- /**
- * Use this method to find out where a column will appear in the visible
- * alignment when hidden columns exist. If the column is not visible, then the
- * left-most visible column will always be returned.
- *
- * @param hiddenColumn
- * int
- * @return int
- */
- public int findColumnPosition(int hiddenColumn)
- {
- int result = hiddenColumn;
- if (hiddenColumns != null)
- {
- int index = 0;
- int[] region;
- do
- {
- region = hiddenColumns.elementAt(index++);
- if (hiddenColumn > region[1])
- {
- result -= region[1] + 1 - region[0];
- }
- } while ((hiddenColumn > region[1]) && (index < hiddenColumns.size()));
- if (hiddenColumn > region[0] && hiddenColumn < region[1])
- {
- return region[0] + hiddenColumn - result;
- }
- }
- return result; // return the shifted position after removing hidden columns.
- }
-
- /**
- * Use this method to determine where the next hiddenRegion starts
- *
- * @param hiddenRegion
- * index of hidden region (counts from 0)
- * @return column number in visible view
- */
- public int findHiddenRegionPosition(int hiddenRegion)
- {
- int result = 0;
- if (hiddenColumns != null)
- {
- int index = 0;
- int gaps = 0;
- do
- {
- int[] region = hiddenColumns.elementAt(index);
- if (hiddenRegion == 0)
- {
- return region[0];
- }
-
- gaps += region[1] + 1 - region[0];
- result = region[1] + 1;
- index++;
- } while (index <= hiddenRegion);
-
- result -= gaps;
- }
-
- return result;
- }
-
- /**
- * THis method returns the rightmost limit of a region of an alignment with
- * hidden columns. In otherwords, the next hidden column.
- *
- * @param index
- * int
- */
- public int getHiddenBoundaryRight(int alPos)
- {
- if (hiddenColumns != null)
- {
- int index = 0;
- do
- {
- int[] region = hiddenColumns.elementAt(index);
- if (alPos < region[0])
- {
- return region[0];
- }
-
- index++;
- } while (index < hiddenColumns.size());
- }
-
- return alPos;
-
- }
-
- /**
- * This method returns the leftmost limit of a region of an alignment with
- * hidden columns. In otherwords, the previous hidden column.
- *
- * @param index
- * int
- */
- public int getHiddenBoundaryLeft(int alPos)
- {
- if (hiddenColumns != null)
- {
- int index = hiddenColumns.size() - 1;
- do
- {
- int[] region = hiddenColumns.elementAt(index);
- if (alPos > region[1])
- {
- return region[1];
- }
-
- index--;
- } while (index > -1);
- }
-
- return alPos;
-
- }
-
- public void hideSelectedColumns()
+ public void hideSelectedColumns(AlignmentI al)
{
synchronized (selection)
{
for (int[] selregions : selection.getRanges())
{
- hideColumns(selregions[0], selregions[1]);
+ al.getHiddenColumns().hideColumns(selregions[0], selregions[1]);
}
selection.clear();
}
}
- /**
- * Adds the specified column range to the hidden columns
- *
- * @param start
- * @param end
- */
- public void hideColumns(int start, int end)
- {
- if (hiddenColumns == null)
- {
- hiddenColumns = new Vector<int[]>();
- }
-
- /*
- * traverse existing hidden ranges and insert / amend / append as
- * appropriate
- */
- for (int i = 0; i < hiddenColumns.size(); i++)
- {
- int[] region = hiddenColumns.elementAt(i);
-
- if (end < region[0] - 1)
- {
- /*
- * insert discontiguous preceding range
- */
- hiddenColumns.insertElementAt(new int[] { start, end }, i);
- return;
- }
-
- if (end <= region[1])
- {
- /*
- * new range overlaps existing, or is contiguous preceding it - adjust
- * start column
- */
- region[0] = Math.min(region[0], start);
- return;
- }
-
- if (start <= region[1] + 1)
- {
- /*
- * new range overlaps existing, or is contiguous following it - adjust
- * start and end columns
- */
- region[0] = Math.min(region[0], start);
- region[1] = Math.max(region[1], end);
-
- /*
- * also update or remove any subsequent ranges
- * that are overlapped
- */
- while (i < hiddenColumns.size() - 1)
- {
- int[] nextRegion = hiddenColumns.get(i + 1);
- if (nextRegion[0] > end + 1)
- {
- /*
- * gap to next hidden range - no more to update
- */
- break;
- }
- region[1] = Math.max(nextRegion[1], end);
- hiddenColumns.remove(i + 1);
- }
- return;
- }
- }
-
- /*
- * remaining case is that the new range follows everything else
- */
- hiddenColumns.addElement(new int[] { start, end });
- }
/**
* Hides the specified column and any adjacent selected columns
* @param res
* int
*/
- public void hideColumns(int col)
+ public void hideSelectedColumns(int col, HiddenColumns hidden)
{
/*
* deselect column (whether selected or not!)
min = max;
}
- hideColumns(min, max);
+ hidden.hideColumns(min, max);
}
- /**
- * Unhides, and adds to the selection list, all hidden columns
- */
- public void revealAllHiddenColumns()
- {
- if (hiddenColumns != null)
- {
- for (int i = 0; i < hiddenColumns.size(); i++)
- {
- int[] region = hiddenColumns.elementAt(i);
- for (int j = region[0]; j < region[1] + 1; j++)
- {
- addElement(j);
- }
- }
- }
- hiddenColumns = null;
- }
- /**
- * Reveals, and marks as selected, the hidden column range with the given
- * start column
- *
- * @param start
- */
- public void revealHiddenColumns(int start)
- {
- for (int i = 0; i < hiddenColumns.size(); i++)
- {
- int[] region = hiddenColumns.elementAt(i);
- if (start == region[0])
- {
- for (int j = region[0]; j < region[1] + 1; j++)
- {
- addElement(j);
- }
- hiddenColumns.removeElement(region);
- break;
- }
- }
- if (hiddenColumns.size() == 0)
- {
- hiddenColumns = null;
- }
- }
-
- public boolean isVisible(int column)
- {
- if (hiddenColumns != null)
- {
- for (int[] region : hiddenColumns)
- {
- if (column >= region[0] && column <= region[1])
- {
- return false;
- }
- }
- }
-
- return true;
- }
/**
* Copy constructor
if (copy != null)
{
selection = new IntList(copy.selection);
- if (copy.hiddenColumns != null)
- {
- hiddenColumns = new Vector<int[]>(copy.hiddenColumns.size());
- for (int i = 0, j = copy.hiddenColumns.size(); i < j; i++)
- {
- int[] rh, cp;
- rh = copy.hiddenColumns.elementAt(i);
- if (rh != null)
- {
- cp = new int[rh.length];
- System.arraycopy(rh, 0, cp, 0, rh.length);
- hiddenColumns.addElement(cp);
- }
- }
- }
}
}
{
}
- public String[] getVisibleSequenceStrings(int start, int end,
- SequenceI[] seqs)
- {
- int i, iSize = seqs.length;
- String selections[] = new String[iSize];
- if (hiddenColumns != null && hiddenColumns.size() > 0)
- {
- for (i = 0; i < iSize; i++)
- {
- StringBuffer visibleSeq = new StringBuffer();
- List<int[]> regions = getHiddenColumns();
-
- int blockStart = start, blockEnd = end;
- int[] region;
- int hideStart, hideEnd;
-
- for (int j = 0; j < regions.size(); j++)
- {
- region = regions.get(j);
- hideStart = region[0];
- hideEnd = region[1];
-
- if (hideStart < start)
- {
- continue;
- }
-
- blockStart = Math.min(blockStart, hideEnd + 1);
- blockEnd = Math.min(blockEnd, hideStart);
-
- if (blockStart > blockEnd)
- {
- break;
- }
-
- visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));
-
- blockStart = hideEnd + 1;
- blockEnd = end;
- }
-
- if (end > blockStart)
- {
- visibleSeq.append(seqs[i].getSequence(blockStart, end));
- }
-
- selections[i] = visibleSeq.toString();
- }
- }
- else
- {
- for (i = 0; i < iSize; i++)
- {
- selections[i] = seqs[i].getSequenceAsString(start, end);
- }
- }
-
- return selections;
- }
-
- /**
- * return all visible segments between the given start and end boundaries
- *
- * @param start
- * (first column inclusive from 0)
- * @param end
- * (last column - not inclusive)
- * @return int[] {i_start, i_end, ..} where intervals lie in
- * start<=i_start<=i_end<end
- */
- public int[] getVisibleContigs(int start, int end)
- {
- if (hiddenColumns != null && hiddenColumns.size() > 0)
- {
- List<int[]> visiblecontigs = new ArrayList<int[]>();
- List<int[]> regions = getHiddenColumns();
-
- int vstart = start;
- int[] region;
- int hideStart, hideEnd;
-
- for (int j = 0; vstart < end && j < regions.size(); j++)
- {
- region = regions.get(j);
- hideStart = region[0];
- hideEnd = region[1];
-
- if (hideEnd < vstart)
- {
- continue;
- }
- if (hideStart > vstart)
- {
- visiblecontigs.add(new int[] { vstart, hideStart - 1 });
- }
- vstart = hideEnd + 1;
- }
-
- if (vstart < end)
- {
- visiblecontigs.add(new int[] { vstart, end - 1 });
- }
- int[] vcontigs = new int[visiblecontigs.size() * 2];
- for (int i = 0, j = visiblecontigs.size(); i < j; i++)
- {
- int[] vc = visiblecontigs.get(i);
- visiblecontigs.set(i, null);
- vcontigs[i * 2] = vc[0];
- vcontigs[i * 2 + 1] = vc[1];
- }
- visiblecontigs.clear();
- return vcontigs;
- }
- else
- {
- return new int[] { start, end - 1 };
- }
- }
-
- /**
- * Locate the first and last position visible for this sequence. if seq isn't
- * visible then return the position of the left and right of the hidden
- * boundary region, and the corresponding alignment column indices for the
- * extent of the sequence
- *
- * @param seq
- * @return int[] { visible start, visible end, first seqpos, last seqpos,
- * alignment index for seq start, alignment index for seq end }
- */
- public int[] locateVisibleBoundsOfSequence(SequenceI seq)
- {
- int fpos = seq.getStart(), lpos = seq.getEnd();
- int start = 0;
-
- if (hiddenColumns == null || hiddenColumns.size() == 0)
- {
- int ifpos = seq.findIndex(fpos) - 1, ilpos = seq.findIndex(lpos) - 1;
- return new int[] { ifpos, ilpos, fpos, lpos, ifpos, ilpos };
- }
-
- // Simply walk along the sequence whilst watching for hidden column
- // boundaries
- List<int[]> regions = getHiddenColumns();
- int spos = fpos, lastvispos = -1, rcount = 0, hideStart = seq
- .getLength(), hideEnd = -1;
- int visPrev = 0, visNext = 0, firstP = -1, lastP = -1;
- boolean foundStart = false;
- for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd()
- && p < pLen; p++)
- {
- if (!Comparison.isGap(seq.getCharAt(p)))
- {
- // keep track of first/last column
- // containing sequence data regardless of visibility
- if (firstP == -1)
- {
- firstP = p;
- }
- lastP = p;
- // update hidden region start/end
- while (hideEnd < p && rcount < regions.size())
- {
- int[] region = regions.get(rcount++);
- visPrev = visNext;
- visNext += region[0] - visPrev;
- hideStart = region[0];
- hideEnd = region[1];
- }
- if (hideEnd < p)
- {
- hideStart = seq.getLength();
- }
- // update visible boundary for sequence
- if (p < hideStart)
- {
- if (!foundStart)
- {
- fpos = spos;
- start = p;
- foundStart = true;
- }
- lastvispos = p;
- lpos = spos;
- }
- // look for next sequence position
- spos++;
- }
- }
- if (foundStart)
- {
- return new int[] { findColumnPosition(start),
- findColumnPosition(lastvispos), fpos, lpos, firstP, lastP };
- }
- // otherwise, sequence was completely hidden
- return new int[] { visPrev, visNext, 0, 0, firstP, lastP };
- }
-
- /**
- * delete any columns in alignmentAnnotation that are hidden (including
- * sequence associated annotation).
- *
- * @param alignmentAnnotation
- */
- public void makeVisibleAnnotation(AlignmentAnnotation alignmentAnnotation)
- {
- makeVisibleAnnotation(-1, -1, alignmentAnnotation);
- }
-
- /**
- * delete any columns in alignmentAnnotation that are hidden (including
- * sequence associated annotation).
- *
- * @param start
- * remove any annotation to the right of this column
- * @param end
- * remove any annotation to the left of this column
- * @param alignmentAnnotation
- * the annotation to operate on
- */
- public void makeVisibleAnnotation(int start, int end,
- AlignmentAnnotation alignmentAnnotation)
- {
- if (alignmentAnnotation.annotations == null)
- {
- return;
- }
- if (start == end && end == -1)
- {
- start = 0;
- end = alignmentAnnotation.annotations.length;
- }
- if (hiddenColumns != null && hiddenColumns.size() > 0)
- {
- // then mangle the alignmentAnnotation annotation array
- Vector<Annotation[]> annels = new Vector<Annotation[]>();
- Annotation[] els = null;
- List<int[]> regions = getHiddenColumns();
- int blockStart = start, blockEnd = end;
- int[] region;
- int hideStart, hideEnd, w = 0;
-
- for (int j = 0; j < regions.size(); j++)
- {
- region = regions.get(j);
- hideStart = region[0];
- hideEnd = region[1];
-
- if (hideStart < start)
- {
- continue;
- }
- blockStart = Math.min(blockStart, hideEnd + 1);
- blockEnd = Math.min(blockEnd, hideStart);
- if (blockStart > blockEnd)
- {
- break;
- }
- annels.addElement(els = new Annotation[blockEnd - blockStart]);
- System.arraycopy(alignmentAnnotation.annotations, blockStart, els,
- 0, els.length);
- w += els.length;
- blockStart = hideEnd + 1;
- blockEnd = end;
- }
- if (end > blockStart)
- {
- annels.addElement(els = new Annotation[end - blockStart + 1]);
- if ((els.length + blockStart) <= alignmentAnnotation.annotations.length)
- {
- // copy just the visible segment of the annotation row
- System.arraycopy(alignmentAnnotation.annotations, blockStart,
- els, 0, els.length);
- }
- else
- {
- // copy to the end of the annotation row
- System.arraycopy(alignmentAnnotation.annotations, blockStart,
- els, 0,
- (alignmentAnnotation.annotations.length - blockStart));
- }
- w += els.length;
- }
- if (w == 0)
- {
- return;
- }
-
- alignmentAnnotation.annotations = new Annotation[w];
- w = 0;
-
- for (Annotation[] chnk : annels)
- {
- System.arraycopy(chnk, 0, alignmentAnnotation.annotations, w,
- chnk.length);
- w += chnk.length;
- }
- }
- else
- {
- alignmentAnnotation.restrict(start, end);
- }
- }
/**
* Invert the column selection from first to end-1. leaves hiddenColumns
* @param first
* @param end
*/
- public void invertColumnSelection(int first, int width)
+ public void invertColumnSelection(int first, int width, AlignmentI al)
{
- boolean hasHidden = hiddenColumns != null && hiddenColumns.size() > 0;
+ boolean hasHidden = al.getHiddenColumns().hasHidden();
for (int i = first; i < width; i++)
{
if (contains(i))
}
else
{
- if (!hasHidden || isVisible(i))
+ if (!hasHidden || al.getHiddenColumns().isVisible(i))
{
addElement(i);
}
}
/**
- * add in any unselected columns from the given column selection, excluding
- * any that are hidden.
+ * set the selected columns to the given column selection, excluding any
+ * columns that are hidden.
*
* @param colsel
*/
- public void addElementsFrom(ColumnSelection colsel)
- {
- if (colsel != null && !colsel.isEmpty())
- {
- for (Integer col : colsel.getSelected())
- {
- if (hiddenColumns != null && isVisible(col.intValue()))
- {
- selection.add(col);
- }
- }
- }
- }
-
- /**
- * set the selected columns the given column selection, excluding any columns
- * that are hidden.
- *
- * @param colsel
- */
- public void setElementsFrom(ColumnSelection colsel)
+ public void setElementsFrom(ColumnSelection colsel,
+ HiddenColumns hiddenColumns)
{
selection = new IntList();
if (colsel.selection != null && colsel.selection.size() > 0)
{
- if (hiddenColumns != null && hiddenColumns.size() > 0)
+ if (hiddenColumns.hasHidden())
{
// only select visible columns in this columns selection
- addElementsFrom(colsel);
- }
- else
- {
- // add everything regardless
for (Integer col : colsel.getSelected())
{
- addElement(col);
- }
- }
- }
- }
-
- /**
- * Add gaps into the sequences aligned to profileseq under the given
- * AlignmentView
- *
- * @param profileseq
- * @param al
- * - alignment to have gaps inserted into it
- * @param input
- * - alignment view where sequence corresponding to profileseq is
- * first entry
- * @return new Column selection for new alignment view, with insertions into
- * profileseq marked as hidden.
- */
- public static ColumnSelection propagateInsertions(SequenceI profileseq,
- AlignmentI al, AlignmentView input)
- {
- int profsqpos = 0;
-
- // return propagateInsertions(profileseq, al, )
- char gc = al.getGapCharacter();
- Object[] alandcolsel = input.getAlignmentAndColumnSelection(gc);
- ColumnSelection nview = (ColumnSelection) alandcolsel[1];
- SequenceI origseq = ((SequenceI[]) alandcolsel[0])[profsqpos];
- nview.propagateInsertions(profileseq, al, origseq);
- return nview;
- }
-
- /**
- *
- * @param profileseq
- * - sequence in al which corresponds to origseq
- * @param al
- * - alignment which is to have gaps inserted into it
- * @param origseq
- * - sequence corresponding to profileseq which defines gap map for
- * modifying al
- */
- public void propagateInsertions(SequenceI profileseq, AlignmentI al,
- SequenceI origseq)
- {
- char gc = al.getGapCharacter();
- // recover mapping between sequence's non-gap positions and positions
- // mapping to view.
- pruneDeletions(ShiftList.parseMap(origseq.gapMap()));
- int[] viscontigs = getVisibleContigs(0, profileseq.getLength());
- int spos = 0;
- int offset = 0;
- // input.pruneDeletions(ShiftList.parseMap(((SequenceI[])
- // alandcolsel[0])[0].gapMap()))
- // add profile to visible contigs
- for (int v = 0; v < viscontigs.length; v += 2)
- {
- if (viscontigs[v] > spos)
- {
- StringBuffer sb = new StringBuffer();
- for (int s = 0, ns = viscontigs[v] - spos; s < ns; s++)
- {
- sb.append(gc);
- }
- for (int s = 0, ns = al.getHeight(); s < ns; s++)
- {
- SequenceI sqobj = al.getSequenceAt(s);
- if (sqobj != profileseq)
+ if (hiddenColumns != null
+ && hiddenColumns.isVisible(col.intValue()))
{
- String sq = al.getSequenceAt(s).getSequenceAsString();
- if (sq.length() <= spos + offset)
- {
- // pad sequence
- int diff = spos + offset - sq.length() - 1;
- if (diff > 0)
- {
- // pad gaps
- sq = sq + sb;
- while ((diff = spos + offset - sq.length() - 1) > 0)
- {
- // sq = sq
- // + ((diff >= sb.length()) ? sb.toString() : sb
- // .substring(0, diff));
- if (diff >= sb.length())
- {
- sq += sb.toString();
- }
- else
- {
- char[] buf = new char[diff];
- sb.getChars(0, diff, buf, 0);
- sq += buf.toString();
- }
- }
- }
- sq += sb.toString();
- }
- else
- {
- al.getSequenceAt(s).setSequence(
- sq.substring(0, spos + offset) + sb.toString()
- + sq.substring(spos + offset));
- }
+ selection.add(col);
}
}
- // offset+=sb.length();
- }
- spos = viscontigs[v + 1] + 1;
- }
- if ((offset + spos) < profileseq.getLength())
- {
- // pad the final region with gaps.
- StringBuffer sb = new StringBuffer();
- for (int s = 0, ns = profileseq.getLength() - spos - offset; s < ns; s++)
- {
- sb.append(gc);
}
- for (int s = 0, ns = al.getHeight(); s < ns; s++)
+ else
{
- SequenceI sqobj = al.getSequenceAt(s);
- if (sqobj == profileseq)
- {
- continue;
- }
- String sq = sqobj.getSequenceAsString();
- // pad sequence
- int diff = origseq.getLength() - sq.length();
- while (diff > 0)
+ // add everything regardless
+ for (Integer col : colsel.getSelected())
{
- // sq = sq
- // + ((diff >= sb.length()) ? sb.toString() : sb
- // .substring(0, diff));
- if (diff >= sb.length())
- {
- sq += sb.toString();
- }
- else
- {
- char[] buf = new char[diff];
- sb.getChars(0, diff, buf, 0);
- sq += buf.toString();
- }
- diff = origseq.getLength() - sq.length();
+ addElement(col);
}
}
}
}
+
/**
*
* @return true if there are columns marked
return (selection != null && selection.size() > 0);
}
- /**
- *
- * @return true if there are columns hidden
- */
- public boolean hasHiddenColumns()
- {
- return hiddenColumns != null && hiddenColumns.size() > 0;
- }
- /**
- *
- * @return true if there are more than one set of columns hidden
- */
- public boolean hasManyHiddenColumns()
- {
- return hiddenColumns != null && hiddenColumns.size() > 1;
- }
-
- /**
- * mark the columns corresponding to gap characters as hidden in the column
- * selection
- *
- * @param sr
- */
- public void hideInsertionsFor(SequenceI sr)
- {
- List<int[]> inserts = sr.getInsertions();
- for (int[] r : inserts)
- {
- hideColumns(r[0], r[1]);
- }
- }
public boolean filterAnnotations(Annotation[] annotations,
AnnotationFilterParameter filterParams)
{
// JBPNote - this method needs to be refactored to become independent of
// viewmodel package
- this.revealAllHiddenColumns();
this.clear();
int count = 0;
do
}
/**
- * Returns a hashCode built from selected columns and hidden column ranges
+ * Returns a hashCode built from selected columns ranges
*/
@Override
public int hashCode()
{
- int hashCode = selection.hashCode();
- if (hiddenColumns != null)
- {
- for (int[] hidden : hiddenColumns)
- {
- hashCode = 31 * hashCode + hidden[0];
- hashCode = 31 * hashCode + hidden[1];
- }
- }
- return hashCode;
+ return selection.hashCode();
}
/**
return false;
}
- /*
- * check hidden columns are either both null, or match
- */
- if (this.hiddenColumns == null)
- {
- return (that.hiddenColumns == null);
- }
- if (that.hiddenColumns == null
- || that.hiddenColumns.size() != this.hiddenColumns.size())
- {
- return false;
- }
- int i = 0;
- for (int[] thisRange : hiddenColumns)
- {
- int[] thatRange = that.hiddenColumns.get(i++);
- if (thisRange[0] != thatRange[0] || thisRange[1] != thatRange[1])
- {
- return false;
- }
- }
return true;
}
--- /dev/null
+package jalview.datamodel;
+
+import jalview.util.Comparison;
+import jalview.util.ShiftList;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.List;
+import java.util.Vector;
+
+public class HiddenColumns
+{
+ /*
+ * list of hidden column [start, end] ranges; the list is maintained in
+ * ascending start column order
+ */
+ private Vector<int[]> hiddenColumns;
+
+ /**
+ * This Method is used to return all the HiddenColumn regions
+ *
+ * @return empty list or List of hidden column intervals
+ */
+ public List<int[]> getHiddenRegions()
+ {
+ return hiddenColumns == null ? Collections.<int[]> emptyList()
+ : hiddenColumns;
+ }
+
+ /**
+ * Find the number of hidden columns
+ *
+ * @return number of hidden columns
+ */
+ public int getSize()
+ {
+ int size = 0;
+ if (hasHidden())
+ {
+ for (int[] range : hiddenColumns)
+ {
+ size += range[1] - range[0] + 1;
+ }
+ }
+ return size;
+ }
+
+ /**
+ * Answers if there are any hidden columns
+ *
+ * @return true if there are hidden columns
+ */
+ public boolean hasHidden()
+ {
+ return (hiddenColumns != null) && (!hiddenColumns.isEmpty());
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof HiddenColumns))
+ {
+ return false;
+ }
+ HiddenColumns that = (HiddenColumns) obj;
+
+ /*
+ * check hidden columns are either both null, or match
+ */
+ if (this.hiddenColumns == null)
+ {
+ return (that.hiddenColumns == null);
+ }
+ if (that.hiddenColumns == null
+ || that.hiddenColumns.size() != this.hiddenColumns.size())
+ {
+ return false;
+ }
+ int i = 0;
+ for (int[] thisRange : hiddenColumns)
+ {
+ int[] thatRange = that.hiddenColumns.get(i++);
+ if (thisRange[0] != thatRange[0] || thisRange[1] != thatRange[1])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Return absolute column index for a visible column index
+ *
+ * @param column
+ * int column index in alignment view (count from zero)
+ * @return alignment column index for column
+ */
+ public int adjustForHiddenColumns(int column)
+ {
+ int result = column;
+ if (hiddenColumns != null)
+ {
+ for (int i = 0; i < hiddenColumns.size(); i++)
+ {
+ int[] region = hiddenColumns.elementAt(i);
+ if (result >= region[0])
+ {
+ result += region[1] - region[0] + 1;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Use this method to find out where a column will appear in the visible
+ * alignment when hidden columns exist. If the column is not visible, then the
+ * left-most visible column will always be returned.
+ *
+ * @param hiddenColumn
+ * the column index in the full alignment including hidden columns
+ * @return the position of the column in the visible alignment
+ */
+ public int findColumnPosition(int hiddenColumn)
+ {
+ int result = hiddenColumn;
+ if (hiddenColumns != null)
+ {
+ int index = 0;
+ int[] region;
+ do
+ {
+ region = hiddenColumns.elementAt(index++);
+ if (hiddenColumn > region[1])
+ {
+ result -= region[1] + 1 - region[0];
+ }
+ } while ((hiddenColumn > region[1]) && (index < hiddenColumns.size()));
+
+ if (hiddenColumn >= region[0] && hiddenColumn <= region[1])
+ {
+ // Here the hidden column is within a region, so
+ // we want to return the position of region[0]-1, adjusted for any
+ // earlier hidden columns.
+ // Calculate the difference between the actual hidden col position
+ // and region[0]-1, and then subtract from result to convert result from
+ // the adjusted hiddenColumn value to the adjusted region[0]-1 value
+
+ // However, if the region begins at 0 we cannot return region[0]-1
+ // just return 0
+ if (region[0] == 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return result - (hiddenColumn - region[0] + 1);
+ }
+ }
+ }
+ return result; // return the shifted position after removing hidden columns.
+ }
+
+ /**
+ * Find the visible column which is a given visible number of columns to the
+ * left of another visible column. i.e. for a startColumn x, the column which
+ * is distance 1 away will be column x-1.
+ *
+ * @param visibleDistance
+ * the number of visible columns to offset by
+ * @param startColumn
+ * the column to start from
+ * @return the position of the column in the visible alignment
+ */
+ public int subtractVisibleColumns(int visibleDistance, int startColumn)
+ {
+ int distance = visibleDistance;
+
+ // in case startColumn is in a hidden region, move it to the left
+ int start = adjustForHiddenColumns(findColumnPosition(startColumn));
+
+ // get index of hidden region to left of start
+ int index = getHiddenIndexLeft(start);
+ if (index == -1)
+ {
+ // no hidden regions to left of startColumn
+ return start - distance;
+ }
+
+ // walk backwards through the alignment subtracting the counts of visible
+ // columns from distance
+ int[] region;
+ int gap = 0;
+ int nextstart = start;
+
+ while ((index > -1) && (distance - gap > 0))
+ {
+ // subtract the gap to right of region from distance
+ distance -= gap;
+ start = nextstart;
+
+ // calculate the next gap
+ region = hiddenColumns.get(index);
+ gap = start - region[1];
+
+ // set start to just to left of current region
+ nextstart = region[0] - 1;
+ index--;
+ }
+
+ if (distance - gap > 0)
+ {
+ // fell out of loop because there are no more hidden regions
+ distance -= gap;
+ return nextstart - distance;
+ }
+ return start - distance;
+
+ }
+
+ /**
+ * Use this method to determine where the next hiddenRegion starts
+ *
+ * @param hiddenRegion
+ * index of hidden region (counts from 0)
+ * @return column number in visible view
+ */
+ public int findHiddenRegionPosition(int hiddenRegion)
+ {
+ int result = 0;
+ if (hiddenColumns != null)
+ {
+ int index = 0;
+ int gaps = 0;
+ do
+ {
+ int[] region = hiddenColumns.elementAt(index);
+ if (hiddenRegion == 0)
+ {
+ return region[0];
+ }
+
+ gaps += region[1] + 1 - region[0];
+ result = region[1] + 1;
+ index++;
+ } while (index <= hiddenRegion);
+
+ result -= gaps;
+ }
+
+ return result;
+ }
+
+ /**
+ * This method returns the rightmost limit of a region of an alignment with
+ * hidden columns. In otherwords, the next hidden column.
+ *
+ * @param index
+ * int
+ */
+ public int getHiddenBoundaryRight(int alPos)
+ {
+ if (hiddenColumns != null)
+ {
+ int index = 0;
+ do
+ {
+ int[] region = hiddenColumns.elementAt(index);
+ if (alPos < region[0])
+ {
+ return region[0];
+ }
+
+ index++;
+ } while (index < hiddenColumns.size());
+ }
+
+ return alPos;
+
+ }
+
+ /**
+ * This method returns the leftmost limit of a region of an alignment with
+ * hidden columns. In otherwords, the previous hidden column.
+ *
+ * @param index
+ * int
+ */
+ public int getHiddenBoundaryLeft(int alPos)
+ {
+ if (hiddenColumns != null)
+ {
+ int index = hiddenColumns.size() - 1;
+ do
+ {
+ int[] region = hiddenColumns.elementAt(index);
+ if (alPos > region[1])
+ {
+ return region[1];
+ }
+
+ index--;
+ } while (index > -1);
+ }
+
+ return alPos;
+
+ }
+
+ /**
+ * This method returns the index of the hidden region to the left of a column
+ * position. If the column is in a hidden region it returns the index of the
+ * region to the left. If there is no hidden region to the left it returns -1.
+ *
+ * @param pos
+ * int
+ */
+ private int getHiddenIndexLeft(int pos)
+ {
+ if (hiddenColumns != null)
+ {
+ int index = hiddenColumns.size() - 1;
+ do
+ {
+ int[] region = hiddenColumns.elementAt(index);
+ if (pos > region[1])
+ {
+ return index;
+ }
+
+ index--;
+ } while (index > -1);
+ }
+
+ return -1;
+
+ }
+
+ /**
+ * Adds the specified column range to the hidden columns
+ *
+ * @param start
+ * @param end
+ */
+ public void hideColumns(int start, int end)
+ {
+ if (hiddenColumns == null)
+ {
+ hiddenColumns = new Vector<int[]>();
+ }
+
+ /*
+ * traverse existing hidden ranges and insert / amend / append as
+ * appropriate
+ */
+ for (int i = 0; i < hiddenColumns.size(); i++)
+ {
+ int[] region = hiddenColumns.elementAt(i);
+
+ if (end < region[0] - 1)
+ {
+ /*
+ * insert discontiguous preceding range
+ */
+ hiddenColumns.insertElementAt(new int[] { start, end }, i);
+ return;
+ }
+
+ if (end <= region[1])
+ {
+ /*
+ * new range overlaps existing, or is contiguous preceding it - adjust
+ * start column
+ */
+ region[0] = Math.min(region[0], start);
+ return;
+ }
+
+ if (start <= region[1] + 1)
+ {
+ /*
+ * new range overlaps existing, or is contiguous following it - adjust
+ * start and end columns
+ */
+ region[0] = Math.min(region[0], start);
+ region[1] = Math.max(region[1], end);
+
+ /*
+ * also update or remove any subsequent ranges
+ * that are overlapped
+ */
+ while (i < hiddenColumns.size() - 1)
+ {
+ int[] nextRegion = hiddenColumns.get(i + 1);
+ if (nextRegion[0] > end + 1)
+ {
+ /*
+ * gap to next hidden range - no more to update
+ */
+ break;
+ }
+ region[1] = Math.max(nextRegion[1], end);
+ hiddenColumns.remove(i + 1);
+ }
+ return;
+ }
+ }
+
+ /*
+ * remaining case is that the new range follows everything else
+ */
+ hiddenColumns.addElement(new int[] { start, end });
+ }
+
+ public boolean isVisible(int column)
+ {
+ if (hiddenColumns != null)
+ {
+ for (int[] region : hiddenColumns)
+ {
+ if (column >= region[0] && column <= region[1])
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * ColumnSelection
+ */
+ public HiddenColumns()
+ {
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param copy
+ */
+ public HiddenColumns(HiddenColumns copy)
+ {
+ if (copy != null)
+ {
+ if (copy.hiddenColumns != null)
+ {
+ hiddenColumns = new Vector<int[]>(copy.hiddenColumns.size());
+ for (int i = 0, j = copy.hiddenColumns.size(); i < j; i++)
+ {
+ int[] rh, cp;
+ rh = copy.hiddenColumns.elementAt(i);
+ if (rh != null)
+ {
+ cp = new int[rh.length];
+ System.arraycopy(rh, 0, cp, 0, rh.length);
+ hiddenColumns.addElement(cp);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * propagate shift in alignment columns to column selection
+ *
+ * @param start
+ * beginning of edit
+ * @param left
+ * shift in edit (+ve for removal, or -ve for inserts)
+ */
+ public List<int[]> compensateForEdit(int start, int change,
+ ColumnSelection sel)
+ {
+ List<int[]> deletedHiddenColumns = null;
+
+ if (hiddenColumns != null)
+ {
+ deletedHiddenColumns = new ArrayList<int[]>();
+ int hSize = hiddenColumns.size();
+ for (int i = 0; i < hSize; i++)
+ {
+ int[] region = hiddenColumns.elementAt(i);
+ if (region[0] > start && start + change > region[1])
+ {
+ deletedHiddenColumns.add(region);
+
+ hiddenColumns.removeElementAt(i);
+ i--;
+ hSize--;
+ continue;
+ }
+
+ if (region[0] > start)
+ {
+ region[0] -= change;
+ region[1] -= change;
+ }
+
+ if (region[0] < 0)
+ {
+ region[0] = 0;
+ }
+
+ }
+
+ this.revealHiddenColumns(0, sel);
+ }
+
+ return deletedHiddenColumns;
+ }
+
+ /**
+ * propagate shift in alignment columns to column selection special version of
+ * compensateForEdit - allowing for edits within hidden regions
+ *
+ * @param start
+ * beginning of edit
+ * @param left
+ * shift in edit (+ve for removal, or -ve for inserts)
+ */
+ public void compensateForDelEdits(int start, int change)
+ {
+ if (hiddenColumns != null)
+ {
+ for (int i = 0; i < hiddenColumns.size(); i++)
+ {
+ int[] region = hiddenColumns.elementAt(i);
+ if (region[0] >= start)
+ {
+ region[0] -= change;
+ }
+ if (region[1] >= start)
+ {
+ region[1] -= change;
+ }
+ if (region[1] < region[0])
+ {
+ hiddenColumns.removeElementAt(i--);
+ }
+
+ if (region[0] < 0)
+ {
+ region[0] = 0;
+ }
+ if (region[1] < 0)
+ {
+ region[1] = 0;
+ }
+ }
+ }
+ }
+
+ /**
+ * return all visible segments between the given start and end boundaries
+ *
+ * @param start
+ * (first column inclusive from 0)
+ * @param end
+ * (last column - not inclusive)
+ * @return int[] {i_start, i_end, ..} where intervals lie in
+ * start<=i_start<=i_end<end
+ */
+ public int[] getVisibleContigs(int start, int end)
+ {
+ if (hiddenColumns != null && hiddenColumns.size() > 0)
+ {
+ List<int[]> visiblecontigs = new ArrayList<int[]>();
+ List<int[]> regions = getHiddenRegions();
+
+ int vstart = start;
+ int[] region;
+ int hideStart, hideEnd;
+
+ for (int j = 0; vstart < end && j < regions.size(); j++)
+ {
+ region = regions.get(j);
+ hideStart = region[0];
+ hideEnd = region[1];
+
+ if (hideEnd < vstart)
+ {
+ continue;
+ }
+ if (hideStart > vstart)
+ {
+ visiblecontigs.add(new int[] { vstart, hideStart - 1 });
+ }
+ vstart = hideEnd + 1;
+ }
+
+ if (vstart < end)
+ {
+ visiblecontigs.add(new int[] { vstart, end - 1 });
+ }
+ int[] vcontigs = new int[visiblecontigs.size() * 2];
+ for (int i = 0, j = visiblecontigs.size(); i < j; i++)
+ {
+ int[] vc = visiblecontigs.get(i);
+ visiblecontigs.set(i, null);
+ vcontigs[i * 2] = vc[0];
+ vcontigs[i * 2 + 1] = vc[1];
+ }
+ visiblecontigs.clear();
+ return vcontigs;
+ }
+ else
+ {
+ return new int[] { start, end - 1 };
+ }
+ }
+
+ public String[] getVisibleSequenceStrings(int start, int end,
+ SequenceI[] seqs)
+ {
+ int i, iSize = seqs.length;
+ String selections[] = new String[iSize];
+ if (hiddenColumns != null && hiddenColumns.size() > 0)
+ {
+ for (i = 0; i < iSize; i++)
+ {
+ StringBuffer visibleSeq = new StringBuffer();
+ List<int[]> regions = getHiddenRegions();
+
+ int blockStart = start, blockEnd = end;
+ int[] region;
+ int hideStart, hideEnd;
+
+ for (int j = 0; j < regions.size(); j++)
+ {
+ region = regions.get(j);
+ hideStart = region[0];
+ hideEnd = region[1];
+
+ if (hideStart < start)
+ {
+ continue;
+ }
+
+ blockStart = Math.min(blockStart, hideEnd + 1);
+ blockEnd = Math.min(blockEnd, hideStart);
+
+ if (blockStart > blockEnd)
+ {
+ break;
+ }
+
+ visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));
+
+ blockStart = hideEnd + 1;
+ blockEnd = end;
+ }
+
+ if (end > blockStart)
+ {
+ visibleSeq.append(seqs[i].getSequence(blockStart, end));
+ }
+
+ selections[i] = visibleSeq.toString();
+ }
+ }
+ else
+ {
+ for (i = 0; i < iSize; i++)
+ {
+ selections[i] = seqs[i].getSequenceAsString(start, end);
+ }
+ }
+
+ return selections;
+ }
+
+ /**
+ * Locate the first and last position visible for this sequence. if seq isn't
+ * visible then return the position of the left and right of the hidden
+ * boundary region, and the corresponding alignment column indices for the
+ * extent of the sequence
+ *
+ * @param seq
+ * @return int[] { visible start, visible end, first seqpos, last seqpos,
+ * alignment index for seq start, alignment index for seq end }
+ */
+ public int[] locateVisibleBoundsOfSequence(SequenceI seq)
+ {
+ int fpos = seq.getStart(), lpos = seq.getEnd();
+ int start = 0;
+
+ if (hiddenColumns == null || hiddenColumns.size() == 0)
+ {
+ int ifpos = seq.findIndex(fpos) - 1, ilpos = seq.findIndex(lpos) - 1;
+ return new int[] { ifpos, ilpos, fpos, lpos, ifpos, ilpos };
+ }
+
+ // Simply walk along the sequence whilst watching for hidden column
+ // boundaries
+ List<int[]> regions = getHiddenRegions();
+ int spos = fpos, lastvispos = -1, rcount = 0, hideStart = seq
+ .getLength(), hideEnd = -1;
+ int visPrev = 0, visNext = 0, firstP = -1, lastP = -1;
+ boolean foundStart = false;
+ for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd()
+ && p < pLen; p++)
+ {
+ if (!Comparison.isGap(seq.getCharAt(p)))
+ {
+ // keep track of first/last column
+ // containing sequence data regardless of visibility
+ if (firstP == -1)
+ {
+ firstP = p;
+ }
+ lastP = p;
+ // update hidden region start/end
+ while (hideEnd < p && rcount < regions.size())
+ {
+ int[] region = regions.get(rcount++);
+ visPrev = visNext;
+ visNext += region[0] - visPrev;
+ hideStart = region[0];
+ hideEnd = region[1];
+ }
+ if (hideEnd < p)
+ {
+ hideStart = seq.getLength();
+ }
+ // update visible boundary for sequence
+ if (p < hideStart)
+ {
+ if (!foundStart)
+ {
+ fpos = spos;
+ start = p;
+ foundStart = true;
+ }
+ lastvispos = p;
+ lpos = spos;
+ }
+ // look for next sequence position
+ spos++;
+ }
+ }
+ if (foundStart)
+ {
+ return new int[] { findColumnPosition(start),
+ findColumnPosition(lastvispos), fpos, lpos, firstP, lastP };
+ }
+ // otherwise, sequence was completely hidden
+ return new int[] { visPrev, visNext, 0, 0, firstP, lastP };
+ }
+
+ /**
+ * delete any columns in alignmentAnnotation that are hidden (including
+ * sequence associated annotation).
+ *
+ * @param alignmentAnnotation
+ */
+ public void makeVisibleAnnotation(AlignmentAnnotation alignmentAnnotation)
+ {
+ makeVisibleAnnotation(-1, -1, alignmentAnnotation);
+ }
+
+ /**
+ * delete any columns in alignmentAnnotation that are hidden (including
+ * sequence associated annotation).
+ *
+ * @param start
+ * remove any annotation to the right of this column
+ * @param end
+ * remove any annotation to the left of this column
+ * @param alignmentAnnotation
+ * the annotation to operate on
+ */
+ public void makeVisibleAnnotation(int start, int end,
+ AlignmentAnnotation alignmentAnnotation)
+ {
+ if (alignmentAnnotation.annotations == null)
+ {
+ return;
+ }
+ if (start == end && end == -1)
+ {
+ start = 0;
+ end = alignmentAnnotation.annotations.length;
+ }
+ if (hiddenColumns != null && hiddenColumns.size() > 0)
+ {
+ // then mangle the alignmentAnnotation annotation array
+ Vector<Annotation[]> annels = new Vector<Annotation[]>();
+ Annotation[] els = null;
+ List<int[]> regions = getHiddenRegions();
+ int blockStart = start, blockEnd = end;
+ int[] region;
+ int hideStart, hideEnd, w = 0;
+
+ for (int j = 0; j < regions.size(); j++)
+ {
+ region = regions.get(j);
+ hideStart = region[0];
+ hideEnd = region[1];
+
+ if (hideStart < start)
+ {
+ continue;
+ }
+
+ blockStart = Math.min(blockStart, hideEnd + 1);
+ blockEnd = Math.min(blockEnd, hideStart);
+
+ if (blockStart > blockEnd)
+ {
+ break;
+ }
+
+ annels.addElement(els = new Annotation[blockEnd - blockStart]);
+ System.arraycopy(alignmentAnnotation.annotations, blockStart, els,
+ 0, els.length);
+ w += els.length;
+ blockStart = hideEnd + 1;
+ blockEnd = end;
+ }
+
+ if (end > blockStart)
+ {
+ annels.addElement(els = new Annotation[end - blockStart + 1]);
+ if ((els.length + blockStart) <= alignmentAnnotation.annotations.length)
+ {
+ // copy just the visible segment of the annotation row
+ System.arraycopy(alignmentAnnotation.annotations, blockStart,
+ els, 0, els.length);
+ }
+ else
+ {
+ // copy to the end of the annotation row
+ System.arraycopy(alignmentAnnotation.annotations, blockStart,
+ els, 0,
+ (alignmentAnnotation.annotations.length - blockStart));
+ }
+ w += els.length;
+ }
+ if (w == 0)
+ {
+ return;
+ }
+
+ alignmentAnnotation.annotations = new Annotation[w];
+ w = 0;
+
+ for (Annotation[] chnk : annels)
+ {
+ System.arraycopy(chnk, 0, alignmentAnnotation.annotations, w,
+ chnk.length);
+ w += chnk.length;
+ }
+ }
+ else
+ {
+ alignmentAnnotation.restrict(start, end);
+ }
+ }
+
+ /**
+ *
+ * @return true if there are columns hidden
+ */
+ public boolean hasHiddenColumns()
+ {
+ return hiddenColumns != null && hiddenColumns.size() > 0;
+ }
+
+ /**
+ *
+ * @return true if there are more than one set of columns hidden
+ */
+ public boolean hasManyHiddenColumns()
+ {
+ return hiddenColumns != null && hiddenColumns.size() > 1;
+ }
+
+ /**
+ * mark the columns corresponding to gap characters as hidden in the column
+ * selection
+ *
+ * @param sr
+ */
+ public void hideInsertionsFor(SequenceI sr)
+ {
+ List<int[]> inserts = sr.getInsertions();
+ for (int[] r : inserts)
+ {
+ hideColumns(r[0], r[1]);
+ }
+ }
+
+ /**
+ * Unhides, and adds to the selection list, all hidden columns
+ */
+ public void revealAllHiddenColumns(ColumnSelection sel)
+ {
+ if (hiddenColumns != null)
+ {
+ for (int i = 0; i < hiddenColumns.size(); i++)
+ {
+ int[] region = hiddenColumns.elementAt(i);
+ for (int j = region[0]; j < region[1] + 1; j++)
+ {
+ sel.addElement(j);
+ }
+ }
+ }
+
+ hiddenColumns = null;
+ }
+
+ /**
+ * Reveals, and marks as selected, the hidden column range with the given
+ * start column
+ *
+ * @param start
+ */
+ public void revealHiddenColumns(int start, ColumnSelection sel)
+ {
+ for (int i = 0; i < hiddenColumns.size(); i++)
+ {
+ int[] region = hiddenColumns.elementAt(i);
+ if (start == region[0])
+ {
+ for (int j = region[0]; j < region[1] + 1; j++)
+ {
+ sel.addElement(j);
+ }
+
+ hiddenColumns.removeElement(region);
+ break;
+ }
+ }
+ if (hiddenColumns.size() == 0)
+ {
+ hiddenColumns = null;
+ }
+ }
+
+ /**
+ * removes intersection of position,length ranges in deletions from the
+ * start,end regions marked in intervals.
+ *
+ * @param shifts
+ * @param intervals
+ * @return
+ */
+ private boolean pruneIntervalVector(final List<int[]> shifts,
+ Vector<int[]> intervals)
+ {
+ boolean pruned = false;
+ int i = 0, j = intervals.size() - 1, s = 0, t = shifts.size() - 1;
+ int hr[] = intervals.elementAt(i);
+ int sr[] = shifts.get(s);
+ while (i <= j && s <= t)
+ {
+ boolean trailinghn = hr[1] >= sr[0];
+ if (!trailinghn)
+ {
+ if (i < j)
+ {
+ hr = intervals.elementAt(++i);
+ }
+ else
+ {
+ i++;
+ }
+ continue;
+ }
+ int endshift = sr[0] + sr[1]; // deletion ranges - -ve means an insert
+ if (endshift < hr[0] || endshift < sr[0])
+ { // leadinghc disjoint or not a deletion
+ if (s < t)
+ {
+ sr = shifts.get(++s);
+ }
+ else
+ {
+ s++;
+ }
+ continue;
+ }
+ boolean leadinghn = hr[0] >= sr[0];
+ boolean leadinghc = hr[0] < endshift;
+ boolean trailinghc = hr[1] < endshift;
+ if (leadinghn)
+ {
+ if (trailinghc)
+ { // deleted hidden region.
+ intervals.removeElementAt(i);
+ pruned = true;
+ j--;
+ if (i <= j)
+ {
+ hr = intervals.elementAt(i);
+ }
+ continue;
+ }
+ if (leadinghc)
+ {
+ hr[0] = endshift; // clip c terminal region
+ leadinghn = !leadinghn;
+ pruned = true;
+ }
+ }
+ if (!leadinghn)
+ {
+ if (trailinghc)
+ {
+ if (trailinghn)
+ {
+ hr[1] = sr[0] - 1;
+ pruned = true;
+ }
+ }
+ else
+ {
+ // sr contained in hr
+ if (s < t)
+ {
+ sr = shifts.get(++s);
+ }
+ else
+ {
+ s++;
+ }
+ continue;
+ }
+ }
+ }
+ return pruned; // true if any interval was removed or modified by
+ // operations.
+ }
+
+ /**
+ * remove any hiddenColumns or selected columns and shift remaining based on a
+ * series of position, range deletions.
+ *
+ * @param deletions
+ */
+ public void pruneDeletions(List<int[]> shifts)
+ {
+ // delete any intervals intersecting.
+ if (hiddenColumns != null)
+ {
+ pruneIntervalVector(shifts, hiddenColumns);
+ if (hiddenColumns != null && hiddenColumns.size() == 0)
+ {
+ hiddenColumns = null;
+ }
+ }
+ }
+
+ /**
+ * Add gaps into the sequences aligned to profileseq under the given
+ * AlignmentView
+ *
+ * @param profileseq
+ * @param al
+ * - alignment to have gaps inserted into it
+ * @param input
+ * - alignment view where sequence corresponding to profileseq is
+ * first entry
+ * @return new HiddenColumns for new alignment view, with insertions into
+ * profileseq marked as hidden.
+ */
+ public static HiddenColumns propagateInsertions(SequenceI profileseq,
+ AlignmentI al, AlignmentView input)
+ {
+ int profsqpos = 0;
+
+ char gc = al.getGapCharacter();
+ Object[] alandhidden = input.getAlignmentAndHiddenColumns(gc);
+ HiddenColumns nview = (HiddenColumns) alandhidden[1];
+ SequenceI origseq = ((SequenceI[]) alandhidden[0])[profsqpos];
+ nview.propagateInsertions(profileseq, al, origseq);
+ return nview;
+ }
+
+ /**
+ *
+ * @param profileseq
+ * - sequence in al which corresponds to origseq
+ * @param al
+ * - alignment which is to have gaps inserted into it
+ * @param origseq
+ * - sequence corresponding to profileseq which defines gap map for
+ * modifying al
+ */
+ private void propagateInsertions(SequenceI profileseq, AlignmentI al,
+ SequenceI origseq)
+ {
+ char gc = al.getGapCharacter();
+ // recover mapping between sequence's non-gap positions and positions
+ // mapping to view.
+ pruneDeletions(ShiftList.parseMap(origseq.gapMap()));
+ int[] viscontigs = al.getHiddenColumns().getVisibleContigs(0,
+ profileseq.getLength());
+ int spos = 0;
+ int offset = 0;
+
+ // add profile to visible contigs
+ for (int v = 0; v < viscontigs.length; v += 2)
+ {
+ if (viscontigs[v] > spos)
+ {
+ StringBuffer sb = new StringBuffer();
+ for (int s = 0, ns = viscontigs[v] - spos; s < ns; s++)
+ {
+ sb.append(gc);
+ }
+ for (int s = 0, ns = al.getHeight(); s < ns; s++)
+ {
+ SequenceI sqobj = al.getSequenceAt(s);
+ if (sqobj != profileseq)
+ {
+ String sq = al.getSequenceAt(s).getSequenceAsString();
+ if (sq.length() <= spos + offset)
+ {
+ // pad sequence
+ int diff = spos + offset - sq.length() - 1;
+ if (diff > 0)
+ {
+ // pad gaps
+ sq = sq + sb;
+ while ((diff = spos + offset - sq.length() - 1) > 0)
+ {
+ // sq = sq
+ // + ((diff >= sb.length()) ? sb.toString() : sb
+ // .substring(0, diff));
+ if (diff >= sb.length())
+ {
+ sq += sb.toString();
+ }
+ else
+ {
+ char[] buf = new char[diff];
+ sb.getChars(0, diff, buf, 0);
+ sq += buf.toString();
+ }
+ }
+ }
+ sq += sb.toString();
+ }
+ else
+ {
+ al.getSequenceAt(s).setSequence(
+ sq.substring(0, spos + offset) + sb.toString()
+ + sq.substring(spos + offset));
+ }
+ }
+ }
+ // offset+=sb.length();
+ }
+ spos = viscontigs[v + 1] + 1;
+ }
+ if ((offset + spos) < profileseq.getLength())
+ {
+ // pad the final region with gaps.
+ StringBuffer sb = new StringBuffer();
+ for (int s = 0, ns = profileseq.getLength() - spos - offset; s < ns; s++)
+ {
+ sb.append(gc);
+ }
+ for (int s = 0, ns = al.getHeight(); s < ns; s++)
+ {
+ SequenceI sqobj = al.getSequenceAt(s);
+ if (sqobj == profileseq)
+ {
+ continue;
+ }
+ String sq = sqobj.getSequenceAsString();
+ // pad sequence
+ int diff = origseq.getLength() - sq.length();
+ while (diff > 0)
+ {
+ // sq = sq
+ // + ((diff >= sb.length()) ? sb.toString() : sb
+ // .substring(0, diff));
+ if (diff >= sb.length())
+ {
+ sq += sb.toString();
+ }
+ else
+ {
+ char[] buf = new char[diff];
+ sb.getChars(0, diff, buf, 0);
+ sq += buf.toString();
+ }
+ diff = origseq.getLength() - sq.length();
+ }
+ }
+ }
+ }
+
+ /**
+ * remove any hiddenColumns or selected columns and shift remaining based on a
+ * series of position, range deletions.
+ *
+ * @param deletions
+ */
+ private void pruneDeletions(ShiftList deletions)
+ {
+ if (deletions != null)
+ {
+ final List<int[]> shifts = deletions.getShifts();
+ if (shifts != null && shifts.size() > 0)
+ {
+ pruneDeletions(shifts);
+
+ // and shift the rest.
+ this.compensateForEdits(deletions);
+ }
+ }
+ }
+
+ /**
+ * Adjust hidden column boundaries based on a series of column additions or
+ * deletions in visible regions.
+ *
+ * @param shiftrecord
+ * @return
+ */
+ private ShiftList compensateForEdits(ShiftList shiftrecord)
+ {
+ if (shiftrecord != null)
+ {
+ final List<int[]> shifts = shiftrecord.getShifts();
+ if (shifts != null && shifts.size() > 0)
+ {
+ int shifted = 0;
+ for (int i = 0, j = shifts.size(); i < j; i++)
+ {
+ int[] sh = shifts.get(i);
+ compensateForDelEdits(shifted + sh[0], sh[1]);
+ shifted -= sh[1];
+ }
+ }
+ return shiftrecord.getInverse();
+ }
+ return null;
+ }
+
+ /**
+ * Returns a hashCode built from hidden column ranges
+ */
+ @Override
+ public int hashCode()
+ {
+ int hashCode = 1;
+ if (hiddenColumns != null)
+ {
+ for (int[] hidden : hiddenColumns)
+ {
+ hashCode = 31 * hashCode + hidden[0];
+ hashCode = 31 * hashCode + hidden[1];
+ }
+ }
+ return hashCode;
+ }
+
+ /**
+ * Hide columns corresponding to the marked bits
+ *
+ * @param inserts
+ * - columns map to bits starting from zero
+ */
+ public void hideMarkedBits(BitSet inserts)
+ {
+ for (int firstSet = inserts.nextSetBit(0), lastSet = 0; firstSet >= 0; firstSet = inserts
+ .nextSetBit(lastSet))
+ {
+ lastSet = inserts.nextClearBit(firstSet);
+ hideColumns(firstSet, lastSet - 1);
+ }
+ }
+
+ /**
+ *
+ * @param inserts
+ * BitSet where hidden columns will be marked
+ */
+ public void markHiddenRegions(BitSet inserts)
+ {
+ if (hiddenColumns == null)
+ {
+ return;
+ }
+ for (int[] range : hiddenColumns)
+ {
+ inserts.set(range[0], range[1] + 1);
+ }
+ }
+
+}
hiddenSequences = new SequenceI[alignment.getHeight()];
}
- int alignmentIndex = alignment.findIndex(sequence);
- alignmentIndex = adjustForHiddenSeqs(alignmentIndex);
+ int absAlignmentIndex = alignment.findIndex(sequence);
+ int alignmentIndex = adjustForHiddenSeqs(absAlignmentIndex);
if (hiddenSequences[alignmentIndex] != null)
{
hiddenSequences[alignmentIndex] = sequence;
- alignment.deleteSequence(sequence);
+ alignment.deleteHiddenSequence(absAlignmentIndex);
}
public List<SequenceI> showAll(
Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
{
- List<SequenceI> revealedSeqs = new ArrayList<SequenceI>();
+ List<SequenceI> revealedSeqs = new ArrayList<>();
+
+ if (hiddenSequences == null)
+ {
+ return revealedSeqs;
+ }
+
for (int i = 0; i < hiddenSequences.length; i++)
{
if (hiddenSequences[i] != null)
public List<SequenceI> showSequence(int alignmentIndex,
Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
{
- List<SequenceI> revealedSeqs = new ArrayList<SequenceI>();
+ List<SequenceI> revealedSeqs = new ArrayList<>();
SequenceI repSequence = alignment.getSequenceAt(alignmentIndex);
if (repSequence != null && hiddenRepSequences != null
&& hiddenRepSequences.containsKey(repSequence))
return hiddenSequences == null ? null : hiddenSequences[alignmentIndex];
}
+ /**
+ * Convert absolute alignment index to visible alignment index
+ *
+ * @param alignmentIndex
+ * @return
+ */
public int findIndexWithoutHiddenSeqs(int alignmentIndex)
{
if (hiddenSequences == null)
}
int index = 0;
int hiddenSeqs = 0;
+ int diff = 0;
if (hiddenSequences.length <= alignmentIndex)
{
+ // if the alignmentIndex runs past the end of hidden sequences
+ // and therefore actually past the end of the alignment
+ // store the difference to add back on at the end, so that behaviour
+ // is consistent with hidden columns behaviour (used by overview panel)
+ diff = alignmentIndex - hiddenSequences.length + 1;
alignmentIndex = hiddenSequences.length - 1;
}
index++;
}
- return (alignmentIndex - hiddenSeqs);
+ return (alignmentIndex - hiddenSeqs + diff);
}
+ /**
+ * Find the visible row which is a given visible number of rows above another
+ * visible row. i.e. for a startRow x, the row which is distance 1 away will
+ * be row x-1.
+ *
+ * @param visibleDistance
+ * the number of visible rows to offset by
+ * @param startRow
+ * the row to start from
+ * @return the position of the row in the visible alignment
+ */
+ public int subtractVisibleRows(int visibleDistance, int startRow)
+ {
+ // walk upwards through the alignment
+ // count all the non-null sequences until we have visibleDistance counted
+ // then return the next visible sequence
+ if (hiddenSequences == null)
+ {
+ return startRow - visibleDistance;
+ }
+
+ int index = startRow;
+ int count = 0;
+ while ((index > -1) && (count < visibleDistance))
+ {
+ if (hiddenSequences[index] == null)
+ {
+ // count visible sequences
+ count++;
+ }
+ index--;
+ }
+ return index;
+ }
+
+ /**
+ * Convert alignment index from visible alignment to absolute alignment
+ *
+ * @param alignmentIndex
+ * @return
+ */
public int adjustForHiddenSeqs(int alignmentIndex)
{
if (hiddenSequences == null)
return false;
}
+
+ /**
+ * Answers if a sequence is hidden
+ *
+ * @param seq
+ * (absolute) index to test
+ * @return true if sequence at index seq is hidden
+ */
+ public boolean isHidden(int seq)
+ {
+ if (hiddenSequences != null)
+ {
+ return (hiddenSequences[seq] != null);
+ }
+ return false;
+ }
}
--- /dev/null
+package jalview.datamodel;
+
+
+/**
+ * A profile for one column of an alignment
+ *
+ * @author gmcarstairs
+ *
+ */
+public class Profile implements ProfileI
+{
+ /*
+ * an object holding counts of symbols in the profile
+ */
+ private ResidueCount counts;
+
+ /*
+ * the number of sequences (gapped or not) in the profile
+ */
+ private int height;
+
+ /*
+ * the number of non-gapped sequences in the profile
+ */
+ private int gapped;
+
+ /*
+ * the highest count for any residue in the profile
+ */
+ private int maxCount;
+
+ /*
+ * the residue (e.g. K) or residues (e.g. KQW) with the
+ * highest count in the profile
+ */
+ private String modalResidue;
+
+ /**
+ * Constructor which allows derived data to be stored without having to store
+ * the full profile
+ *
+ * @param seqCount
+ * the number of sequences in the profile
+ * @param gaps
+ * the number of gapped sequences
+ * @param max
+ * the highest count for any residue
+ * @param modalres
+ * the residue (or concatenated residues) with the highest count
+ */
+ public Profile(int seqCount, int gaps, int max, String modalRes)
+ {
+ this.height = seqCount;
+ this.gapped = gaps;
+ this.maxCount = max;
+ this.modalResidue = modalRes;
+ }
+
+ /* (non-Javadoc)
+ * @see jalview.datamodel.ProfileI#setCounts(jalview.datamodel.ResidueCount)
+ */
+ @Override
+ public void setCounts(ResidueCount residueCounts)
+ {
+ this.counts = residueCounts;
+ }
+
+ /* (non-Javadoc)
+ * @see jalview.datamodel.ProfileI#getPercentageIdentity(boolean)
+ */
+ @Override
+ public float getPercentageIdentity(boolean ignoreGaps)
+ {
+ if (height == 0)
+ {
+ return 0f;
+ }
+ float pid = 0f;
+ if (ignoreGaps && gapped < height)
+ {
+ pid = (maxCount * 100f) / (height - gapped);
+ }
+ else
+ {
+ pid = (maxCount * 100f) / height;
+ }
+ return pid;
+ }
+
+ /* (non-Javadoc)
+ * @see jalview.datamodel.ProfileI#getCounts()
+ */
+ @Override
+ public ResidueCount getCounts()
+ {
+ return counts;
+ }
+
+ /* (non-Javadoc)
+ * @see jalview.datamodel.ProfileI#getHeight()
+ */
+ @Override
+ public int getHeight()
+ {
+ return height;
+ }
+
+ /* (non-Javadoc)
+ * @see jalview.datamodel.ProfileI#getGapped()
+ */
+ @Override
+ public int getGapped()
+ {
+ return gapped;
+ }
+
+ /* (non-Javadoc)
+ * @see jalview.datamodel.ProfileI#getMaxCount()
+ */
+ @Override
+ public int getMaxCount()
+ {
+ return maxCount;
+ }
+
+ /* (non-Javadoc)
+ * @see jalview.datamodel.ProfileI#getModalResidue()
+ */
+ @Override
+ public String getModalResidue()
+ {
+ return modalResidue;
+ }
+
+ /* (non-Javadoc)
+ * @see jalview.datamodel.ProfileI#getNonGapped()
+ */
+ @Override
+ public int getNonGapped()
+ {
+ return height - gapped;
+ }
+}
--- /dev/null
+package jalview.datamodel;
+
+public interface ProfileI
+{
+
+ /**
+ * Set the full profile of counts
+ *
+ * @param residueCounts
+ */
+ public abstract void setCounts(ResidueCount residueCounts);
+
+ /**
+ * Returns the percentage identity of the profile, i.e. the highest proportion
+ * of conserved (equal) symbols. The percentage is as a fraction of all
+ * sequences, or only ungapped sequences if flag ignoreGaps is set true.
+ *
+ * @param ignoreGaps
+ * @return
+ */
+ public abstract float getPercentageIdentity(boolean ignoreGaps);
+
+ /**
+ * Returns the full symbol counts for this profile
+ *
+ * @return
+ */
+ public abstract ResidueCount getCounts();
+
+ /**
+ * Returns the number of sequences in the profile
+ *
+ * @return
+ */
+ public abstract int getHeight();
+
+ /**
+ * Returns the number of sequences in the profile which had a gap character
+ * (or were too short to be included in this column's profile)
+ *
+ * @return
+ */
+ public abstract int getGapped();
+
+ /**
+ * Returns the highest count for any symbol(s) in the profile
+ *
+ * @return
+ */
+ public abstract int getMaxCount();
+
+ /**
+ * Returns the symbol (or concatenated symbols) which have the highest count
+ * in the profile, or an empty string if there were no symbols counted
+ *
+ * @return
+ */
+ public abstract String getModalResidue();
+
+ /**
+ * Answers the number of non-gapped sequences in the profile
+ *
+ * @return
+ */
+ public abstract int getNonGapped();
+
+}
\ No newline at end of file
--- /dev/null
+package jalview.datamodel;
+
+public class Profiles implements ProfilesI
+{
+
+ private ProfileI[] profiles;
+
+ public Profiles(ProfileI[] p)
+ {
+ profiles = p;
+ }
+
+ /**
+ * Returns the profile for the given column, or null if none found
+ *
+ * @param col
+ */
+ @Override
+ public ProfileI get(int col)
+ {
+ return profiles != null && col >= 0 && col < profiles.length ? profiles[col]
+ : null;
+ }
+
+ /**
+ * Returns the first column (base 0) covered by the profiles
+ */
+ @Override
+ public int getStartColumn()
+ {
+ return 0;
+ }
+
+ /**
+ * Returns the last column (base 0) covered by the profiles
+ */
+ @Override
+ public int getEndColumn()
+ {
+ return profiles == null ? 0 : profiles.length - 1;
+ }
+
+}
--- /dev/null
+package jalview.datamodel;
+
+public interface ProfilesI
+{
+
+ ProfileI get(int i);
+
+ int getStartColumn();
+
+ int getEndColumn();
+
+}
--- /dev/null
+package jalview.datamodel;
+
+import jalview.util.Comparison;
+import jalview.util.Format;
+import jalview.util.QuickSort;
+import jalview.util.SparseCount;
+
+/**
+ * A class to count occurrences of residues in a profile, optimised for speed
+ * and memory footprint.
+ * @author gmcarstairs
+ *
+ */
+public class ResidueCount
+{
+ /**
+ * A data bean to hold the results of counting symbols
+ */
+ public class SymbolCounts
+ {
+ /**
+ * the symbols seen (as char values), in no particular order
+ */
+ public final char[] symbols;
+
+ /**
+ * the counts for each symbol, in the same order as the symbols
+ */
+ public final int[] values;
+
+ SymbolCounts(char[] s, int[] v)
+ {
+ symbols = s;
+ values = v;
+ }
+ }
+
+ private static final int TOUPPERCASE = 'A' - 'a';
+
+ /*
+ * nucleotide symbols to count (including N unknown)
+ */
+ private static final String NUCS = "ACGNTU";
+
+ /*
+ * amino acid symbols to count (including X unknown)
+ * NB we also include U so as to support counting of RNA bases
+ * in the "don't know" case of nucleotide / peptide
+ */
+ private static final String AAS = "ACDEFGHIKLMNPQRSTUVWXY";
+
+ private static final int GAP_COUNT = 0;
+
+ /*
+ * fast lookup tables holding the index into our count
+ * arrays of each symbol; index 0 is reserved for gap counting
+ */
+ private static int[] NUC_INDEX = new int[26];
+
+ private static int[] AA_INDEX = new int[26];
+ static
+ {
+ for (int i = 0; i < NUCS.length(); i++)
+ {
+ NUC_INDEX[NUCS.charAt(i) - 'A'] = i + 1;
+ }
+ for (int i = 0; i < AAS.length(); i++)
+ {
+ AA_INDEX[AAS.charAt(i) - 'A'] = i + 1;
+ }
+ }
+
+ /*
+ * counts array, just big enough for the nucleotide or peptide
+ * character set (plus gap counts in position 0)
+ */
+ private short[] counts;
+
+ /*
+ * alternative array of int counts for use if any count
+ * exceeds the maximum value of short (32767)
+ */
+ private int[] intCounts;
+
+ /*
+ * flag set if we switch from short to int counts
+ */
+ private boolean useIntCounts;
+
+ /*
+ * general-purpose counter, only for use for characters
+ * that are not in the expected alphabet
+ */
+ private SparseCount otherData;
+
+ /*
+ * keeps track of the maximum count value recorded
+ * (if this class ever allows decrements, would need to
+ * calculate this on request instead)
+ */
+ int maxCount;
+
+ /*
+ * if we think we are counting nucleotide, can get by with smaller
+ * array to hold counts
+ */
+ private boolean isNucleotide;
+
+ /**
+ * Default constructor allocates arrays able to count either nucleotide or
+ * peptide bases. Use this constructor if not sure which the data is.
+ */
+ public ResidueCount()
+ {
+ this(false);
+ }
+
+ /**
+ * Constructor that allocates an array just big enough for the anticipated
+ * characters, plus one position to count gaps
+ */
+ public ResidueCount(boolean nucleotide)
+ {
+ isNucleotide = nucleotide;
+ int charsToCount = nucleotide ? NUCS.length() : AAS.length();
+ counts = new short[charsToCount + 1];
+ }
+
+ /**
+ * Increments the count for the given character. The supplied character may be
+ * upper or lower case but counts are for the upper case only. Gap characters
+ * (space, ., -) are all counted together.
+ *
+ * @param c
+ * @return the new value of the count for the character
+ */
+ public int add(final char c)
+ {
+ char u = toUpperCase(c);
+ int newValue = 0;
+ int offset = getOffset(u);
+
+ /*
+ * offset 0 is reserved for gap counting, so 0 here means either
+ * an unexpected character, or a gap character passed in error
+ */
+ if (offset == 0)
+ {
+ if (Comparison.isGap(u))
+ {
+ newValue = addGap();
+ }
+ else
+ {
+ newValue = addOtherCharacter(u);
+ }
+ }
+ else
+ {
+ newValue = increment(offset);
+ }
+ return newValue;
+ }
+
+ /**
+ * Increment the count at the specified offset. If this would result in short
+ * overflow, promote to counting int values instead.
+ *
+ * @param offset
+ * @return the new value of the count at this offset
+ */
+ int increment(int offset)
+ {
+ int newValue = 0;
+ if (useIntCounts)
+ {
+ newValue = intCounts[offset];
+ intCounts[offset] = ++newValue;
+ }
+ else
+ {
+ if (counts[offset] == Short.MAX_VALUE)
+ {
+ handleOverflow();
+ newValue = intCounts[offset];
+ intCounts[offset] = ++newValue;
+ }
+ else
+ {
+ newValue = counts[offset];
+ counts[offset] = (short) ++newValue;
+ }
+ }
+ maxCount = Math.max(maxCount, newValue);
+ return newValue;
+ }
+
+ /**
+ * Switch from counting in short to counting in int
+ */
+ synchronized void handleOverflow()
+ {
+ intCounts = new int[counts.length];
+ for (int i = 0; i < counts.length; i++)
+ {
+ intCounts[i] = counts[i];
+ }
+ counts = null;
+ useIntCounts = true;
+ }
+
+ /**
+ * Returns this character's offset in the count array
+ *
+ * @param c
+ * @return
+ */
+ int getOffset(char c)
+ {
+ int offset = 0;
+ if ('A' <= c && c <= 'Z')
+ {
+ offset = isNucleotide ? NUC_INDEX[c - 'A'] : AA_INDEX[c - 'A'];
+ }
+ return offset;
+ }
+
+ /**
+ * @param c
+ * @return
+ */
+ protected char toUpperCase(final char c)
+ {
+ char u = c;
+ if ('a' <= c && c <= 'z')
+ {
+ u = (char) (c + TOUPPERCASE);
+ }
+ return u;
+ }
+
+ /**
+ * Increment count for some unanticipated character. The first time this
+ * called, a SparseCount is instantiated to hold these 'extra' counts.
+ *
+ * @param c
+ * @return the new value of the count for the character
+ */
+ int addOtherCharacter(char c)
+ {
+ if (otherData == null)
+ {
+ otherData = new SparseCount();
+ }
+ int newValue = otherData.add(c, 1);
+ maxCount = Math.max(maxCount, newValue);
+ return newValue;
+ }
+
+ /**
+ * Set count for some unanticipated character. The first time this called, a
+ * SparseCount is instantiated to hold these 'extra' counts.
+ *
+ * @param c
+ * @param value
+ */
+ void setOtherCharacter(char c, int value)
+ {
+ if (otherData == null)
+ {
+ otherData = new SparseCount();
+ }
+ otherData.put(c, value);
+ }
+
+ /**
+ * Increment count of gap characters
+ *
+ * @return the new count of gaps
+ */
+ public int addGap()
+ {
+ int newValue;
+ if (useIntCounts)
+ {
+ newValue = ++intCounts[GAP_COUNT];
+ }
+ else
+ {
+ newValue = ++counts[GAP_COUNT];
+ }
+ return newValue;
+ }
+
+ /**
+ * Answers true if we are counting ints (only after overflow of short counts)
+ *
+ * @return
+ */
+ boolean isCountingInts()
+ {
+ return useIntCounts;
+ }
+
+ /**
+ * Sets the count for the given character. The supplied character may be upper
+ * or lower case but counts are for the upper case only.
+ *
+ * @param c
+ * @param count
+ */
+ public void put(char c, int count)
+ {
+ char u = toUpperCase(c);
+ int offset = getOffset(u);
+
+ /*
+ * offset 0 is reserved for gap counting, so 0 here means either
+ * an unexpected character, or a gap character passed in error
+ */
+ if (offset == 0)
+ {
+ if (Comparison.isGap(u))
+ {
+ set(0, count);
+ }
+ else
+ {
+ setOtherCharacter(u, count);
+ maxCount = Math.max(maxCount, count);
+ }
+ }
+ else
+ {
+ set(offset, count);
+ maxCount = Math.max(maxCount, count);
+ }
+ }
+
+ /**
+ * Sets the count at the specified offset. If this would result in short
+ * overflow, promote to counting int values instead.
+ *
+ * @param offset
+ * @param value
+ */
+ void set(int offset, int value)
+ {
+ if (useIntCounts)
+ {
+ intCounts[offset] = value;
+ }
+ else
+ {
+ if (value > Short.MAX_VALUE || value < Short.MIN_VALUE)
+ {
+ handleOverflow();
+ intCounts[offset] = value;
+ }
+ else
+ {
+ counts[offset] = (short) value;
+ }
+ }
+ }
+
+ /**
+ * Returns the count for the given character, or zero if no count held
+ *
+ * @param c
+ * @return
+ */
+ public int getCount(char c)
+ {
+ char u = toUpperCase(c);
+ int offset = getOffset(u);
+ if (offset == 0)
+ {
+ if (!Comparison.isGap(u))
+ {
+ // should have called getGapCount()
+ return otherData == null ? 0 : otherData.get(u);
+ }
+ }
+ return useIntCounts ? intCounts[offset] : counts[offset];
+ }
+
+ public int getGapCount()
+ {
+ return useIntCounts ? intCounts[0] : counts[0];
+ }
+
+ /**
+ * Answers true if this object wraps a counter for unexpected characters
+ *
+ * @return
+ */
+ boolean isUsingOtherData()
+ {
+ return otherData != null;
+ }
+
+ /**
+ * Returns the character (or concatenated characters) for the symbol(s) with
+ * the given count in the profile. Can be used to get the modal residue by
+ * supplying the modal count value. Returns an empty string if no symbol has
+ * the given count. The symbols are in alphabetic order of standard peptide or
+ * nucleotide characters, followed by 'other' symbols if any.
+ *
+ * @return
+ */
+ public String getResiduesForCount(int count)
+ {
+ if (count == 0)
+ {
+ return "";
+ }
+
+ /*
+ * find counts for the given value and append the
+ * corresponding symbol
+ */
+ StringBuilder modal = new StringBuilder();
+ if (useIntCounts)
+ {
+ for (int i = 1; i < intCounts.length; i++)
+ {
+ if (intCounts[i] == count)
+ {
+ modal.append(isNucleotide ? NUCS.charAt(i - 1) : AAS
+ .charAt(i - 1));
+ }
+ }
+ }
+ else
+ {
+ for (int i = 1; i < counts.length; i++)
+ {
+ if (counts[i] == count)
+ {
+ modal.append(isNucleotide ? NUCS.charAt(i - 1) : AAS
+ .charAt(i - 1));
+ }
+ }
+ }
+ if (otherData != null)
+ {
+ for (int i = 0; i < otherData.size(); i++)
+ {
+ if (otherData.valueAt(i) == count)
+ {
+ modal.append((char) otherData.keyAt(i));
+ }
+ }
+ }
+ return modal.toString();
+ }
+
+ /**
+ * Returns the highest count for any symbol(s) in the profile (excluding gap)
+ *
+ * @return
+ */
+ public int getModalCount()
+ {
+ return maxCount;
+ }
+
+ /**
+ * Returns the number of distinct symbols with a non-zero count (excluding the
+ * gap symbol)
+ *
+ * @return
+ */
+ public int size() {
+ int size = 0;
+ if (useIntCounts)
+ {
+ for (int i = 1; i < intCounts.length; i++)
+ {
+ if (intCounts[i] > 0)
+ {
+ size++;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 1; i < counts.length; i++)
+ {
+ if (counts[i] > 0)
+ {
+ size++;
+ }
+ }
+ }
+
+ /*
+ * include 'other' characters recorded (even if count is zero
+ * though that would be a strange use case)
+ */
+ if (otherData != null)
+ {
+ size += otherData.size();
+ }
+
+ return size;
+ }
+
+ /**
+ * Returns a data bean holding those symbols that have a non-zero count
+ * (excluding the gap symbol), with their counts.
+ *
+ * @return
+ */
+ public SymbolCounts getSymbolCounts()
+ {
+ int size = size();
+ char[] symbols = new char[size];
+ int[] values = new int[size];
+ int j = 0;
+
+ if (useIntCounts)
+ {
+ for (int i = 1; i < intCounts.length; i++)
+ {
+ if (intCounts[i] > 0)
+ {
+ char symbol = isNucleotide ? NUCS.charAt(i - 1) : AAS
+ .charAt(i - 1);
+ symbols[j] = symbol;
+ values[j] = intCounts[i];
+ j++;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 1; i < counts.length; i++)
+ {
+ if (counts[i] > 0)
+ {
+ char symbol = isNucleotide ? NUCS.charAt(i - 1) : AAS
+ .charAt(i - 1);
+ symbols[j] = symbol;
+ values[j] = counts[i];
+ j++;
+ }
+ }
+ }
+ if (otherData != null)
+ {
+ for (int i = 0; i < otherData.size(); i++)
+ {
+ symbols[j] = (char) otherData.keyAt(i);
+ values[j] = otherData.valueAt(i);
+ j++;
+ }
+ }
+
+ return new SymbolCounts(symbols, values);
+ }
+
+ /**
+ * Returns a tooltip string showing residues in descending order of their
+ * percentage frequency in the profile
+ *
+ * @param normaliseBy
+ * the divisor for residue counts (may or may not include gapped
+ * sequence count)
+ * @param percentageDecPl
+ * the number of decimal places to show in percentages
+ * @return
+ */
+ public String getTooltip(int normaliseBy, int percentageDecPl)
+ {
+ SymbolCounts symbolCounts = getSymbolCounts();
+ char[] ca = symbolCounts.symbols;
+ int[] vl = symbolCounts.values;
+
+ /*
+ * sort characters into ascending order of their counts
+ */
+ QuickSort.sort(vl, ca);
+
+ /*
+ * traverse in reverse order (highest count first) to build tooltip
+ */
+ boolean first = true;
+ StringBuilder sb = new StringBuilder(64);
+ for (int c = ca.length - 1; c >= 0; c--)
+ {
+ final char residue = ca[c];
+ // TODO combine residues which share a percentage
+ // (see AAFrequency.completeCdnaConsensus)
+ float tval = (vl[c] * 100f) / normaliseBy;
+ sb.append(first ? "" : "; ").append(residue).append(" ");
+ Format.appendPercentage(sb, tval, percentageDecPl);
+ sb.append("%");
+ first = false;
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns a string representation of the symbol counts, for debug purposes.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[ ");
+ SymbolCounts sc = getSymbolCounts();
+ for (int i = 0; i < sc.symbols.length; i++)
+ {
+ sb.append(sc.symbols[i]).append(":").append(sc.values[i]).append(" ");
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+}
--- /dev/null
+package jalview.datamodel;
+
+/**
+ * An interface that describes one matched region of an alignment, as one
+ * contiguous portion of a single dataset sequence
+ */
+public interface SearchResultMatchI
+{
+ /**
+ * Returns the matched sequence
+ *
+ * @return
+ */
+ SequenceI getSequence();
+
+ /**
+ * Returns the start position of the match in the sequence (base 1)
+ *
+ * @return
+ */
+ int getStart();
+
+ /**
+ * Returns the end position of the match in the sequence (base 1)
+ *
+ * @return
+ */
+ int getEnd();
+
+}
\ No newline at end of file
--- /dev/null
+package jalview.datamodel;
+
+import java.util.BitSet;
+import java.util.List;
+
+/**
+ * An interface describing the result of a search or other operation which
+ * highlights matched regions of an alignment
+ */
+public interface SearchResultsI
+{
+
+ /**
+ * Adds one region to the results
+ *
+ * @param seq
+ * Sequence
+ * @param start
+ * int
+ * @param end
+ * int
+ * @return
+ */
+ SearchResultMatchI addResult(SequenceI seq, int start, int end);
+
+ /**
+ * Answers true if the search results include the given sequence (or its
+ * dataset sequence), else false
+ *
+ * @param sequence
+ * @return
+ */
+ boolean involvesSequence(SequenceI sequence);
+
+ /**
+ * Returns an array of [from, to, from, to..] matched columns (base 0) between
+ * the given start and end columns of the given sequence. Returns null if no
+ * matches overlap the specified region.
+ * <p>
+ * Implementations should provide an optimised method to return locations to
+ * highlight on a visible portion of an alignment.
+ *
+ * @param sequence
+ * @param start
+ * first column of range (base 0, inclusive)
+ * @param end
+ * last column of range base 0, inclusive)
+ * @return int[]
+ */
+ int[] getResults(SequenceI sequence, int start, int end);
+
+ /**
+ * Returns the number of matches found
+ *
+ * @return
+ */
+ int getSize();
+
+ /**
+ * Returns true if no search result matches are held.
+ *
+ * @return
+ */
+ boolean isEmpty();
+
+ /**
+ * Returns the list of matches.
+ *
+ * @return
+ */
+ List<SearchResultMatchI> getResults();
+
+ /**
+ * Set bits in a bitfield for all columns in the given sequence collection
+ * that are highlighted
+ *
+ * @param sqcol
+ * the set of sequences to search for highlighted regions
+ * @param bs
+ * bitset to set
+ * @return number of bits set
+ */
+ int markColumns(SequenceCollectionI sqcol, BitSet bs);
+}
\ No newline at end of file
/**
* create an alignment from the given array of cigar sequences and gap
* character, and marking the given segments as visible in the given
- * columselection.
+ * hiddenColumns.
*
* @param alseqs
* @param gapCharacter
- * @param colsel
- * - columnSelection where hidden regions are marked
+ * @param hidden
+ * - hiddenColumns where hidden regions are marked
* @param segments
* - visible regions of alignment
* @return SequenceI[]
*/
public static SequenceI[] createAlignmentSequences(SeqCigar[] alseqs,
- char gapCharacter, ColumnSelection colsel, int[] segments)
+ char gapCharacter, HiddenColumns hidden, int[] segments)
{
SequenceI[] seqs = new SequenceI[alseqs.length];
StringBuffer[] g_seqs = new StringBuffer[alseqs.length];
if (segments == null)
{
// add a hidden column for this deletion
- colsel.hideColumns(inspos, inspos + insert.length - 1);
+ hidden.hideColumns(inspos, inspos + insert.length - 1);
}
}
}
{
// int start=shifts.shift(segments[i]-1)+1;
// int end=shifts.shift(segments[i]+segments[i+1]-1)-1;
- colsel.hideColumns(segments[i + 1], segments[i + 1]
+ hidden.hideColumns(segments[i + 1], segments[i + 1]
+ segments[i + 2] - 1);
}
}
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
}
@Override
- public synchronized void addSequenceFeature(SequenceFeature sf)
+ public synchronized boolean addSequenceFeature(SequenceFeature sf)
{
if (sequenceFeatures == null && datasetSequence != null)
{
- datasetSequence.addSequenceFeature(sf);
- return;
+ return datasetSequence.addSequenceFeature(sf);
}
if (sequenceFeatures == null)
{
{
if (sequenceFeatures[i].equals(sf))
{
- return;
+ return false;
}
}
temp[sequenceFeatures.length] = sf;
sequenceFeatures = temp;
+ return true;
}
@Override
}
@Override
+ public BitSet getInsertionsAsBits()
+ {
+ BitSet map = new BitSet();
+ int lastj = -1, j = 0;
+ int pos = start;
+ int seqlen = sequence.length;
+ while ((j < seqlen))
+ {
+ if (jalview.util.Comparison.isGap(sequence[j]))
+ {
+ if (lastj == -1)
+ {
+ lastj = j;
+ }
+ }
+ else
+ {
+ if (lastj != -1)
+ {
+ map.set(lastj, j);
+ lastj = -1;
+ }
+ }
+ j++;
+ }
+ if (lastj != -1)
+ {
+ map.set(lastj, j);
+ lastj = -1;
+ }
+ return map;
+ }
+
+ @Override
public void deleteChars(int i, int j)
{
int newstart = start, newend = end;
boolean colourText = false;
/**
+ * True if the group is defined as a group on the alignment, false if it is
+ * just a selection.
+ */
+ boolean isDefined = false;
+
+ /**
* after Olivier's non-conserved only character display
*/
boolean showNonconserved = false;
/**
* group members
*/
- private List<SequenceI> sequences = new ArrayList<SequenceI>();
+ private List<SequenceI> sequences = new ArrayList<>();
/**
* representative sequence for this group (if any)
*/
private boolean normaliseSequenceLogo;
- /**
- * @return the includeAllConsSymbols
+ /*
+ * visibility of rows or represented rows covered by group
*/
- public boolean isShowSequenceLogo()
- {
- return showSequenceLogo;
- }
+ private boolean hidereps = false;
+
+ /*
+ * visibility of columns intersecting this group
+ */
+ private boolean hidecols = false;
+
+ AlignmentAnnotation consensus = null;
+
+ AlignmentAnnotation conservation = null;
+
+ private boolean showConsensusHistogram;
+
+ private AnnotatedCollectionI context;
/**
* Creates a new SequenceGroup object.
this();
if (seqsel != null)
{
- sequences = new ArrayList<SequenceI>();
+ sequences = new ArrayList<>();
sequences.addAll(seqsel.sequences);
if (seqsel.groupName != null)
{
colourText = seqsel.colourText;
startRes = seqsel.startRes;
endRes = seqsel.endRes;
- cs = seqsel.cs;
+ cs = new ResidueShader(seqsel.getColourScheme());
if (seqsel.description != null)
{
description = new String(seqsel.description);
}
hidecols = seqsel.hidecols;
hidereps = seqsel.hidereps;
+ showNonconserved = seqsel.showNonconserved;
+ showSequenceLogo = seqsel.showSequenceLogo;
+ normaliseSequenceLogo = seqsel.normaliseSequenceLogo;
+ showConsensusHistogram = seqsel.showConsensusHistogram;
idColour = seqsel.idColour;
outlineColour = seqsel.outlineColour;
seqrep = seqsel.seqrep;
}
}
+ public boolean isShowSequenceLogo()
+ {
+ return showSequenceLogo;
+ }
+
public SequenceI[] getSelectionAsNewSequences(AlignmentI align)
{
int iSize = sequences.size();
}
else
{
- List<SequenceI> allSequences = new ArrayList<SequenceI>();
+ List<SequenceI> allSequences = new ArrayList<>();
for (SequenceI seq : sequences)
{
allSequences.add(seq);
}
/**
- * visibility of rows or represented rows covered by group
- */
- private boolean hidereps = false;
-
- /**
* set visibility of sequences covered by (if no sequence representative is
* defined) or represented by this group.
*
}
/**
- * visibility of columns intersecting this group
- */
- private boolean hidecols = false;
-
- /**
* set intended visibility of columns covered by this group
*
* @param visibility
{
SequenceGroup sgroup = new SequenceGroup(this);
SequenceI[] insect = getSequencesInOrder(alignment);
- sgroup.sequences = new ArrayList<SequenceI>();
+ sgroup.sequences = new ArrayList<>();
for (int s = 0; insect != null && s < insect.length; s++)
{
if (map == null || map.containsKey(insect[s]))
this.showNonconserved = displayNonconserved;
}
- AlignmentAnnotation consensus = null, conservation = null;
-
- /**
- * flag indicating if consensus histogram should be rendered
- */
- private boolean showConsensusHistogram;
-
/**
* set this alignmentAnnotation object as the one used to render consensus
* annotation
{
// TODO add in other methods like 'getAlignmentAnnotation(String label),
// etc'
- ArrayList<AlignmentAnnotation> annot = new ArrayList<AlignmentAnnotation>();
+ ArrayList<AlignmentAnnotation> annot = new ArrayList<>();
synchronized (sequences)
{
for (SequenceI seq : sequences)
@Override
public Iterable<AlignmentAnnotation> findAnnotation(String calcId)
{
- List<AlignmentAnnotation> aa = new ArrayList<AlignmentAnnotation>();
+ List<AlignmentAnnotation> aa = new ArrayList<>();
if (calcId == null)
{
return aa;
return aa;
}
- /**
- * Returns a list of annotations that match the specified sequenceRef, calcId
- * and label, ignoring null values.
- *
- * @return list of AlignmentAnnotation objects
- */
@Override
public Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq,
String calcId, String label)
{
- ArrayList<AlignmentAnnotation> aa = new ArrayList<AlignmentAnnotation>();
+ ArrayList<AlignmentAnnotation> aa = new ArrayList<>();
for (AlignmentAnnotation ann : getAlignmentAnnotation())
{
- if (ann.getCalcId() != null && ann.getCalcId().equals(calcId)
- && ann.sequenceRef != null && ann.sequenceRef == seq
- && ann.label != null && ann.label.equals(label))
+ if ((calcId == null || (ann.getCalcId() != null && ann.getCalcId()
+ .equals(calcId)))
+ && (seq == null || (ann.sequenceRef != null && ann.sequenceRef == seq))
+ && (label == null || (ann.label != null && ann.label
+ .equals(label))))
{
aa.add(ann);
}
}
}
- private AnnotatedCollectionI context;
+ /**
+ * Sets the alignment or group context for this group, and whether it is
+ * defined as a group
+ *
+ * @param ctx
+ * the context for the group
+ * @param defined
+ * whether the group is defined on the alignment or is just a
+ * selection
+ * @throws IllegalArgumentException
+ * if setting the context would result in a circular reference chain
+ */
+ public void setContext(AnnotatedCollectionI ctx, boolean defined)
+ {
+ setContext(ctx);
+ this.isDefined = defined;
+ }
/**
* Sets the alignment or group context for this group
*
* @param ctx
+ * the context for the group
* @throws IllegalArgumentException
* if setting the context would result in a circular reference chain
*/
AnnotatedCollectionI ref = ctx;
while (ref != null)
{
- if (ref == this)
+ if (ref == this || ref.getContext() == ctx)
{
throw new IllegalArgumentException(
"Circular reference in SequenceGroup.context");
return context;
}
+ public boolean isDefined()
+ {
+ return isDefined;
+ }
+
public void setColourScheme(ColourSchemeI scheme)
{
if (cs == null)
}
return false;
}
+
+ /**
+ * @param seq
+ * @return true if seq is a member of the group
+ */
+
+ public boolean contains(SequenceI seq1)
+ {
+ return sequences.contains(seq1);
+ }
+
+ /**
+ * @param seq
+ * @param apos
+ * @return true if startRes<=apos and endRes>=apos and seq is in the group
+ */
+ public boolean contains(SequenceI seq, int apos)
+ {
+ return (startRes <= apos && endRes >= apos) && sequences.contains(seq);
+ }
}
*/
package jalview.datamodel;
+import java.util.BitSet;
import java.util.List;
import java.util.Vector;
public int findIndex(int pos);
/**
- * Returns the sequence position for an alignment position
+ * Returns the sequence position for an alignment position.
*
* @param i
* column index in alignment (from 0..<length)
*
- * @return residue number for residue (left of and) nearest ith column
+ * @return TODO: JAL-2562 - residue number for residue (left of and) nearest
+ * ith column
*/
public int findPosition(int i);
*/
public void addDBRef(DBRefEntry entry);
- public void addSequenceFeature(SequenceFeature sf);
+ /**
+ * Adds the given sequence feature and returns true, or returns false if it is
+ * already present on the sequence
+ *
+ * @param sf
+ * @return
+ */
+ public boolean addSequenceFeature(SequenceFeature sf);
public void deleteFeature(SequenceFeature sf);
* list
*/
public List<DBRefEntry> getPrimaryDBRefs();
+
+ /**
+ *
+ * @return BitSet corresponding to index [0,length) where Comparison.isGap()
+ * returns true.
+ */
+ BitSet getInsertionsAsBits();
}
public class SequenceNode extends BinaryNode
{
/** DOCUMENT ME!! */
- public float dist;
+ public double dist;
/** DOCUMENT ME!! */
public int count;
/** DOCUMENT ME!! */
- public float height;
+ public double height;
/** DOCUMENT ME!! */
public float ycount;
{
char q = name.charAt(c);
if ('0' <= q && q <= '9')
+ {
continue;
+ }
return true;
}
}
--- /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.
+ */
+package jalview.datamodel;
+
+import jalview.api.AlignmentColsCollectionI;
+
+import java.util.Iterator;
+
+public class VisibleColsCollection implements AlignmentColsCollectionI
+{
+ int start;
+ int end;
+
+ HiddenColumns hidden;
+
+ public VisibleColsCollection(int s, int e, AlignmentI al)
+ {
+ start = s;
+ end = e;
+ hidden = al.getHiddenColumns();
+ }
+
+ @Override
+ public Iterator<Integer> iterator()
+ {
+ return new VisibleColsIterator(start, end, hidden);
+ }
+
+ @Override
+ public boolean isHidden(int c)
+ {
+ return false;
+ }
+
+}
--- /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.
+ */
+package jalview.datamodel;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * An iterator which iterates over all visible columns in an alignment
+ *
+ * @author kmourao
+ *
+ */
+public class VisibleColsIterator implements Iterator<Integer>
+{
+ private int last;
+
+ private int current;
+
+ private int next;
+
+ private List<int[]> hidden;
+
+ private int lasthiddenregion;
+
+ public VisibleColsIterator(int firstcol, int lastcol,
+ HiddenColumns hiddenCols)
+ {
+ last = lastcol;
+ current = firstcol;
+ next = firstcol;
+ hidden = hiddenCols.getHiddenRegions();
+ lasthiddenregion = -1;
+
+ if (hidden != null)
+ {
+ int i = 0;
+ for (i = 0; i < hidden.size(); ++i)
+ {
+ if (current >= hidden.get(i)[0] && current <= hidden.get(i)[1])
+ {
+ // current is hidden, move to right
+ current = hidden.get(i)[1] + 1;
+ next = current;
+ }
+ if (current < hidden.get(i)[0])
+ {
+ break;
+ }
+ }
+ lasthiddenregion = i - 1;
+
+ for (i = hidden.size() - 1; i >= 0; --i)
+ {
+ if (last >= hidden.get(i)[0] && last <= hidden.get(i)[1])
+ {
+ // last is hidden, move to left
+ last = hidden.get(i)[0] - 1;
+ }
+ if (last > hidden.get(i)[1])
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return next <= last;
+ }
+
+ @Override
+ public Integer next()
+ {
+ if (next > last)
+ {
+ throw new NoSuchElementException();
+ }
+ current = next;
+ if ((hidden != null) && (lasthiddenregion + 1 < hidden.size()))
+ {
+ // still some more hidden regions
+ if (next + 1 < hidden.get(lasthiddenregion + 1)[0])
+ {
+ // next+1 is still before the next hidden region
+ next++;
+ }
+ else if ((next + 1 >= hidden.get(lasthiddenregion + 1)[0])
+ && (next + 1 <= hidden.get(lasthiddenregion + 1)[1]))
+ {
+ // next + 1 is in the next hidden region
+ next = hidden.get(lasthiddenregion + 1)[1] + 1;
+ lasthiddenregion++;
+ }
+ }
+ else
+ {
+ // finished with hidden regions, just increment normally
+ next++;
+ }
+ return current;
+ }
+
+ @Override
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+}
+
--- /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.
+ */
+package jalview.datamodel;
+
+import jalview.api.AlignmentRowsCollectionI;
+
+import java.util.Iterator;
+
+public class VisibleRowsCollection implements AlignmentRowsCollectionI
+{
+ int start;
+
+ int end;
+
+ AlignmentI alignment;
+
+ public VisibleRowsCollection(int s, int e, AlignmentI al)
+ {
+ start = s;
+ end = e;
+ alignment = al;
+ }
+
+ @Override
+ public Iterator<Integer> iterator()
+ {
+ return new VisibleRowsIterator(start, end, alignment);
+ }
+
+ @Override
+ public boolean isHidden(int seq)
+ {
+ return false;
+ }
+
+ @Override
+ public SequenceI getSequence(int seq)
+ {
+ return alignment.getSequenceAtAbsoluteIndex(seq);
+ }
+}
+
--- /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.
+ */
+package jalview.datamodel;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * An iterator which iterates over all visible rows in an alignment
+ *
+ * @author kmourao
+ *
+ */
+public class VisibleRowsIterator implements Iterator<Integer>
+{
+ private int last;
+
+ private int current;
+
+ private int next;
+
+ private HiddenSequences hidden;
+
+ private AlignmentI al;
+
+ /**
+ * Create an iterator for all visible rows in the alignment
+ *
+ * @param firstrow
+ * absolute row index to start from
+ * @param lastrow
+ * absolute row index to end at
+ * @param alignment
+ * alignment to work with
+ */
+ public VisibleRowsIterator(int firstrow, int lastrow, AlignmentI alignment)
+ {
+ al = alignment;
+ current = firstrow;
+ last = lastrow;
+ hidden = al.getHiddenSequences();
+ while (last > current && hidden.isHidden(last))
+ {
+ last--;
+ }
+ current = firstrow;
+ while (current < last && hidden.isHidden(current))
+ {
+ current++;
+ }
+ next = current;
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return next <= last;
+ }
+
+ @Override
+ public Integer next()
+ {
+ if (next > last)
+ {
+ throw new NoSuchElementException();
+ }
+ current = next;
+ do
+ {
+ next++;
+ } while (next <= last && hidden.isHidden(next));
+ return current;
+ }
+
+ @Override
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+}
+
/*
* Copied to Jalview September 2016.
* Only the members of this class required for SparseIntArray were copied.
- * Method binarySearch(short[] array, int size, short value) added to support
+ * Change Log:
+ * Sep 2016: Method binarySearch(short[] array, int size, short value) added to support
* SparseShortArray.
+ * Jan 2017: EMPTY_DOUBLES added
*/
class ContainerHelpers
{
static final int[] EMPTY_INTS = new int[0];
+ static final double[] EMPTY_DOUBLES = new double[0];
+
static final long[] EMPTY_LONGS = new long[0];
static final Object[] EMPTY_OBJECTS = new Object[0];
--- /dev/null
+package jalview.ext.android;
+
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * SparseDoubleArray map integers to doubles. Unlike a normal array of integers,
+ * there can be gaps in the indices. It is intended to be more memory efficient
+ * than using a HashMap to map Integer to Double, both because it avoids
+ * auto-boxing keys and values and its data structure doesn't rely on an extra
+ * entry object for each mapping.
+ *
+ * <p>
+ * Note that this container keeps its mappings in an array data structure, using
+ * a binary search to find keys. The implementation is not intended to be
+ * appropriate for data structures that may contain large numbers of items. It
+ * is generally slower than a traditional HashMap, since lookups require a
+ * binary search and adds and removes require inserting and deleting entries in
+ * the array. For containers holding up to hundreds of items, the performance
+ * difference is not significant, less than 50%.
+ * </p>
+ *
+ * <p>
+ * It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.
+ * </p>
+ */
+
+/*
+ * Change log:
+ * Jan 2017 cloned from SparseIntArray for Jalview to support SparseMatrix
+ * - SparseDoubleArray(double[]) constructor added
+ * - multiply() added for more efficient multiply (or divide) of a value
+ */
+public class SparseDoubleArray implements Cloneable
+{
+ private int[] mKeys;
+
+ private double[] mValues;
+
+ private int mSize;
+
+ /**
+ * Creates a new SparseDoubleArray containing no mappings.
+ */
+ public SparseDoubleArray()
+ {
+ this(10);
+ }
+
+ /**
+ * Creates a new SparseDoubleArray containing no mappings that will not
+ * require any additional memory allocation to store the specified number of
+ * mappings. If you supply an initial capacity of 0, the sparse array will be
+ * initialized with a light-weight representation not requiring any additional
+ * array allocations.
+ */
+ public SparseDoubleArray(int initialCapacity)
+ {
+ if (initialCapacity == 0)
+ {
+ mKeys = ContainerHelpers.EMPTY_INTS;
+ mValues = ContainerHelpers.EMPTY_DOUBLES;
+ }
+ else
+ {
+ initialCapacity = idealDoubleArraySize(initialCapacity);
+ mKeys = new int[initialCapacity];
+ mValues = new double[initialCapacity];
+ }
+ mSize = 0;
+ }
+
+ /**
+ * Constructor given an array of double values; stores the non-zero values
+ *
+ * @param row
+ */
+ public SparseDoubleArray(double[] row)
+ {
+ this();
+ for (int i = 0; i < row.length; i++)
+ {
+ if (row[i] != 0d)
+ {
+ put(i, row[i]);
+ }
+ }
+ }
+
+ @Override
+ public SparseDoubleArray clone()
+ {
+ SparseDoubleArray clone = null;
+ try
+ {
+ clone = (SparseDoubleArray) super.clone();
+ clone.mKeys = mKeys.clone();
+ clone.mValues = mValues.clone();
+ } catch (CloneNotSupportedException cnse)
+ {
+ /* ignore */
+ }
+ return clone;
+ }
+
+ /**
+ * Gets the value mapped from the specified key, or <code>0</code> if no such
+ * mapping has been made.
+ */
+ public double get(int key)
+ {
+ return get(key, 0d);
+ }
+
+ /**
+ * Gets the int mapped from the specified key, or the specified value if no
+ * such mapping has been made.
+ */
+ public double get(int key, double valueIfKeyNotFound)
+ {
+ int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+ if (i < 0)
+ {
+ return valueIfKeyNotFound;
+ }
+ else
+ {
+ return mValues[i];
+ }
+ }
+
+ /**
+ * Removes the mapping from the specified key, if there was any.
+ */
+ public void delete(int key)
+ {
+ int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+ if (i >= 0)
+ {
+ removeAt(i);
+ }
+ }
+
+ /**
+ * Removes the mapping at the given index.
+ */
+ public void removeAt(int index)
+ {
+ System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
+ System.arraycopy(mValues, index + 1, mValues, index, mSize
+ - (index + 1));
+ mSize--;
+ }
+
+ /**
+ * Adds a mapping from the specified key to the specified value, replacing the
+ * previous mapping from the specified key if there was one.
+ */
+ public void put(int key, double value)
+ {
+ int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+ if (i >= 0)
+ {
+ mValues[i] = value;
+ }
+ else
+ {
+ i = ~i;
+ if (mSize >= mKeys.length)
+ {
+ int n = idealDoubleArraySize(mSize + 1);
+ int[] nkeys = new int[n];
+ double[] nvalues = new double[n];
+ // Log.e("SparseDoubleArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+ if (mSize - i != 0)
+ {
+ // Log.e("SparseDoubleArray", "move " + (mSize - i));
+ System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+ System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+ }
+ mKeys[i] = key;
+ mValues[i] = value;
+ mSize++;
+ }
+ }
+
+ /**
+ * Returns the number of key-value mappings that this SparseDoubleArray
+ * currently stores.
+ */
+ public int size()
+ {
+ return mSize;
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns the key from
+ * the <code>index</code>th key-value mapping that this SparseDoubleArray
+ * stores.
+ *
+ * <p>
+ * The keys corresponding to indices in ascending order are guaranteed to be
+ * in ascending order, e.g., <code>keyAt(0)</code> will return the smallest
+ * key and <code>keyAt(size()-1)</code> will return the largest key.
+ * </p>
+ */
+ public int keyAt(int index)
+ {
+ return mKeys[index];
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns the value
+ * from the <code>index</code>th key-value mapping that this SparseDoubleArray
+ * stores.
+ *
+ * <p>
+ * The values corresponding to indices in ascending order are guaranteed to be
+ * associated with keys in ascending order, e.g., <code>valueAt(0)</code> will
+ * return the value associated with the smallest key and
+ * <code>valueAt(size()-1)</code> will return the value associated with the
+ * largest key.
+ * </p>
+ */
+ public double valueAt(int index)
+ {
+ return mValues[index];
+ }
+
+ /**
+ * Returns the index for which {@link #keyAt} would return the specified key,
+ * or a negative number if the specified key is not mapped.
+ */
+ public int indexOfKey(int key)
+ {
+ return ContainerHelpers.binarySearch(mKeys, mSize, key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the specified key,
+ * or a negative number if no keys map to the specified value. Beware that
+ * this is a linear search, unlike lookups by key, and that multiple keys can
+ * map to the same value and this will find only one of them.
+ */
+ public int indexOfValue(double value)
+ {
+ for (int i = 0; i < mSize; i++)
+ {
+ if (mValues[i] == value)
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Removes all key-value mappings from this SparseDoubleArray.
+ */
+ public void clear()
+ {
+ mSize = 0;
+ }
+
+ /**
+ * Puts a key/value pair into the array, optimizing for the case where the key
+ * is greater than all existing keys in the array.
+ */
+ public void append(int key, double value)
+ {
+ if (mSize != 0 && key <= mKeys[mSize - 1])
+ {
+ put(key, value);
+ return;
+ }
+ int pos = mSize;
+ if (pos >= mKeys.length)
+ {
+ int n = idealDoubleArraySize(pos + 1);
+ int[] nkeys = new int[n];
+ double[] nvalues = new double[n];
+ // Log.e("SparseDoubleArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+ mKeys[pos] = key;
+ mValues[pos] = value;
+ mSize = pos + 1;
+ }
+
+ /**
+ * Created by analogy with
+ * com.android.internal.util.ArrayUtils#idealLongArraySize
+ *
+ * @param i
+ * @return
+ */
+ public static int idealDoubleArraySize(int need)
+ {
+ return idealByteArraySize(need * 8) / 8;
+ }
+
+ /**
+ * Inlined here by copying from com.android.internal.util.ArrayUtils
+ *
+ * @param i
+ * @return
+ */
+ public static int idealByteArraySize(int need)
+ {
+ for (int i = 4; i < 32; i++)
+ {
+ if (need <= (1 << i) - 12)
+ {
+ return (1 << i) - 12;
+ }
+ }
+
+ return need;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>
+ * This implementation composes a string by iterating over its mappings.
+ */
+ @Override
+ public String toString()
+ {
+ if (size() <= 0)
+ {
+ return "{}";
+ }
+ StringBuilder buffer = new StringBuilder(mSize * 28);
+ buffer.append('{');
+ for (int i = 0; i < mSize; i++)
+ {
+ if (i > 0)
+ {
+ buffer.append(", ");
+ }
+ int key = keyAt(i);
+ buffer.append(key);
+ buffer.append('=');
+ double value = valueAt(i);
+ buffer.append(value);
+ }
+ buffer.append('}');
+ return buffer.toString();
+ }
+
+ /**
+ * Method (copied from put) added for Jalview to efficiently increment a key's
+ * value if present, else add it with the given value. This avoids a double
+ * binary search (once to get the value, again to put the updated value).
+ *
+ * @param key
+ * @oparam toAdd
+ * @return the new value for the key
+ */
+ public double add(int key, double toAdd)
+ {
+ double newValue = toAdd;
+ int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+ if (i >= 0)
+ {
+ mValues[i] += toAdd;
+ newValue = mValues[i];
+ }
+ else
+ {
+ i = ~i;
+ if (mSize >= mKeys.length)
+ {
+ int n = idealDoubleArraySize(mSize + 1);
+ int[] nkeys = new int[n];
+ double[] nvalues = new double[n];
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+ if (mSize - i != 0)
+ {
+ System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+ System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+ }
+ mKeys[i] = key;
+ mValues[i] = toAdd;
+ mSize++;
+ }
+ return newValue;
+ }
+
+ /**
+ * Method added for Jalview to efficiently multiply a key's value if present,
+ * else do nothing. This avoids a double binary search (once to get the value,
+ * again to put the updated value).
+ *
+ * @param key
+ * @oparam toAdd
+ * @return the new value for the key
+ */
+ public double divide(int key, double divisor)
+ {
+ double newValue = 0d;
+ if (divisor == 0d)
+ {
+ return newValue;
+ }
+ int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+ if (i >= 0)
+ {
+ mValues[i] /= divisor;
+ newValue = mValues[i];
+ }
+ return newValue;
+ }
+}
geneIds.add(geneId);
}
}
+ else if (isProteinIdentifier(acc))
+ {
+ String tscriptId = new EnsemblLookup(getDomain()).getParent(acc);
+ if (tscriptId != null)
+ {
+ String geneId = new EnsemblLookup(getDomain())
+ .getParent(tscriptId);
+ if (geneId != null && !geneIds.contains(geneId))
+ {
+ geneIds.add(geneId);
+ }
+ }
+ // NOTE - acc is lost if it resembles an ENS.+ ID but isn't actually
+ // resolving to one... e.g. ENSMICP00000009241
+ }
/*
* if given a gene or other external name, lookup and fetch
* the corresponding gene for all model organisms
/*
* update these constants when Jalview has been checked / updated for
- * changes to Ensembl REST API
+ * changes to Ensembl REST API (ref JAL-2105)
* @see https://github.com/Ensembl/ensembl-rest/wiki/Change-log
* @see http://rest.ensembl.org/info/rest?content-type=application/json
*/
- private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "4.8";
+ private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "5.0";
- private static final String LATEST_ENSEMBL_REST_VERSION = "4.8";
+ private static final String LATEST_ENSEMBL_REST_VERSION = "5.0";
private static final String REST_CHANGE_LOG = "https://github.com/Ensembl/ensembl-rest/wiki/Change-log";
private final static long VERSION_RETEST_INTERVAL = 1000L * 3600; // 1 hr
+ private static final Regex PROTEIN_REGEX = new Regex(
+ "(ENS)([A-Z]{3}|)P[0-9]{11}$");
+
private static final Regex TRANSCRIPT_REGEX = new Regex(
"(ENS)([A-Z]{3}|)T[0-9]{11}$");
/**
* Answers true if the query matches the regular expression pattern for an
+ * Ensembl protein stable identifier
+ *
+ * @param query
+ * @return
+ */
+ public boolean isProteinIdentifier(String query)
+ {
+ return query == null ? false : PROTEIN_REGEX.search(query);
+ }
+
+ /**
+ * Answers true if the query matches the regular expression pattern for an
* Ensembl gene stable identifier
*
* @param query
boolean laterVersion = StringUtils.compareVersions(version, expected) == 1;
if (laterVersion)
{
- System.err.println(String.format(
- "Expected %s REST version %s but found %s, see %s",
- getDbSource(), expected, version, REST_CHANGE_LOG));
+ System.err
+ .println(String
+ .format("EnsemblRestClient expected %s REST version %s but found %s, see %s",
+ getDbSource(), expected, version,
+ REST_CHANGE_LOG));
}
info.restVersion = version;
} catch (Throwable t)
import jalview.util.Comparison;
import jalview.util.DBRefUtils;
import jalview.util.MapList;
+import jalview.util.RangeComparator;
import java.io.IOException;
import java.net.MalformedURLException;
}
/**
- * A comparator to sort ranges into ascending start position order
- */
- private class RangeSorter implements Comparator<int[]>
- {
- boolean forwards;
-
- RangeSorter(boolean forward)
- {
- forwards = forward;
- }
-
- @Override
- public int compare(int[] o1, int[] o2)
- {
- return (forwards ? 1 : -1) * Integer.compare(o1[0], o2[0]);
- }
-
- }
-
- /**
* Default constructor (to use rest.ensembl.org)
*/
public EnsemblSeqProxy()
* a final sort is needed since Ensembl returns CDS sorted within source
* (havana / ensembl_havana)
*/
- Collections.sort(regions, new RangeSorter(direction == 1));
+ Collections.sort(regions, new RangeComparator(direction == 1));
List<int[]> to = Arrays.asList(new int[] { start,
start + mappedLength - 1 });
*/
package jalview.ext.jmol;
+import jalview.api.AlignmentViewPanel;
import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
import jalview.io.DataSourceType;
import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
import jalview.structures.models.AAStructureBindingModel;
+import jalview.util.MessageManager;
import java.awt.Color;
import java.awt.Container;
import java.net.URL;
import java.security.AccessControlException;
import java.util.ArrayList;
+import java.util.BitSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
public void closeViewer()
{
// remove listeners for all structures in viewer
- getSsm().removeStructureViewerListener(this, this.getPdbFile());
+ getSsm().removeStructureViewerListener(this, this.getStructureFiles());
viewer.dispose();
lastCommand = null;
viewer = null;
* TODO
*/
public void superposeStructures(AlignmentI alignment, int refStructure,
- ColumnSelection hiddenCols)
+ HiddenColumns hiddenCols)
{
superposeStructures(new AlignmentI[] { alignment },
new int[] { refStructure },
- new ColumnSelection[] { hiddenCols });
+ new HiddenColumns[] { hiddenCols });
}
/**
- * Construct and send a command to align structures against a reference
- * structure, based on one or more sequence alignments
- *
- * @param _alignment
- * an array of alignments to process
- * @param _refStructure
- * an array of corresponding reference structures (index into pdb
- * file array); if a negative value is passed, the first PDB file
- * mapped to an alignment sequence is used as the reference for
- * superposition
- * @param _hiddenCols
- * an array of corresponding hidden columns for each alignment
+ * {@inheritDoc}
*/
@Override
- public void superposeStructures(AlignmentI[] _alignment,
- int[] _refStructure, ColumnSelection[] _hiddenCols)
+ public String superposeStructures(AlignmentI[] _alignment,
+ int[] _refStructure, HiddenColumns[] _hiddenCols)
{
while (viewer.isScriptExecuting())
{
* get the distinct structure files modelled
* (a file with multiple chains may map to multiple sequences)
*/
- String[] files = getPdbFile();
+ String[] files = getStructureFiles();
if (!waitForFileLoad(files))
{
- return;
+ return null;
}
StringBuilder selectioncom = new StringBuilder(256);
nSeconds = " " + (2.0 / files.length) + " ";
// if (nSeconds).substring(0,5)+" ";
}
+
// see JAL-1345 - should really automatically turn off the animation for
// large numbers of structures, but Jmol doesn't seem to allow that.
// nSeconds = " ";
{
int refStructure = _refStructure[a];
AlignmentI alignment = _alignment[a];
- ColumnSelection hiddenCols = _hiddenCols[a];
+ HiddenColumns hiddenCols = _hiddenCols[a];
if (a > 0
&& selectioncom.length() > 0
&& !selectioncom.substring(selectioncom.length() - 1).equals(
}
/*
- * 'matched' array will hold 'true' for visible alignment columns where
+ * 'matched' bit j will be set for visible alignment columns j where
* all sequences have a residue with a mapping to the PDB structure
*/
- // TODO could use a BitSet for matched
- boolean matched[] = new boolean[alignment.getWidth()];
- for (int m = 0; m < matched.length; m++)
+ BitSet matched = new BitSet();
+ for (int m = 0; m < alignment.getWidth(); m++)
{
- matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
+ if (hiddenCols == null || hiddenCols.isVisible(m))
+ {
+ matched.set(m);
+ }
}
SuperposeData[] structures = new SuperposeData[files.length];
}
String[] selcom = new String[files.length];
- int nmatched = 0;
- for (boolean b : matched)
- {
- if (b)
- {
- nmatched++;
- }
- }
+ int nmatched = matched.cardinality();
if (nmatched < 4)
{
- // TODO: bail out here because superposition illdefined?
+ return (MessageManager.formatMessage(
+"label.insufficient_residues",
+ nmatched));
}
/*
boolean run = false;
StringBuilder molsel = new StringBuilder();
molsel.append("{");
- for (int r = 0; r < matched.length; r++)
+
+ int nextColumnMatch = matched.nextSetBit(0);
+ while (nextColumnMatch != -1)
{
- if (matched[r])
+ int pdbResNo = structures[pdbfnum].pdbResNo[nextColumnMatch];
+ if (lpos != pdbResNo - 1)
{
- int pdbResNo = structures[pdbfnum].pdbResNo[r];
- if (lpos != pdbResNo - 1)
+ // discontinuity
+ if (lpos != -1)
{
- // discontinuity
- if (lpos != -1)
- {
- molsel.append(lpos);
- molsel.append(chainCd);
- molsel.append("|");
- }
- run = false;
+ molsel.append(lpos);
+ molsel.append(chainCd);
+ molsel.append("|");
}
- else
+ run = false;
+ }
+ else
+ {
+ // continuous run - and lpos >-1
+ if (!run)
{
- // continuous run - and lpos >-1
- if (!run)
- {
- // at the beginning, so add dash
- molsel.append(lpos);
- molsel.append("-");
- }
- run = true;
+ // at the beginning, so add dash
+ molsel.append(lpos);
+ molsel.append("-");
}
- lpos = pdbResNo;
+ run = true;
}
+ lpos = pdbResNo;
+ nextColumnMatch = matched.nextSetBit(nextColumnMatch + 1);
}
/*
* add final selection phrase
+ selectioncom.toString() + "); cartoons; ");
// evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
}
+
+ return null;
}
public void evalStateCommand(String command)
/**
* @param files
* @param sr
- * @param fr
- * @param alignment
+ * @param viewPanel
* @return
*/
@Override
protected StructureMappingcommandSet[] getColourBySequenceCommands(
- String[] files, SequenceRenderer sr, FeatureRenderer fr,
- AlignmentI alignment)
+ String[] files, SequenceRenderer sr, AlignmentViewPanel viewPanel)
{
return JmolCommands.getColourBySequenceCommand(getSsm(), files,
- getSequence(), sr, fr, alignment);
+ getSequence(), sr, viewPanel);
}
/**
private int getModelNum(String modelFileName)
{
- String[] mfn = getPdbFile();
+ String[] mfn = getStructureFiles();
if (mfn == null)
{
return -1;
// ////////////////////////////////
// /StructureListener
- @Override
- public synchronized String[] getPdbFile()
+ // @Override
+ public synchronized String[] getPdbFilex()
{
if (viewer == null)
{
return modelFileNames;
}
+ @Override
+ public synchronized String[] getStructureFiles()
+ {
+ List<String> mset = new ArrayList<String>();
+ if (viewer == null)
+ {
+ return new String[0];
+ }
+
+ if (modelFileNames == null)
+ {
+ int modelCount = viewer.ms.mc;
+ String filePath = null;
+ for (int i = 0; i < modelCount; ++i)
+ {
+ filePath = viewer.ms.getModelFileName(i);
+ if (!mset.contains(filePath))
+ {
+ mset.add(filePath);
+ }
+ }
+ modelFileNames = mset.toArray(new String[mset.size()]);
+ }
+
+ return modelFileNames;
+ }
/**
* map from string to applet
*/
chainNames = new ArrayList<String>();
chainFile = new Hashtable<String, String>();
boolean notifyLoaded = false;
- String[] modelfilenames = getPdbFile();
+ String[] modelfilenames = getStructureFiles();
// first check if we've lost any structures
if (oldmodels != null && oldmodels.length > 0)
{
*/
package jalview.ext.jmol;
+import jalview.api.AlignViewportI;
+import jalview.api.AlignmentViewPanel;
import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.structure.StructureMapping;
import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
import java.awt.Color;
import java.util.ArrayList;
+import java.util.List;
/**
* Routines for generating Jmol commands for Jalview/Jmol binding another
*/
public static StructureMappingcommandSet[] getColourBySequenceCommand(
StructureSelectionManager ssm, String[] files,
- SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr,
- AlignmentI alignment)
+ SequenceI[][] sequence, SequenceRenderer sr,
+ AlignmentViewPanel viewPanel)
{
-
- ArrayList<StructureMappingcommandSet> cset = new ArrayList<StructureMappingcommandSet>();
+ FeatureRenderer fr = viewPanel.getFeatureRenderer();
+ FeatureColourFinder finder = new FeatureColourFinder(fr);
+ AlignViewportI viewport = viewPanel.getAlignViewport();
+ HiddenColumns cs = viewport.getAlignment().getHiddenColumns();
+ AlignmentI al = viewport.getAlignment();
+ List<StructureMappingcommandSet> cset = new ArrayList<StructureMappingcommandSet>();
for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
{
for (int sp, m = 0; m < mapping.length; m++)
{
if (mapping[m].getSequence() == sequence[pdbfnum][s]
- && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
+ && (sp = al.findIndex(sequence[pdbfnum][s])) > -1)
{
- SequenceI asp = alignment.getSequenceAt(sp);
+ SequenceI asp = al.getSequenceAt(sp);
for (int r = 0; r < asp.getLength(); r++)
{
// no mapping to gaps in sequence
lastPos = pos;
- Color col = sr.getResidueBoxColour(sequence[pdbfnum][s], r);
+ Color col = sr.getResidueColour(sequence[pdbfnum][s], r,
+ finder);
- if (fr != null)
+ /*
+ * shade hidden regions darker
+ */
+ if (!cs.isVisible(r))
{
- col = fr.findFeatureColour(col, sequence[pdbfnum][s], r);
+ col = Color.GRAY;
}
+
String newSelcom = (mapping[m].getChain() != " " ? ":"
+ mapping[m].getChain() : "")
+ "/"
--- /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.
+ */
+package jalview.ext.jmol;
+
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.io.FileParse;
+import jalview.io.StructureFile;
+import jalview.schemes.ResidueProperties;
+import jalview.structure.StructureImportSettings;
+import jalview.util.Format;
+import jalview.util.MessageManager;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import javajs.awt.Dimension;
+
+import org.jmol.api.JmolStatusListener;
+import org.jmol.api.JmolViewer;
+import org.jmol.c.CBK;
+import org.jmol.c.STR;
+import org.jmol.modelset.ModelSet;
+import org.jmol.viewer.Viewer;
+
+import MCview.Atom;
+import MCview.PDBChain;
+import MCview.Residue;
+
+/**
+ * Import and process files with Jmol for file like PDB, mmCIF
+ *
+ * @author jprocter
+ *
+ */
+public class JmolParser extends StructureFile implements JmolStatusListener
+{
+ Viewer viewer = null;
+
+ public JmolParser(String inFile, String type) throws IOException
+ {
+ super(inFile, type);
+ }
+
+ public JmolParser(FileParse fp) throws IOException
+ {
+ super(fp);
+ }
+
+ public JmolParser()
+ {
+ }
+
+ /**
+ * Calls the Jmol library to parse the PDB/mmCIF file, and then inspects the
+ * resulting object model to generate Jalview-style sequences, with secondary
+ * structure annotation added where available (i.e. where it has been computed
+ * by Jmol using DSSP).
+ *
+ * @see jalview.io.AlignFile#parse()
+ */
+ @Override
+ public void parse() throws IOException
+ {
+ setChains(new Vector<PDBChain>());
+ Viewer jmolModel = getJmolData();
+ jmolModel.openReader(getDataName(), getDataName(), getReader());
+ waitForScript(jmolModel);
+
+ /*
+ * Convert one or more Jmol Model objects to Jalview sequences
+ */
+ if (jmolModel.ms.mc > 0)
+ {
+ // ideally we do this
+ // try
+ // {
+ // setStructureFileType(jmolModel.evalString("show _fileType"));
+ // } catch (Exception q)
+ // {
+ // }
+ // ;
+ // instead, we distinguish .cif from non-.cif by filename
+ setStructureFileType(getDataName().toLowerCase().endsWith(".cif") ? PDBEntry.Type.MMCIF
+ .toString() : "PDB");
+
+ transformJmolModelToJalview(jmolModel.ms);
+ }
+ }
+
+ /**
+ * create a headless jmol instance for dataprocessing
+ *
+ * @return
+ */
+ private Viewer getJmolData()
+ {
+ if (viewer == null)
+ {
+ try
+ {
+ /*
+ * params -o (output to sysout) -n (nodisplay) -x (exit when finished)
+ * see http://wiki.jmol.org/index.php/Jmol_Application
+ */
+ viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
+ null, "-x -o -n", this);
+ // ensure the 'new' (DSSP) not 'old' (Ramachandran) SS method is used
+ viewer.setBooleanProperty("defaultStructureDSSP", true);
+ } catch (ClassCastException x)
+ {
+ throw new Error(MessageManager.formatMessage(
+ "error.jmol_version_not_compatible_with_jalview_version",
+ new String[] { JmolViewer.getJmolVersion() }), x);
+ }
+ }
+ return viewer;
+ }
+
+ public void transformJmolModelToJalview(ModelSet ms) throws IOException
+ {
+ try
+ {
+ String lastID = "";
+ List<SequenceI> rna = new ArrayList<SequenceI>();
+ List<SequenceI> prot = new ArrayList<SequenceI>();
+ PDBChain tmpchain;
+ String pdbId = (String) ms.getInfo(0, "title");
+
+ if (pdbId == null)
+ {
+ setId(safeName(getDataName()));
+ setPDBIdAvailable(false);
+ }
+ else
+ {
+ setId(pdbId);
+ setPDBIdAvailable(true);
+ }
+ List<Atom> significantAtoms = convertSignificantAtoms(ms);
+ for (Atom tmpatom : significantAtoms)
+ {
+ try
+ {
+ tmpchain = findChain(tmpatom.chain);
+ if (tmpatom.resNumIns.trim().equals(lastID))
+ {
+ // phosphorylated protein - seen both CA and P..
+ continue;
+ }
+ tmpchain.atoms.addElement(tmpatom);
+ } catch (Exception e)
+ {
+ tmpchain = new PDBChain(getId(), tmpatom.chain);
+ getChains().add(tmpchain);
+ tmpchain.atoms.addElement(tmpatom);
+ }
+ lastID = tmpatom.resNumIns.trim();
+ }
+ xferSettings();
+
+ makeResidueList();
+ makeCaBondList();
+
+<<<<<<< HEAD
+=======
+ if (getId() == null)
+ {
+ // always use resource name, not the hardwired file
+ // Does the value of ID get used ? Behaviour needs to be
+ // documented and tested
+ setId(getDataName());
+ }
+>>>>>>> spike/JAL-2040_JAL-2137_phyre2
+ for (PDBChain chain : getChains())
+ {
+ SequenceI chainseq = postProcessChain(chain);
+ if (isRNA(chainseq))
+ {
+ rna.add(chainseq);
+ }
+ else
+ {
+ prot.add(chainseq);
+ }
+
+ if (StructureImportSettings.isProcessSecondaryStructure())
+ {
+ createAnnotation(chainseq, chain, ms.at);
+ }
+ }
+ } catch (OutOfMemoryError er)
+ {
+ System.out
+ .println("OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
+ throw new IOException(
+ MessageManager
+ .getString("exception.outofmemory_loading_mmcif_file"));
+ }
+ }
+
+ private List<Atom> convertSignificantAtoms(ModelSet ms)
+ {
+ List<Atom> significantAtoms = new ArrayList<Atom>();
+ HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
+ org.jmol.modelset.Atom prevAtom = null;
+ for (org.jmol.modelset.Atom atom : ms.at)
+ {
+ if (atom.getAtomName().equalsIgnoreCase("CA")
+ || atom.getAtomName().equalsIgnoreCase("P"))
+ {
+ if (!atomValidated(atom, prevAtom, chainTerMap))
+ {
+ continue;
+ }
+ Atom curAtom = new Atom(atom.x, atom.y, atom.z);
+ curAtom.atomIndex = atom.getIndex();
+ curAtom.chain = atom.getChainIDStr();
+ curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
+ : atom.group.getInsertionCode();
+ curAtom.name = atom.getAtomName();
+ curAtom.number = atom.getAtomNumber();
+ curAtom.resName = atom.getGroup3(true);
+ curAtom.resNumber = atom.getResno();
+ curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
+ .getIndex()] : Float.valueOf(atom.getOccupancy100());
+ String fmt = new Format("%4i").form(curAtom.resNumber);
+ curAtom.resNumIns = (fmt + curAtom.insCode);
+ curAtom.tfactor = atom.getBfactor100() / 100f;
+ curAtom.type = 0;
+ // significantAtoms.add(curAtom);
+ // ignore atoms from subsequent models
+ if (!significantAtoms.contains(curAtom))
+ {
+ significantAtoms.add(curAtom);
+ }
+ prevAtom = atom;
+ }
+ }
+ return significantAtoms;
+ }
+
+ private boolean atomValidated(org.jmol.modelset.Atom curAtom,
+ org.jmol.modelset.Atom prevAtom,
+ HashMap<String, org.jmol.modelset.Atom> chainTerMap)
+ {
+ // System.out.println("Atom: " + curAtom.getAtomNumber()
+ // + " Last atom index " + curAtom.group.lastAtomIndex);
+ if (chainTerMap == null || prevAtom == null)
+ {
+ return true;
+ }
+ String curAtomChId = curAtom.getChainIDStr();
+ String prevAtomChId = prevAtom.getChainIDStr();
+ // new chain encoutered
+ if (!prevAtomChId.equals(curAtomChId))
+ {
+ // On chain switch add previous chain termination to xTerMap if not exists
+ if (!chainTerMap.containsKey(prevAtomChId))
+ {
+ chainTerMap.put(prevAtomChId, prevAtom);
+ }
+ // if current atom belongs to an already terminated chain and the resNum
+ // diff < 5 then mark as valid and update termination Atom
+ if (chainTerMap.containsKey(curAtomChId))
+ {
+ if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
+ {
+ return false;
+ }
+ if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
+ {
+ chainTerMap.put(curAtomChId, curAtom);
+ return true;
+ }
+ return false;
+ }
+ }
+ // atom with previously terminated chain encountered
+ else if (chainTerMap.containsKey(curAtomChId))
+ {
+ if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
+ {
+ return false;
+ }
+ if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
+ {
+ chainTerMap.put(curAtomChId, curAtom);
+ return true;
+ }
+ return false;
+ }
+ // HETATM with resNum jump > 2
+ return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
+ .getResno()) > 2));
+ }
+
+ private void createAnnotation(SequenceI sequence, PDBChain chain,
+ org.jmol.modelset.Atom[] jmolAtoms)
+ {
+ char[] secstr = new char[sequence.getLength()];
+ char[] secstrcode = new char[sequence.getLength()];
+
+ // Ensure Residue size equals Seq size
+ if (chain.residues.size() != sequence.getLength())
+ {
+ return;
+ }
+ int annotIndex = 0;
+ for (Residue residue : chain.residues)
+ {
+ Atom repAtom = residue.getAtoms().get(0);
+ STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
+ .getProteinStructureSubType();
+ setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
+ secstrcode);
+ ++annotIndex;
+ }
+ addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
+ secstrcode, chain.id, sequence.getStart());
+ }
+
+ /**
+ * Helper method that adds an AlignmentAnnotation for secondary structure to
+ * the sequence, provided at least one secondary structure prediction has been
+ * made
+ *
+ * @param modelTitle
+ * @param seq
+ * @param secstr
+ * @param secstrcode
+ * @param chainId
+ * @param firstResNum
+ * @return
+ */
+ protected void addSecondaryStructureAnnotation(String modelTitle,
+ SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
+ int firstResNum)
+ {
+ char[] seq = sq.getSequence();
+ boolean ssFound = false;
+ Annotation asecstr[] = new Annotation[seq.length + firstResNum - 1];
+ for (int p = 0; p < seq.length; p++)
+ {
+ if (secstr[p] >= 'A' && secstr[p] <= 'z')
+ {
+ try
+ {
+ asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
+ secstrcode[p], Float.NaN);
+ ssFound = true;
+ } catch (Exception e)
+ {
+ // e.printStackTrace();
+ }
+ }
+ }
+
+ if (ssFound)
+ {
+ String mt = modelTitle == null ? getDataName() : modelTitle;
+ mt += chainId;
+ AlignmentAnnotation ann = new AlignmentAnnotation(
+ "Secondary Structure", "Secondary Structure for " + mt,
+ asecstr);
+ ann.belowAlignment = true;
+ ann.visible = true;
+ ann.autoCalculated = false;
+ ann.setCalcId(getClass().getName());
+ ann.adjustForAlignment();
+ ann.validateRangeAndDisplay();
+ annotations.add(ann);
+ sq.addAlignmentAnnotation(ann);
+ }
+ }
+
+ private void waitForScript(Viewer jmd)
+ {
+ while (jmd.isScriptExecuting())
+ {
+ try
+ {
+ Thread.sleep(50);
+
+ } catch (InterruptedException x)
+ {
+ }
+ }
+ }
+
+ /**
+ * Convert Jmol's secondary structure code to Jalview's, and stored it in the
+ * secondary structure arrays at the given sequence position
+ *
+ * @param proteinStructureSubType
+ * @param pos
+ * @param secstr
+ * @param secstrcode
+ */
+ protected void setSecondaryStructure(STR proteinStructureSubType,
+ int pos, char[] secstr, char[] secstrcode)
+ {
+ switch (proteinStructureSubType)
+ {
+ case HELIX310:
+ secstr[pos] = '3';
+ break;
+ case HELIX:
+ case HELIXALPHA:
+ secstr[pos] = 'H';
+ break;
+ case HELIXPI:
+ secstr[pos] = 'P';
+ break;
+ case SHEET:
+ secstr[pos] = 'E';
+ break;
+ default:
+ secstr[pos] = 0;
+ }
+
+ switch (proteinStructureSubType)
+ {
+ case HELIX310:
+ case HELIXALPHA:
+ case HELIXPI:
+ case HELIX:
+ secstrcode[pos] = 'H';
+ break;
+ case SHEET:
+ secstrcode[pos] = 'E';
+ break;
+ default:
+ secstrcode[pos] = 0;
+ }
+ }
+
+ /**
+ * Convert any non-standard peptide codes to their standard code table
+ * equivalent. (Initial version only does Selenomethionine MSE->MET.)
+ *
+ * @param threeLetterCode
+ * @param seq
+ * @param pos
+ */
+ protected void replaceNonCanonicalResidue(String threeLetterCode,
+ char[] seq, int pos)
+ {
+ String canonical = ResidueProperties
+ .getCanonicalAminoAcid(threeLetterCode);
+ if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
+ {
+ seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
+ }
+ }
+
+ /**
+ * Not implemented - returns null
+ */
+ @Override
+ public String print()
+ {
+ return null;
+ }
+
+ /**
+ * Not implemented
+ */
+ @Override
+ public void setCallbackFunction(String callbackType,
+ String callbackFunction)
+ {
+ }
+
+ @Override
+ public void notifyCallback(CBK cbType, Object[] data)
+ {
+ String strInfo = (data == null || data[1] == null ? null : data[1]
+ .toString());
+ switch (cbType)
+ {
+ case ECHO:
+ sendConsoleEcho(strInfo);
+ break;
+ case SCRIPT:
+ notifyScriptTermination((String) data[2],
+ ((Integer) data[3]).intValue());
+ break;
+ case MEASURE:
+ String mystatus = (String) data[3];
+ if (mystatus.indexOf("Picked") >= 0
+ || mystatus.indexOf("Sequence") >= 0)
+ {
+ // Picking mode
+ sendConsoleMessage(strInfo);
+ }
+ else if (mystatus.indexOf("Completed") >= 0)
+ {
+ sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
+ strInfo.length() - 1));
+ }
+ break;
+ case MESSAGE:
+ sendConsoleMessage(data == null ? null : strInfo);
+ break;
+ case PICK:
+ sendConsoleMessage(strInfo);
+ break;
+ default:
+ break;
+ }
+ }
+
+ String lastConsoleEcho = "";
+
+ private void sendConsoleEcho(String string)
+ {
+ lastConsoleEcho += string;
+ lastConsoleEcho += "\n";
+ }
+
+ String lastConsoleMessage = "";
+
+ private void sendConsoleMessage(String string)
+ {
+ lastConsoleMessage += string;
+ lastConsoleMessage += "\n";
+ }
+
+ int lastScriptTermination = -1;
+
+ String lastScriptMessage = "";
+
+ private void notifyScriptTermination(String string, int intValue)
+ {
+ lastScriptMessage += string;
+ lastScriptMessage += "\n";
+ lastScriptTermination = intValue;
+ }
+
+ @Override
+ public boolean notifyEnabled(CBK callbackPick)
+ {
+ switch (callbackPick)
+ {
+ case MESSAGE:
+ case SCRIPT:
+ case ECHO:
+ case LOADSTRUCT:
+ case ERROR:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Not implemented - returns null
+ */
+ @Override
+ public String eval(String strEval)
+ {
+ return null;
+ }
+
+ /**
+ * Not implemented - returns null
+ */
+ @Override
+ public float[][] functionXY(String functionName, int x, int y)
+ {
+ return null;
+ }
+
+ /**
+ * Not implemented - returns null
+ */
+ @Override
+ public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
+ {
+ return null;
+ }
+
+ /**
+ * Not implemented - returns null
+ */
+ @Override
+ public String createImage(String fileName, String imageType,
+ Object text_or_bytes, int quality)
+ {
+ return null;
+ }
+
+ /**
+ * Not implemented - returns null
+ */
+ @Override
+ public Map<String, Object> getRegistryInfo()
+ {
+ return null;
+ }
+
+ /**
+ * Not implemented
+ */
+ @Override
+ public void showUrl(String url)
+ {
+ }
+
+ /**
+ * Not implemented - returns null
+ */
+ @Override
+ public Dimension resizeInnerPanel(String data)
+ {
+ return null;
+ }
+
+ @Override
+ public Map<String, Object> getJSpecViewProperty(String arg0)
+ {
+ return null;
+ }
+
+ public boolean isPredictSecondaryStructure()
+ {
+ return predictSecondaryStructure;
+ }
+
+ public void setPredictSecondaryStructure(boolean predictSecondaryStructure)
+ {
+ this.predictSecondaryStructure = predictSecondaryStructure;
+ }
+
+ public boolean isVisibleChainAnnotation()
+ {
+ return visibleChainAnnotation;
+ }
+
+ public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
+ {
+ this.visibleChainAnnotation = visibleChainAnnotation;
+ }
+
+}
--- /dev/null
+package jalview.ext.rbvi.chimera;
+
+import jalview.util.RangeComparator;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * A class to model a Chimera atomspec pattern, for example
+ *
+ * <pre>
+ * #0:15.A,28.A,54.A,63.A,70-72.A,83-84.A,97-98.A|#1:2.A,6.A,11.A,13-14.A,70.A,82.A,96-97.A
+ * </pre>
+ *
+ * where
+ * <ul>
+ * <li>#0 is a model number</li>
+ * <li>15 or 70-72 is a residue number, or range of residue numbers</li>
+ * <li>.A is a chain identifier</li>
+ * <li>residue ranges are separated by comma</li>
+ * <li>atomspecs for distinct models are separated by | (or)</li>
+ * </ul>
+ *
+ * <pre>
+ * @see http://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec.html
+ * </pre>
+ */
+public class AtomSpecModel
+{
+ private Map<Integer, Map<String, List<int[]>>> atomSpec;
+
+ /**
+ * Constructor
+ */
+ public AtomSpecModel()
+ {
+ atomSpec = new TreeMap<Integer, Map<String, List<int[]>>>();
+ }
+
+ /**
+ * Adds one contiguous range to this atom spec
+ *
+ * @param model
+ * @param startPos
+ * @param endPos
+ * @param chain
+ */
+ public void addRange(int model, int startPos, int endPos, String chain)
+ {
+ /*
+ * Get/initialize map of data for the colour and model
+ */
+ Map<String, List<int[]>> modelData = atomSpec.get(model);
+ if (modelData == null)
+ {
+ atomSpec.put(model, modelData = new TreeMap<String, List<int[]>>());
+ }
+
+ /*
+ * Get/initialize map of data for colour, model and chain
+ */
+ List<int[]> chainData = modelData.get(chain);
+ if (chainData == null)
+ {
+ chainData = new ArrayList<int[]>();
+ modelData.put(chain, chainData);
+ }
+
+ /*
+ * Add the start/end positions
+ */
+ chainData.add(new int[] { startPos, endPos });
+ // TODO add intelligently, using a RangeList class
+ }
+
+ /**
+ * Returns the range(s) formatted as a Chimera atomspec
+ *
+ * @return
+ */
+ public String getAtomSpec()
+ {
+ StringBuilder sb = new StringBuilder(128);
+ boolean firstModel = true;
+ for (Integer model : atomSpec.keySet())
+ {
+ if (!firstModel)
+ {
+ sb.append("|");
+ }
+ firstModel = false;
+ sb.append("#").append(model).append(":");
+
+ boolean firstPositionForModel = true;
+ final Map<String, List<int[]>> modelData = atomSpec.get(model);
+
+ for (String chain : modelData.keySet())
+ {
+ chain = chain.trim();
+
+ List<int[]> rangeList = modelData.get(chain);
+
+ /*
+ * sort ranges into ascending start position order
+ */
+ Collections.sort(rangeList, new RangeComparator(true));
+
+ int start = rangeList.isEmpty() ? 0 : rangeList.get(0)[0];
+ int end = rangeList.isEmpty() ? 0 : rangeList.get(0)[1];
+
+ Iterator<int[]> iterator = rangeList.iterator();
+ while (iterator.hasNext())
+ {
+ int[] range = iterator.next();
+ if (range[0] <= end + 1)
+ {
+ /*
+ * range overlaps or is contiguous with the last one
+ * - so just extend the end position, and carry on
+ * (unless this is the last in the list)
+ */
+ end = Math.max(end, range[1]);
+ }
+ else
+ {
+ /*
+ * we have a break so append the last range
+ */
+ appendRange(sb, start, end, chain, firstPositionForModel);
+ firstPositionForModel = false;
+ start = range[0];
+ end = range[1];
+ }
+ }
+
+ /*
+ * and append the last range
+ */
+ if (!rangeList.isEmpty())
+ {
+ appendRange(sb, start, end, chain, firstPositionForModel);
+ firstPositionForModel = false;
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * @param sb
+ * @param start
+ * @param end
+ * @param chain
+ * @param firstPositionForModel
+ */
+ protected void appendRange(StringBuilder sb, int start, int end,
+ String chain, boolean firstPositionForModel)
+ {
+ if (!firstPositionForModel)
+ {
+ sb.append(",");
+ }
+ if (end == start)
+ {
+ sb.append(start);
+ }
+ else
+ {
+ sb.append(start).append("-").append(end);
+ }
+ if (chain.length() > 0)
+ {
+ sb.append(".").append(chain);
+ }
+ }
+}
*/
package jalview.ext.rbvi.chimera;
+import jalview.api.AlignViewportI;
+import jalview.api.AlignmentViewPanel;
import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.structure.StructureMapping;
import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
import java.awt.Color;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
/**
* Routines for generating Chimera commands for Jalview/Chimera binding
public class ChimeraCommands
{
+ public static final String NAMESPACE_PREFIX = "jv_";
+
/**
- * utility to construct the commands to colour chains by the given alignment
- * for passing to Chimera
- *
- * @returns Object[] { Object[] { <model being coloured>,
+ * Constructs Chimera commands to colour residues as per the Jalview alignment
*
+ * @param ssm
+ * @param files
+ * @param sequence
+ * @param sr
+ * @param fr
+ * @param viewPanel
+ * @return
*/
public static StructureMappingcommandSet[] getColourBySequenceCommand(
StructureSelectionManager ssm, String[] files,
- SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr,
- AlignmentI alignment)
+ SequenceI[][] sequence, SequenceRenderer sr,
+ AlignmentViewPanel viewPanel)
{
- Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> colourMap = buildColoursMap(
- ssm, files, sequence, sr, fr, alignment);
+ Map<Object, AtomSpecModel> colourMap = buildColoursMap(ssm, files,
+ sequence, sr, viewPanel);
List<String> colourCommands = buildColourCommands(colourMap);
StructureMappingcommandSet cs = new StructureMappingcommandSet(
ChimeraCommands.class, null,
- colourCommands.toArray(new String[0]));
+ colourCommands.toArray(new String[colourCommands.size()]));
return new StructureMappingcommandSet[] { cs };
}
* 'color' commands (one per distinct colour used). The format of each command
* is
*
- * <blockquote> color colorname #modelnumber:range.chain e.g. color #00ff00
- * #0:2.B,4.B,9-12.B|#1:1.A,2-6.A,...
- *
- * @see http
- * ://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec
- * .html </pre>
+ * <pre>
+ * <blockquote>
+ * color colorname #modelnumber:range.chain
+ * e.g. color #00ff00 #0:2.B,4.B,9-12.B|#1:1.A,2-6.A,...
+ * </blockquote>
+ * </pre>
*
* @param colourMap
* @return
*/
protected static List<String> buildColourCommands(
- Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> colourMap)
+ Map<Object, AtomSpecModel> colourMap)
{
/*
* This version concatenates all commands into a single String (semi-colon
List<String> commands = new ArrayList<String>();
StringBuilder sb = new StringBuilder(256);
boolean firstColour = true;
- for (Color colour : colourMap.keySet())
+ for (Object key : colourMap.keySet())
{
+ Color colour = (Color) key;
String colourCode = ColorUtils.toTkCode(colour);
if (!firstColour)
{
}
sb.append("color ").append(colourCode).append(" ");
firstColour = false;
- boolean firstModelForColour = true;
- final Map<Integer, Map<String, List<int[]>>> colourData = colourMap
- .get(colour);
- for (Integer model : colourData.keySet())
+ final AtomSpecModel colourData = colourMap.get(colour);
+ sb.append(colourData.getAtomSpec());
+ }
+ commands.add(sb.toString());
+ return commands;
+ }
+
+ /**
+ * Traverses a map of { modelNumber, {chain, {list of from-to ranges} } } and
+ * builds a Chimera format atom spec
+ *
+ * @param modelAndChainRanges
+ */
+ protected static String getAtomSpec(
+ Map<Integer, Map<String, List<int[]>>> modelAndChainRanges)
+ {
+ StringBuilder sb = new StringBuilder(128);
+ boolean firstModelForColour = true;
+ for (Integer model : modelAndChainRanges.keySet())
+ {
+ boolean firstPositionForModel = true;
+ if (!firstModelForColour)
{
- boolean firstPositionForModel = true;
- if (!firstModelForColour)
- {
- sb.append("|");
- }
- firstModelForColour = false;
- sb.append("#").append(model).append(":");
+ sb.append("|");
+ }
+ firstModelForColour = false;
+ sb.append("#").append(model).append(":");
- final Map<String, List<int[]>> modelData = colourData.get(model);
- for (String chain : modelData.keySet())
+ final Map<String, List<int[]>> modelData = modelAndChainRanges
+ .get(model);
+ for (String chain : modelData.keySet())
+ {
+ boolean hasChain = !"".equals(chain.trim());
+ for (int[] range : modelData.get(chain))
{
- boolean hasChain = !"".equals(chain.trim());
- for (int[] range : modelData.get(chain))
+ if (!firstPositionForModel)
{
- if (!firstPositionForModel)
- {
- sb.append(",");
- }
- if (range[0] == range[1])
- {
- sb.append(range[0]);
- }
- else
- {
- sb.append(range[0]).append("-").append(range[1]);
- }
- if (hasChain)
- {
- sb.append(".").append(chain);
- }
- firstPositionForModel = false;
+ sb.append(",");
}
+ if (range[0] == range[1])
+ {
+ sb.append(range[0]);
+ }
+ else
+ {
+ sb.append(range[0]).append("-").append(range[1]);
+ }
+ if (hasChain)
+ {
+ sb.append(".").append(chain);
+ }
+ firstPositionForModel = false;
}
}
}
- commands.add(sb.toString());
- return commands;
+ return sb.toString();
}
/**
* <pre>
- * Build a data structure which maps contiguous subsequences for each colour.
- * This generates a data structure from which we can easily generate the
- * Chimera command for colour by sequence.
+ * Build a data structure which records contiguous subsequences for each colour.
+ * From this we can easily generate the Chimera command for colour by sequence.
* Color
* Model number
* Chain
* Ordering is by order of addition (for colours and positions), natural ordering (for models and chains)
* </pre>
*/
- protected static Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> buildColoursMap(
+ protected static Map<Object, AtomSpecModel> buildColoursMap(
StructureSelectionManager ssm, String[] files,
- SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr,
- AlignmentI alignment)
+ SequenceI[][] sequence, SequenceRenderer sr,
+ AlignmentViewPanel viewPanel)
{
- Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> colourMap = new LinkedHashMap<Color, SortedMap<Integer, Map<String, List<int[]>>>>();
+ FeatureRenderer fr = viewPanel.getFeatureRenderer();
+ FeatureColourFinder finder = new FeatureColourFinder(fr);
+ AlignViewportI viewport = viewPanel.getAlignViewport();
+ HiddenColumns cs = viewport.getAlignment().getHiddenColumns();
+ AlignmentI al = viewport.getAlignment();
+ Map<Object, AtomSpecModel> colourMap = new LinkedHashMap<Object, AtomSpecModel>();
Color lastColour = null;
+
for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
{
StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
{
final SequenceI seq = sequence[pdbfnum][s];
if (mapping[m].getSequence() == seq
- && (sp = alignment.findIndex(seq)) > -1)
+ && (sp = al.findIndex(seq)) > -1)
{
- SequenceI asp = alignment.getSequenceAt(sp);
+ SequenceI asp = al.getSequenceAt(sp);
for (int r = 0; r < asp.getLength(); r++)
{
// no mapping to gaps in sequence
continue;
}
- Color colour = sr.getResidueColour(seq, r, fr);
+ Color colour = sr.getResidueColour(seq, r, finder);
+
+ /*
+ * darker colour for hidden regions
+ */
+ if (!cs.isVisible(r))
+ {
+ colour = Color.GRAY;
+ }
+
final String chain = mapping[m].getChain();
/*
// final colour range
if (lastColour != null)
{
- addColourRange(colourMap, lastColour, pdbfnum, startPos,
- lastPos, lastChain);
+ addColourRange(colourMap, lastColour, pdbfnum, startPos, lastPos,
+ lastChain);
}
// break;
}
/**
* Helper method to add one contiguous colour range to the colour map.
*
- * @param colourMap
- * @param colour
+ * @param map
+ * @param key
* @param model
* @param startPos
* @param endPos
* @param chain
*/
- protected static void addColourRange(
- Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> colourMap,
- Color colour, int model, int startPos, int endPos, String chain)
+ protected static void addColourRange(Map<Object, AtomSpecModel> map,
+ Object key, int model, int startPos, int endPos, String chain)
{
/*
* Get/initialize map of data for the colour
*/
- SortedMap<Integer, Map<String, List<int[]>>> colourData = colourMap
- .get(colour);
- if (colourData == null)
+ AtomSpecModel atomSpec = map.get(key);
+ if (atomSpec == null)
{
- colourMap
- .put(colour,
- colourData = new TreeMap<Integer, Map<String, List<int[]>>>());
+ atomSpec = new AtomSpecModel();
+ map.put(key, atomSpec);
}
- /*
- * Get/initialize map of data for the colour and model
- */
- Map<String, List<int[]>> modelData = colourData.get(model);
- if (modelData == null)
+ atomSpec.addRange(model, startPos, endPos, chain);
+ }
+
+ /**
+ * Constructs and returns Chimera commands to set attributes on residues
+ * corresponding to features in Jalview. Attribute names are the Jalview
+ * feature type, with a "jv_" prefix.
+ *
+ * @param ssm
+ * @param files
+ * @param seqs
+ * @param viewPanel
+ * @return
+ */
+ public static StructureMappingcommandSet getSetAttributeCommandsForFeatures(
+ StructureSelectionManager ssm, String[] files,
+ SequenceI[][] seqs, AlignmentViewPanel viewPanel)
+ {
+ Map<String, Map<Object, AtomSpecModel>> featureMap = buildFeaturesMap(
+ ssm, files, seqs, viewPanel);
+
+ List<String> commands = buildSetAttributeCommands(featureMap);
+
+ StructureMappingcommandSet cs = new StructureMappingcommandSet(
+ ChimeraCommands.class, null,
+ commands.toArray(new String[commands.size()]));
+
+ return cs;
+ }
+
+ /**
+ * <pre>
+ * Helper method to build a map of
+ * { featureType, { feature value, AtomSpecModel } }
+ * </pre>
+ *
+ * @param ssm
+ * @param files
+ * @param seqs
+ * @param viewPanel
+ * @return
+ */
+ protected static Map<String, Map<Object, AtomSpecModel>> buildFeaturesMap(
+ StructureSelectionManager ssm, String[] files,
+ SequenceI[][] seqs, AlignmentViewPanel viewPanel)
+ {
+ Map<String, Map<Object, AtomSpecModel>> theMap = new LinkedHashMap<String, Map<Object, AtomSpecModel>>();
+
+ FeatureRenderer fr = viewPanel.getFeatureRenderer();
+ if (fr == null)
{
- colourData.put(model, modelData = new TreeMap<String, List<int[]>>());
+ return theMap;
}
- /*
- * Get/initialize map of data for colour, model and chain
- */
- List<int[]> chainData = modelData.get(chain);
- if (chainData == null)
+ List<String> visibleFeatures = fr.getDisplayedFeatureTypes();
+ if (visibleFeatures.isEmpty())
{
- modelData.put(chain, chainData = new ArrayList<int[]>());
+ return theMap;
}
+ AlignmentI alignment = viewPanel.getAlignment();
+ for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
+ {
+ StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
+
+ if (mapping == null || mapping.length < 1)
+ {
+ continue;
+ }
+
+ for (int seqNo = 0; seqNo < seqs[pdbfnum].length; seqNo++)
+ {
+ for (int m = 0; m < mapping.length; m++)
+ {
+ final SequenceI seq = seqs[pdbfnum][seqNo];
+ int sp = alignment.findIndex(seq);
+ if (mapping[m].getSequence() == seq && sp > -1)
+ {
+ /*
+ * found a sequence with a mapping to a structure;
+ * now scan its features
+ */
+ SequenceI asp = alignment.getSequenceAt(sp);
+
+ scanSequenceFeatures(visibleFeatures, mapping[m], asp, theMap,
+ pdbfnum);
+ }
+ }
+ }
+ }
+ return theMap;
+ }
+
+ /**
+ * Inspect features on the sequence; for each feature that is visible,
+ * determine its mapped ranges in the structure (if any) according to the
+ * given mapping, and add them to the map
+ *
+ * @param visibleFeatures
+ * @param mapping
+ * @param seq
+ * @param theMap
+ * @param modelNumber
+ */
+ protected static void scanSequenceFeatures(List<String> visibleFeatures,
+ StructureMapping mapping, SequenceI seq,
+ Map<String, Map<Object, AtomSpecModel>> theMap, int modelNumber)
+ {
+ SequenceFeature[] sfs = seq.getSequenceFeatures();
+ if (sfs == null)
+ {
+ return;
+ }
+
+ for (SequenceFeature sf : sfs)
+ {
+ String type = sf.getType();
+
+ /*
+ * Only copy visible features, don't copy any which originated
+ * from Chimera, and suppress uninteresting ones (e.g. RESNUM)
+ */
+ boolean isFromViewer = JalviewChimeraBinding.CHIMERA_FEATURE_GROUP
+ .equals(sf.getFeatureGroup());
+ if (isFromViewer || !visibleFeatures.contains(type))
+ {
+ continue;
+ }
+ List<int[]> mappedRanges = mapping.getPDBResNumRanges(sf.getBegin(),
+ sf.getEnd());
+
+ if (!mappedRanges.isEmpty())
+ {
+ String value = sf.getDescription();
+ if (value == null || value.length() == 0)
+ {
+ value = type;
+ }
+ float score = sf.getScore();
+ if (score != 0f && !Float.isNaN(score))
+ {
+ value = Float.toString(score);
+ }
+ Map<Object, AtomSpecModel> featureValues = theMap.get(type);
+ if (featureValues == null)
+ {
+ featureValues = new HashMap<Object, AtomSpecModel>();
+ theMap.put(type, featureValues);
+ }
+ for (int[] range : mappedRanges)
+ {
+ addColourRange(featureValues, value, modelNumber, range[0], range[1],
+ mapping.getChain());
+ }
+ }
+ }
+ }
+
+ /**
+ * Traverse the map of features/values/models/chains/positions to construct a
+ * list of 'setattr' commands (one per distinct feature type and value).
+ * <p>
+ * The format of each command is
+ *
+ * <pre>
+ * <blockquote> setattr r <featureName> " " #modelnumber:range.chain
+ * e.g. setattr r jv:chain <value> #0:2.B,4.B,9-12.B|#1:1.A,2-6.A,...
+ * </blockquote>
+ * </pre>
+ *
+ * @param featureMap
+ * @return
+ */
+ protected static List<String> buildSetAttributeCommands(
+ Map<String, Map<Object, AtomSpecModel>> featureMap)
+ {
+ List<String> commands = new ArrayList<String>();
+ for (String featureType : featureMap.keySet())
+ {
+ String attributeName = makeAttributeName(featureType);
+
+ /*
+ * clear down existing attributes for this feature
+ */
+ // 'problem' - sets attribute to None on all residues - overkill?
+ // commands.add("~setattr r " + attributeName + " :*");
+
+ Map<Object, AtomSpecModel> values = featureMap.get(featureType);
+ for (Object value : values.keySet())
+ {
+ /*
+ * for each distinct value recorded for this feature type,
+ * add a command to set the attribute on the mapped residues
+ * Put values in single quotes, encoding any embedded single quotes
+ */
+ StringBuilder sb = new StringBuilder(128);
+ String featureValue = value.toString();
+ featureValue = featureValue.replaceAll("\\'", "'");
+ sb.append("setattr r ").append(attributeName).append(" '")
+ .append(featureValue).append("' ");
+ sb.append(values.get(value).getAtomSpec());
+ commands.add(sb.toString());
+ }
+ }
+
+ return commands;
+ }
+
+ /**
+ * Makes a prefixed and valid Chimera attribute name. A jv_ prefix is applied
+ * for a 'Jalview' namespace, and any non-alphanumeric character is converted
+ * to an underscore.
+ *
+ * @param featureType
+ * @return <pre>
+ * @see https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/setattr.html
+ * </pre>
+ */
+ protected static String makeAttributeName(String featureType)
+ {
+ StringBuilder sb = new StringBuilder();
+ if (featureType != null)
+ {
+ for (char c : featureType.toCharArray())
+ {
+ sb.append(Character.isLetterOrDigit(c) ? c : '_');
+ }
+ }
+ String attName = NAMESPACE_PREFIX + sb.toString();
+
/*
- * Add the start/end positions
+ * Chimera treats an attribute name ending in 'color' as colour-valued;
+ * Jalview doesn't, so prevent this by appending an underscore
*/
- chainData.add(new int[] { startPos, endPos });
+ if (attName.toUpperCase().endsWith("COLOR"))
+ {
+ attName += "_";
+ }
+
+ return attName;
}
}
}
/**
- * Handler a ModelChanged notification from Chimera
+ * Handle a ModelChanged notification from Chimera
*
* @param substring
*/
package jalview.ext.rbvi.chimera;
import jalview.api.AlignmentViewPanel;
-import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.api.structures.JalviewStructureDisplayI;
import jalview.bin.Cache;
import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SearchResultMatchI;
+import jalview.datamodel.SearchResultsI;
+import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
import jalview.httpserver.AbstractRequestHandler;
import jalview.io.DataSourceType;
import jalview.util.MessageManager;
import java.awt.Color;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
import java.net.BindException;
import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collections;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
public abstract class JalviewChimeraBinding extends AAStructureBindingModel
{
+ public static final String CHIMERA_FEATURE_GROUP = "Chimera";
+
// Chimera clause to exclude alternate locations in atom selection
private static final String NO_ALTLOCS = "&~@.B-Z&~@.2-9";
*/
private Map<String, List<ChimeraModel>> chimeraMaps = new LinkedHashMap<String, List<ChimeraModel>>();
- /*
- * the default or current model displayed if the model cannot be identified
- * from the selection message
- */
- private int frameNo = 0;
-
- private String lastCommand;
-
String lastHighlightCommand;
/*
if (getSsm() != null)
{
getSsm().addStructureViewerListener(this);
- // ssm.addSelectionListener(this);
- FeatureRenderer fr = getFeatureRenderer(null);
- if (fr != null)
- {
- fr.featuresAdded();
- }
- refreshGUI();
}
return true;
} catch (Exception q)
*/
public void closeViewer(boolean closeChimera)
{
- getSsm().removeStructureViewerListener(this, this.getPdbFile());
+ getSsm().removeStructureViewerListener(this, this.getStructureFiles());
if (closeChimera)
{
viewer.exitChimera();
chimeraListener.shutdown();
chimeraListener = null;
}
- lastCommand = null;
viewer = null;
if (chimeraMonitor != null)
}
/**
- * Construct and send a command to align structures against a reference
- * structure, based on one or more sequence alignments
- *
- * @param _alignment
- * an array of alignments to process
- * @param _refStructure
- * an array of corresponding reference structures (index into pdb
- * file array); if a negative value is passed, the first PDB file
- * mapped to an alignment sequence is used as the reference for
- * superposition
- * @param _hiddenCols
- * an array of corresponding hidden columns for each alignment
+ * {@inheritDoc}
*/
@Override
- public void superposeStructures(AlignmentI[] _alignment,
- int[] _refStructure, ColumnSelection[] _hiddenCols)
+ public String superposeStructures(AlignmentI[] _alignment,
+ int[] _refStructure, HiddenColumns[] _hiddenCols)
{
StringBuilder allComs = new StringBuilder(128);
- String[] files = getPdbFile();
+ String[] files = getStructureFiles();
if (!waitForFileLoad(files))
{
- return;
+ return null;
}
refreshPdbEntries();
{
int refStructure = _refStructure[a];
AlignmentI alignment = _alignment[a];
- ColumnSelection hiddenCols = _hiddenCols[a];
+ HiddenColumns hiddenCols = _hiddenCols[a];
if (refStructure >= files.length)
{
}
/*
- * 'matched' array will hold 'true' for visible alignment columns where
+ * 'matched' bit i will be set for visible alignment columns i where
* all sequences have a residue with a mapping to the PDB structure
*/
- boolean matched[] = new boolean[alignment.getWidth()];
- for (int m = 0; m < matched.length; m++)
+ BitSet matched = new BitSet();
+ for (int m = 0; m < alignment.getWidth(); m++)
{
- matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
+ if (hiddenCols == null || hiddenCols.isVisible(m))
+ {
+ matched.set(m);
+ }
}
SuperposeData[] structures = new SuperposeData[files.length];
refStructure = candidateRefStructure;
}
- int nmatched = 0;
- for (boolean b : matched)
- {
- if (b)
- {
- nmatched++;
- }
- }
+ int nmatched = matched.cardinality();
if (nmatched < 4)
{
- // TODO: bail out here because superposition illdefined?
+ return MessageManager.formatMessage("label.insufficient_residues",
+ nmatched);
}
/*
int lpos = -1;
boolean run = false;
StringBuilder molsel = new StringBuilder();
- for (int r = 0; r < matched.length; r++)
+
+ int nextColumnMatch = matched.nextSetBit(0);
+ while (nextColumnMatch != -1)
{
- if (matched[r])
+ int pdbResNum = structures[pdbfnum].pdbResNo[nextColumnMatch];
+ if (lpos != pdbResNum - 1)
{
- int pdbResNum = structures[pdbfnum].pdbResNo[r];
- if (lpos != pdbResNum - 1)
+ /*
+ * discontiguous - append last residue now
+ */
+ if (lpos != -1)
{
- /*
- * discontiguous - append last residue now
- */
- if (lpos != -1)
- {
- molsel.append(String.valueOf(lpos));
- molsel.append(chainCd);
- molsel.append(",");
- }
- run = false;
+ molsel.append(String.valueOf(lpos));
+ molsel.append(chainCd);
+ molsel.append(",");
}
- else
+ run = false;
+ }
+ else
+ {
+ /*
+ * extending a contiguous run
+ */
+ if (!run)
{
/*
- * extending a contiguous run
+ * start the range selection
*/
- if (!run)
- {
- /*
- * start the range selection
- */
- molsel.append(String.valueOf(lpos));
- molsel.append("-");
- }
- run = true;
+ molsel.append(String.valueOf(lpos));
+ molsel.append("-");
}
- lpos = pdbResNum;
+ run = true;
}
+ lpos = pdbResNum;
+ nextColumnMatch = matched.nextSetBit(nextColumnMatch + 1);
}
/*
.append(";" + command.toString());
}
}
+
+ String error = null;
if (selectioncom.length() > 0)
{
// TODO: visually distinguish regions that were superposed
}
allComs.append("; ~display all; chain @CA|P; ribbon ")
.append(selectioncom.toString()).append("; focus");
- sendChimeraCommand(allComs.toString(), false);
+ List<String> chimeraReplies = sendChimeraCommand(allComs.toString(),
+ true);
+ for (String reply : chimeraReplies)
+ {
+ if (reply.toLowerCase().contains("unequal numbers of atoms"))
+ {
+ error = reply;
+ }
+ }
}
-
+ return error;
}
/**
* to the Chimera command 'list models type molecule', see
* ChimeraManager.getModelList().
*/
- List<ChimeraModel> maps = chimeraMaps.get(getPdbFile()[pdbfnum]);
+ List<ChimeraModel> maps = chimeraMaps.get(getStructureFiles()[pdbfnum]);
boolean hasSubModels = maps != null && maps.size() > 1;
return "#" + String.valueOf(pdbfnum) + (hasSubModels ? ".1" : "");
}
}
/**
- * Send a command to Chimera, and optionally log any responses.
+ * Send a command to Chimera, and optionally log and return any responses.
+ * <p>
+ * Does nothing, and returns null, if the command is the same as the last one
+ * sent [why?].
*
* @param command
- * @param logResponse
+ * @param getResponse
*/
- public void sendChimeraCommand(final String command, boolean logResponse)
+ public List<String> sendChimeraCommand(final String command,
+ boolean getResponse)
{
if (viewer == null)
{
// ? thread running after viewer shut down
- return;
+ return null;
}
+ List<String> reply = null;
viewerCommandHistory(false);
- if (lastCommand == null || !lastCommand.equals(command))
+ if (true /*lastCommand == null || !lastCommand.equals(command)*/)
{
// trim command or it may never find a match in the replyLog!!
List<String> lastReply = viewer.sendChimeraCommand(command.trim(),
- logResponse);
- if (logResponse && debug)
+ getResponse);
+ if (getResponse)
{
- log("Response from command ('" + command + "') was:\n" + lastReply);
+ reply = lastReply;
+ if (debug)
+ {
+ log("Response from command ('" + command + "') was:\n"
+ + lastReply);
+ }
}
}
viewerCommandHistory(true);
- lastCommand = command;
+
+ return reply;
}
/**
/**
* @param files
* @param sr
- * @param fr
- * @param alignment
+ * @param viewPanel
* @return
*/
@Override
protected StructureMappingcommandSet[] getColourBySequenceCommands(
- String[] files, SequenceRenderer sr, FeatureRenderer fr,
- AlignmentI alignment)
+ String[] files, SequenceRenderer sr, AlignmentViewPanel viewPanel)
{
return ChimeraCommands.getColourBySequenceCommand(getSsm(), files,
- getSequence(), sr, fr, alignment);
+ getSequence(), sr, viewPanel);
}
/**
*/
private int _modelFileNameMap[];
+
// ////////////////////////////////
// /StructureListener
@Override
- public synchronized String[] getPdbFile()
+ public synchronized String[] getStructureFiles()
{
if (viewer == null)
{
* Parse model number, residue and chain for each selected position,
* formatted as #0:123.A or #1.2:87.B (#model.submodel:residue.chain)
*/
+ List<AtomSpec> atomSpecs = convertStructureResiduesToAlignment(selection);
+
+ /*
+ * Broadcast the selection (which may be empty, if the user just cleared all
+ * selections)
+ */
+ getSsm().mouseOverStructure(atomSpecs);
+ }
+
+ /**
+ * Converts a list of Chimera atomspecs to a list of AtomSpec representing the
+ * corresponding residues (if any) in Jalview
+ *
+ * @param structureSelection
+ * @return
+ */
+ protected List<AtomSpec> convertStructureResiduesToAlignment(
+ List<String> structureSelection)
+ {
List<AtomSpec> atomSpecs = new ArrayList<AtomSpec>();
- for (String atomSpec : selection)
+ for (String atomSpec : structureSelection)
{
- int colonPos = atomSpec.indexOf(":");
- if (colonPos == -1)
- {
- continue; // malformed
- }
-
- int hashPos = atomSpec.indexOf("#");
- String modelSubmodel = atomSpec.substring(hashPos + 1, colonPos);
- int dotPos = modelSubmodel.indexOf(".");
- int modelId = 0;
try
{
- modelId = Integer.valueOf(dotPos == -1 ? modelSubmodel
- : modelSubmodel.substring(0, dotPos));
- } catch (NumberFormatException e)
+ AtomSpec spec = AtomSpec.fromChimeraAtomspec(atomSpec);
+ String pdbfilename = getPdbFileForModel(spec.getModelNumber());
+ spec.setPdbFile(pdbfilename);
+ atomSpecs.add(spec);
+ } catch (IllegalArgumentException e)
{
- // ignore, default to model 0
+ System.err.println("Failed to parse atomspec: " + atomSpec);
}
+ }
+ return atomSpecs;
+ }
- String residueChain = atomSpec.substring(colonPos + 1);
- dotPos = residueChain.indexOf(".");
- int pdbResNum = Integer.parseInt(dotPos == -1 ? residueChain
- : residueChain.substring(0, dotPos));
-
- String chainId = dotPos == -1 ? "" : residueChain
- .substring(dotPos + 1);
-
- /*
- * Work out the pdbfilename from the model number
- */
- String pdbfilename = modelFileNames[frameNo];
- findfileloop: for (String pdbfile : this.chimeraMaps.keySet())
+ /**
+ * @param modelId
+ * @return
+ */
+ protected String getPdbFileForModel(int modelId)
+ {
+ /*
+ * Work out the pdbfilename from the model number
+ */
+ String pdbfilename = modelFileNames[0];
+ findfileloop: for (String pdbfile : this.chimeraMaps.keySet())
+ {
+ for (ChimeraModel cm : chimeraMaps.get(pdbfile))
{
- for (ChimeraModel cm : chimeraMaps.get(pdbfile))
+ if (cm.getModelNumber() == modelId)
{
- if (cm.getModelNumber() == modelId)
- {
- pdbfilename = pdbfile;
- break findfileloop;
- }
+ pdbfilename = pdbfile;
+ break findfileloop;
}
}
- atomSpecs.add(new AtomSpec(pdbfilename, chainId, pdbResNum, 0));
}
-
- /*
- * Broadcast the selection (which may be empty, if the user just cleared all
- * selections)
- */
- getSsm().mouseOverStructure(atomSpecs);
+ return pdbfilename;
}
private void log(String message)
}
/**
+ * Returns a list of chains mapped in this viewer. Note this list is not
+ * currently scoped per structure.
+ *
+ * @return
+ */
+ @Override
+ public List<String> getChainNames()
+ {
+ return chainNames;
+ }
+
+ /**
* Send a 'focus' command to Chimera to recentre the visible display
*/
public void focusView()
}
}
+ /**
+ * Constructs and send commands to Chimera to set attributes on residues for
+ * features visible in Jalview
+ *
+ * @param avp
+ * @return
+ */
+ public int sendFeaturesToViewer(AlignmentViewPanel avp)
+ {
+ // TODO refactor as required to pull up to an interface
+ AlignmentI alignment = avp.getAlignment();
+
+ String[] files = getStructureFiles();
+ if (files == null)
+ {
+ return 0;
+ }
+
+ StructureMappingcommandSet commandSet = ChimeraCommands
+ .getSetAttributeCommandsForFeatures(getSsm(), files,
+ getSequence(), avp);
+ String[] commands = commandSet.commands;
+ if (commands.length > 10)
+ {
+ sendCommandsByFile(commands);
+ }
+ else
+ {
+ for (String command : commands)
+ {
+ sendAsynchronousCommand(command, null);
+ }
+ }
+ return commands.length;
+ }
+
+ /**
+ * Write commands to a temporary file, and send a command to Chimera to open
+ * the file as a commands script. For use when sending a large number of
+ * separate commands would overload the REST interface mechanism.
+ *
+ * @param commands
+ */
+ protected void sendCommandsByFile(String[] commands)
+ {
+ try
+ {
+ File tmp = File.createTempFile("chim", ".com");
+ tmp.deleteOnExit();
+ PrintWriter out = new PrintWriter(new FileOutputStream(tmp));
+ for (String command : commands)
+ {
+ out.println(command);
+ }
+ out.flush();
+ out.close();
+ String path = tmp.getAbsolutePath();
+ sendAsynchronousCommand("open cmd:" + path, null);
+ } catch (IOException e)
+ {
+ System.err
+ .println("Sending commands to Chimera via file failed with "
+ + e.getMessage());
+ }
+ }
- @Override
- public List<String> getChainNames()
+ /**
+ * Get Chimera residues which have the named attribute, find the mapped
+ * positions in the Jalview sequence(s), and set as sequence features
+ *
+ * @param attName
+ * @param alignmentPanel
+ */
+ public void copyStructureAttributesToFeatures(String attName,
+ AlignmentViewPanel alignmentPanel)
{
- return chainNames;
+ // todo pull up to AAStructureBindingModel (and interface?)
+
+ /*
+ * ask Chimera to list residues with the attribute, reporting its value
+ */
+ // this alternative command
+ // list residues spec ':*/attName' attr attName
+ // doesn't report 'None' values (which is good), but
+ // fails for 'average.bfactor' (which is bad):
+
+ String cmd = "list residues attr '" + attName + "'";
+ List<String> residues = sendChimeraCommand(cmd, true);
+
+ boolean featureAdded = createFeaturesForAttributes(attName, residues);
+ if (featureAdded)
+ {
+ alignmentPanel.getFeatureRenderer().featuresAdded();
+ }
}
+ /**
+ * Create features in Jalview for the given attribute name and structure
+ * residues.
+ *
+ * <pre>
+ * The residue list should be 0, 1 or more reply lines of the format:
+ * residue id #0:5.A isHelix -155.000836316 index 5
+ * or
+ * residue id #0:6.A isHelix None
+ * </pre>
+ *
+ * @param attName
+ * @param residues
+ * @return
+ */
+ protected boolean createFeaturesForAttributes(String attName,
+ List<String> residues)
+ {
+ boolean featureAdded = false;
+ String featureGroup = getViewerFeatureGroup();
+
+ for (String residue : residues)
+ {
+ AtomSpec spec = null;
+ String[] tokens = residue.split(" ");
+ if (tokens.length < 5)
+ {
+ continue;
+ }
+ String atomSpec = tokens[2];
+ String attValue = tokens[4];
+
+ /*
+ * ignore 'None' (e.g. for phi) or 'False' (e.g. for isHelix)
+ */
+ if ("None".equalsIgnoreCase(attValue)
+ || "False".equalsIgnoreCase(attValue))
+ {
+ continue;
+ }
+
+ try
+ {
+ spec = AtomSpec.fromChimeraAtomspec(atomSpec);
+ } catch (IllegalArgumentException e)
+ {
+ System.err.println("Problem parsing atomspec " + atomSpec);
+ continue;
+ }
+
+ String chainId = spec.getChain();
+ String description = attValue;
+ float score = Float.NaN;
+ try
+ {
+ score = Float.valueOf(attValue);
+ description = chainId;
+ } catch (NumberFormatException e)
+ {
+ // was not a float value
+ }
+
+ String pdbFile = getPdbFileForModel(spec.getModelNumber());
+ spec.setPdbFile(pdbFile);
+
+ List<AtomSpec> atoms = Collections.singletonList(spec);
+
+ /*
+ * locate the mapped position in the alignment (if any)
+ */
+ SearchResultsI sr = getSsm()
+ .findAlignmentPositionsForStructurePositions(atoms);
+
+ /*
+ * expect one matched alignment position, or none
+ * (if the structure position is not mapped)
+ */
+ for (SearchResultMatchI m : sr.getResults())
+ {
+ SequenceI seq = m.getSequence();
+ int start = m.getStart();
+ int end = m.getEnd();
+ SequenceFeature sf = new SequenceFeature(attName, description,
+ start, end, score, featureGroup);
+ // todo: should SequenceFeature have an explicit property for chain?
+ // note: repeating the action shouldn't duplicate features
+ featureAdded |= seq.addSequenceFeature(sf);
+ }
+ }
+ return featureAdded;
+ }
+
+ /**
+ * Answers the feature group name to apply to features created in Jalview from
+ * Chimera attributes
+ *
+ * @return
+ */
+ protected String getViewerFeatureGroup()
+ {
+ // todo pull up to interface
+ return CHIMERA_FEATURE_GROUP;
+ }
+
+
public Hashtable<String, String> getChainFile()
{
return chainFile;
*/
package jalview.ext.varna;
-import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.structure.StructureMapping;
import jalview.structure.StructureSelectionManager;
*/
public static String[] getColourBySequenceCommand(
StructureSelectionManager ssm, String[] files,
- SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr,
+ SequenceI[][] sequence, SequenceRenderer sr,
+ FeatureColourFinder finder,
AlignmentI alignment)
{
ArrayList<String> str = new ArrayList<String>();
StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
if (mapping == null || mapping.length < 1)
+ {
continue;
+ }
int lastPos = -1;
for (int s = 0; s < sequence[pdbfnum].length; s++)
int pos = mapping[m].getPDBResNum(asp.findPosition(r));
if (pos < 1 || pos == lastPos)
+ {
continue;
+ }
lastPos = pos;
- Color col = sr.getResidueBoxColour(sequence[pdbfnum][s], r);
+ Color col = sr.getResidueColour(sequence[pdbfnum][s], r,
+ finder);
- if (fr != null)
- col = fr.findFeatureColour(col, sequence[pdbfnum][s], r);
String newSelcom = (mapping[m].getChain() != " " ? ":"
+ mapping[m].getChain() : "")
+ "/"
* @return
*/
public Map<String, Integer> getTempUserPrefs();
+
+ /**
+ * Returns unique key used for storing an FTSs instance cache items in the
+ * cache data structure
+ *
+ * @return
+ */
+ public String getCacheKey();
}
import jalview.gui.IProgressIndicator;
import jalview.gui.JvSwingUtils;
import jalview.gui.SequenceFetcher;
+import jalview.io.cache.JvCacheableInputBox;
import jalview.util.MessageManager;
import java.awt.BorderLayout;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
-import javax.swing.JTextField;
import javax.swing.Timer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.InternalFrameEvent;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
+import javax.swing.text.JTextComponent;
/**
* This class provides the swing GUI layout for FTS Panel and implements most of
protected JButton btn_cancel = new JButton();
- protected JTextField txt_search = new JTextField(30);
+ protected JvCacheableInputBox<String> txt_search;
protected SequenceFetcher seqFetcher;
protected HashSet<String> paginatorCart = new HashSet<String>();
+ private static final int MIN_WIDTH = 670;
+
+ private static final int MIN_HEIGHT = 300;
+
protected static final DecimalFormat totalNumberformatter = new DecimalFormat(
"###,###");
try
{
jbInit();
+ mainFrame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
mainFrame.addFocusListener(new FocusAdapter()
{
@Override
*/
private void jbInit() throws Exception
{
+
+ txt_search = new JvCacheableInputBox<String>(getCacheKey());
+ populateCmbSearchTargetOptions();
Integer width = getTempUserPrefs().get("FTSPanel.width") == null ? 800
: getTempUserPrefs().get("FTSPanel.width");
Integer height = getTempUserPrefs().get("FTSPanel.height") == null ? 400
scrl_searchResult.setPreferredSize(new Dimension(width, height));
cmb_searchTarget.setFont(new java.awt.Font("Verdana", 0, 12));
- cmb_searchTarget.addActionListener(new ActionListener()
+ cmb_searchTarget.addItemListener(new ItemListener()
{
@Override
- public void actionPerformed(ActionEvent e)
+ public void itemStateChanged(ItemEvent e)
{
- String tooltipText;
- if ("all".equalsIgnoreCase(getCmbSearchTarget().getSelectedItem()
- .toString()))
+ if (e.getStateChange() == ItemEvent.SELECTED)
{
- tooltipText = MessageManager.getString("label.search_all");
- }
- else if ("pdb id".equalsIgnoreCase(getCmbSearchTarget()
- .getSelectedItem().toString()))
- {
- tooltipText = MessageManager
- .getString("label.separate_multiple_accession_ids");
- }
- else
- {
- tooltipText = MessageManager.formatMessage(
- "label.separate_multiple_query_values",
- new Object[] { getCmbSearchTarget().getSelectedItem()
- .toString() });
+ String tooltipText;
+ if ("all".equalsIgnoreCase(getCmbSearchTarget().getSelectedItem()
+ .toString()))
+ {
+ tooltipText = MessageManager.getString("label.search_all");
+ }
+ else if ("pdb id".equalsIgnoreCase(getCmbSearchTarget()
+ .getSelectedItem().toString()))
+ {
+ tooltipText = MessageManager
+ .getString("label.separate_multiple_accession_ids");
+ }
+ else
+ {
+ tooltipText = MessageManager.formatMessage(
+ "label.separate_multiple_query_values",
+ new Object[] { getCmbSearchTarget().getSelectedItem()
+ .toString() });
+ }
+ txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
+ tooltipText));
+ searchAction(true);
}
- txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
- tooltipText));
- searchAction(true);
}
});
-
- populateCmbSearchTargetOptions();
+
txt_search.setFont(new java.awt.Font("Verdana", 0, 12));
- txt_search.addKeyListener(new KeyAdapter()
+ txt_search.getEditor().getEditorComponent()
+ .addKeyListener(new KeyAdapter()
{
@Override
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_ENTER)
{
- if (txt_search.getText() == null
- || txt_search.getText().isEmpty())
+ if (getTypedText() == null || getTypedText().isEmpty())
{
return;
}
if (primaryKeyName.equalsIgnoreCase(getCmbSearchTarget()
.getSelectedItem().toString()))
{
- transferToSequenceFetcher(txt_search.getText());
+ transferToSequenceFetcher(getTypedText());
}
}
}
});
-
final DeferredTextInputListener listener = new DeferredTextInputListener(
1500, new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
- if (!getTypedText().equalsIgnoreCase(lastSearchTerm))
+ String typed = getTypedText();
+ if (!typed.equalsIgnoreCase(lastSearchTerm))
{
searchAction(true);
paginatorCart.clear();
- lastSearchTerm = getTypedText();
+ lastSearchTerm = typed;
}
}
}, false);
- txt_search.getDocument().addDocumentListener(listener);
+ ((JTextComponent) txt_search.getEditor().getEditorComponent())
+ .getDocument().addDocumentListener(listener);
+
txt_search.addFocusListener(new FocusListener()
{
@Override
protected void closeAction()
{
- // System.out.println(">>>>>>>>>> closing internal frame!!!");
- // System.out.println("width : " + this.getWidth());
- // System.out.println("heigh : " + this.getHeight());
- // System.out.println("x : " + mainFrame.getX());
- // System.out.println("y : " + mainFrame.getY());
getTempUserPrefs().put("FTSPanel.width", this.getWidth());
getTempUserPrefs().put("FTSPanel.height", pnl_results.getHeight());
getTempUserPrefs().put("FTSPanel.x", mainFrame.getX());
getTempUserPrefs().put("FTSPanel.y", mainFrame.getY());
mainFrame.dispose();
+ txt_search.persistCache();
}
public class DeferredTextInputListener implements DocumentListener
{
if (previousWantedFields == null)
{
- return true;
+ return false;
}
return Arrays.equals(getFTSRestClient()
return cmb_searchTarget;
}
- public JTextField getTxtSearch()
+ public JComboBox<String> getTxtSearch()
{
return txt_search;
}
public void transferToSequenceFetcher(String ids)
{
- // mainFrame.dispose();
seqFetcher.getTextArea().setText(ids);
Thread worker = new Thread(seqFetcher);
worker.start();
@Override
public String getTypedText()
{
- return txt_search.getText().trim();
+ return txt_search.getUserInput();
}
@Override
{
lbl_blank.setVisible(!isSearchInProgress);
lbl_loading.setVisible(isSearchInProgress);
+ txt_search.setEditable(!isSearchInProgress);
}
@Override
.toString();
paginatorCart.add(idStr);
}
- // System.out.println("Paginator shopping cart size : "
- // + paginatorCart.size());
}
public void updateSummaryTableSelections()
{
e.printStackTrace();
}
- // System.out.println(">>>>>> got here : 1");
int totalRows = resultTable.getRowCount();
- // resultTable.clearSelection();
for (int row = 0; row < totalRows; row++)
{
String id = (String) resultTable.getValueAt(row, primaryKeyColIndex);
public void refreshPaginatorState()
{
- // System.out.println("resultSet count : " + resultSetCount);
- // System.out.println("offSet : " + offSet);
- // System.out.println("page limit : " + pageLimit);
setPrevPageButtonEnabled(false);
setNextPageButtonEnabled(false);
if (resultSetCount == 0 && pageLimit == 0)
mainFrame.setTitle(getFTSFrameTitle());
}
+
}
private static String defaultFTSFrameTitle = MessageManager
.getString("label.pdb_sequence_fetcher");
- private String ftsFrameTitle = defaultFTSFrameTitle;
private static Map<String, Integer> tempUserPrefs = new HashMap<String, Integer>();
+ private static final String PDB_FTS_CACHE_KEY = "CACHE.PDB_FTS";
+
public PDBFTSPanel(SequenceFetcher seqFetcher)
{
super();
@Override
public void searchAction(boolean isFreshSearch)
{
+ mainFrame.requestFocusInWindow();
if (isFreshSearch)
{
offSet = 0;
@Override
public void run()
{
- ftsFrameTitle = defaultFTSFrameTitle;
reset();
boolean allowEmptySequence = false;
if (getTypedText().length() > 0)
.getSelectedItem()).getCode();
wantedFields = PDBFTSRestClient.getInstance()
.getAllDefaultDisplayedFTSDataColumns();
- String searchTerm = decodeSearchTerm(txt_search.getText(),
+ String searchTerm = decodeSearchTerm(getTypedText(),
searchTarget);
FTSRestRequest request = new FTSRestRequest();
refreshPaginatorState();
updateSummaryTableSelections();
}
+ txt_search.updateCache();
}
}.start();
}
e.printStackTrace();
}
int[] selectedRows = getResultTable().getSelectedRows();
- String searchTerm = txt_search.getText();
+ String searchTerm = getTypedText();
for (int summaryRow : selectedRows)
{
String idStr = getResultTable().getValueAt(summaryRow,
@Override
public String getFTSFrameTitle()
{
- return ftsFrameTitle;
+ return defaultFTSFrameTitle;
}
@Override
return tempUserPrefs;
}
+
+ @Override
+ public String getCacheKey()
+ {
+ return PDB_FTS_CACHE_KEY;
+ }
+
+
}
if (foundDataRow != null && foundDataRow.length > 0)
{
result = new ArrayList<FTSData>();
- String titleRow = getDataColumnsFieldsAsTabDelimitedString(uniprotRestRequest
- .getWantedFields());
- // System.out.println(">>>>Title row : " + titleRow);
+ boolean firstRow = true;
for (String dataRow : foundDataRow)
{
- if (dataRow.equalsIgnoreCase(titleRow))
+ // The first data row is usually the header data. This should be
+ // filtered out from the rest of the data See: JAL-2485
+ if (firstRow)
{
- // System.out.println(">>>>>>>>>> matched!!!");
+ firstRow = false;
continue;
}
// System.out.println(dataRow);
private static String defaultFTSFrameTitle = MessageManager
.getString("label.uniprot_sequence_fetcher");
- private String ftsFrameTitle = defaultFTSFrameTitle;
private static Map<String, Integer> tempUserPrefs = new HashMap<String, Integer>();
+ private static final String UNIPROT_FTS_CACHE_KEY = "CACHE.UNIPROT_FTS";
+
public UniprotFTSPanel(SequenceFetcher seqFetcher)
{
super();
@Override
public void searchAction(boolean isFreshSearch)
{
+ mainFrame.requestFocusInWindow();
if (isFreshSearch)
{
offSet = 0;
@Override
public void run()
{
- ftsFrameTitle = defaultFTSFrameTitle;
reset();
- if (getTypedText().length() > 0)
+ String searchInput = getTypedText();
+ if (searchInput.length() > 0)
{
setSearchInProgress(true);
long startTime = System.currentTimeMillis();
-
+ searchInput = getTypedText();
String searchTarget = ((FTSDataColumnI) cmb_searchTarget
.getSelectedItem()).getAltCode();
-
wantedFields = UniProtFTSRestClient.getInstance()
.getAllDefaultDisplayedFTSDataColumns();
- String searchTerm = decodeSearchTerm(txt_search.getText(),
- searchTarget);
+ String searchTerm = decodeSearchTerm(searchInput, searchTarget);
FTSRestRequest request = new FTSRestRequest();
request.setFieldToSearchBy(searchTarget);
refreshPaginatorState();
updateSummaryTableSelections();
}
+ txt_search.updateCache();
}
}.start();
@Override
public String getFTSFrameTitle()
{
- return ftsFrameTitle;
+ return defaultFTSFrameTitle;
}
@Override
return tempUserPrefs;
}
+ @Override
+ public String getCacheKey()
+ {
+ return UNIPROT_FTS_CACHE_KEY;
+ }
}
--- /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.
+ */
+package jalview.gui;
+
+import jalview.datamodel.SequenceI;
+import jalview.renderer.AnnotationRenderer;
+import jalview.viewmodel.OverviewDimensions;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionAdapter;
+import java.awt.image.BufferedImage;
+
+import javax.swing.JPanel;
+
+/**
+ * Panel displaying an overview of the full alignment, with an interactive box
+ * representing the viewport onto the alignment.
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class OverviewPanel extends JPanel implements Runnable
+{
+ private static final Color TRANS_GREY = new Color(100, 100, 100, 25);
+
+ private final AnnotationRenderer renderer = new AnnotationRenderer();
+
+ private OverviewDimensions od;
+
+ private BufferedImage miniMe;
+
+ private BufferedImage lastMiniMe = null;
+
+ private AlignViewport av;
+
+ private AlignmentPanel ap;
+
+ //
+ private boolean resizing = false;
+
+ // This is set true if the user resizes whilst
+ // the overview is being calculated
+ private boolean resizeAgain = false;
+
+ // Can set different properties in this seqCanvas than
+ // main visible SeqCanvas
+ private SequenceRenderer sr;
+
+ private jalview.renderer.seqfeatures.FeatureRenderer fr;
+
+ /**
+ * Creates a new OverviewPanel object.
+ *
+ * @param alPanel
+ * The alignment panel which is shown in the overview panel
+ */
+ public OverviewPanel(AlignmentPanel alPanel)
+ {
+ this.av = alPanel.av;
+ this.ap = alPanel;
+ setLayout(null);
+
+ sr = new SequenceRenderer(av);
+ sr.renderGaps = false;
+ sr.forOverview = true;
+ fr = new FeatureRenderer(alPanel);
+
+ od = new OverviewDimensions(av.getRanges(), av.isShowAnnotation());
+
+ addComponentListener(new ComponentAdapter()
+ {
+ @Override
+ public void componentResized(ComponentEvent evt)
+ {
+ if ((getWidth() != od.getWidth())
+ || (getHeight() != (od.getHeight())))
+ {
+ updateOverviewImage();
+ }
+ }
+ });
+
+ addMouseMotionListener(new MouseMotionAdapter()
+ {
+ @Override
+ public void mouseDragged(MouseEvent evt)
+ {
+ if (!av.getWrapAlignment())
+ {
+ od.updateViewportFromMouse(evt.getX(), evt.getY(), av
+ .getAlignment().getHiddenSequences(), av
+ .getColumnSelection(), av.getRanges());
+ ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
+ }
+ }
+ });
+
+ addMouseListener(new MouseAdapter()
+ {
+ @Override
+ public void mousePressed(MouseEvent evt)
+ {
+ if (!av.getWrapAlignment())
+ {
+ od.updateViewportFromMouse(evt.getX(), evt.getY(), av
+ .getAlignment().getHiddenSequences(), av
+ .getColumnSelection(), av.getRanges());
+ ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
+ }
+ }
+ });
+
+ updateOverviewImage();
+ }
+
+ /**
+ * Updates the overview image when the related alignment panel is updated
+ */
+ public void updateOverviewImage()
+ {
+ if (resizing)
+ {
+ resizeAgain = true;
+ return;
+ }
+
+ resizing = true;
+
+ if ((getWidth() > 0) && (getHeight() > 0))
+ {
+ od.setWidth(getWidth());
+ od.setHeight(getHeight());
+ }
+
+ setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
+
+ Thread thread = new Thread(this);
+ thread.start();
+ repaint();
+ }
+
+ @Override
+ public void run()
+ {
+ miniMe = null;
+
+ if (av.isShowSequenceFeatures())
+ {
+ fr.transferSettings(ap.getSeqPanel().seqCanvas.getFeatureRenderer());
+ }
+
+ // why do we need to set preferred size again? was set in
+ // updateOverviewImage
+ setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
+
+ miniMe = new BufferedImage(od.getWidth(), od.getHeight(),
+ BufferedImage.TYPE_INT_RGB);
+
+ Graphics mg = miniMe.getGraphics();
+ mg.setColor(Color.orange);
+ mg.fillRect(0, 0, od.getWidth(), miniMe.getHeight());
+
+<<<<<<< HEAD
+ // calculate sampleCol and sampleRow
+ // alignment width is max number of residues/bases
+ // alignment height is number of sequences
+ int alwidth = av.getAlignment().getWidth();
+ int alheight = av.getAlignment().getAbsoluteHeight();
+
+ // sampleCol or sampleRow is the width/height allocated to each residue
+ // in particular, sometimes we may need more than one row/col of the
+ // BufferedImage allocated
+ // sampleCol is how much of a residue to assign to each pixel
+ // sampleRow is how many sequences to assign to each pixel
+ float sampleCol = alwidth / (float) od.getWidth();
+ float sampleRow = alheight / (float) od.getSequencesHeight();
+
+ buildImage(sampleRow, sampleCol);
+=======
+ float sampleCol = (float) alwidth / (float) width;
+ float sampleRow = (float) alheight / (float) sequencesHeight;
+
+ int lastcol = -1, lastrow = -1;
+ Color color = Color.white;
+ int row, col;
+ jalview.datamodel.SequenceI seq;
+ final boolean hasHiddenRows = av.hasHiddenRows(), hasHiddenCols = av
+ .hasHiddenColumns();
+ boolean hiddenRow = false;
+ // get hidden row and hidden column map once at beginning.
+ // clone featureRenderer settings to avoid race conditions... if state is
+ // updated just need to refresh again
+
+ FeatureColourFinder finder = new FeatureColourFinder(fr);
+
+ for (row = 0; row < sequencesHeight; row++)
+ {
+ if (resizeAgain)
+ {
+ break;
+ }
+ if ((int) (row * sampleRow) == lastrow)
+ {
+ // No need to recalculate the colours,
+ // Just copy from the row above
+ for (col = 0; col < width; col++)
+ {
+ if (resizeAgain)
+ {
+ break;
+ }
+ miniMe.setRGB(col, row, miniMe.getRGB(col, row - 1));
+ }
+ continue;
+ }
+
+ lastrow = (int) (row * sampleRow);
+
+ hiddenRow = false;
+ if (hasHiddenRows)
+ {
+ seq = av.getAlignment().getHiddenSequences()
+ .getHiddenSequence(lastrow);
+ if (seq == null)
+ {
+ int index = av.getAlignment().getHiddenSequences()
+ .findIndexWithoutHiddenSeqs(lastrow);
+
+ seq = av.getAlignment().getSequenceAt(index);
+ }
+ else
+ {
+ hiddenRow = true;
+ }
+ }
+ else
+ {
+ seq = av.getAlignment().getSequenceAt(lastrow);
+ }
+
+ if (seq == null)
+ {
+ System.out.println(lastrow + " null");
+ continue;
+ }
+
+ for (col = 0; col < width; col++)
+ {
+ if (resizeAgain)
+ {
+ break;
+ }
+ if ((int) (col * sampleCol) == lastcol
+ && (int) (row * sampleRow) == lastrow)
+ {
+ miniMe.setRGB(col, row, color.getRGB());
+ continue;
+ }
+
+ lastcol = (int) (col * sampleCol);
+
+ if (seq.getLength() > lastcol)
+ {
+ color = sr.getResidueColour(seq, lastcol, finder);
+ }
+ else
+ {
+ color = Color.WHITE;
+ }
+
+ if (hiddenRow
+ || (hasHiddenCols && !av.getColumnSelection().isVisible(
+ lastcol)))
+ {
+ color = color.darker().darker();
+ }
+
+ miniMe.setRGB(col, row, color.getRGB());
+>>>>>>> bug/JAL-2436featureRendererThreading
+
+ if (av.isShowAnnotation())
+ {
+ renderer.updateFromAlignViewport(av);
+ for (int col = 0; col < od.getWidth() && !resizeAgain; col++)
+ {
+ mg.translate(col, od.getSequencesHeight());
+ renderer.drawGraph(mg, av.getAlignmentConservationAnnotation(),
+ av.getAlignmentConservationAnnotation().annotations,
+ (int) (sampleCol) + 1, od.getGraphHeight(),
+ (int) (col * sampleCol), (int) (col * sampleCol) + 1);
+ mg.translate(-col, -od.getSequencesHeight());
+
+ }
+ }
+ System.gc();
+
+ resizing = false;
+
+ if (resizeAgain)
+ {
+ resizeAgain = false;
+ updateOverviewImage();
+ }
+ else
+ {
+ lastMiniMe = miniMe;
+ }
+
+ setBoxPosition();
+ }
+
+ /*
+ * Build the overview panel image
+ */
+ private void buildImage(float sampleRow, float sampleCol)
+ {
+ int lastcol = -1;
+ int lastrow = -1;
+ int color = Color.white.getRGB();
+
+ SequenceI seq = null;
+
+ final boolean hasHiddenCols = av.hasHiddenColumns();
+ boolean hiddenRow = false;
+ // get hidden row and hidden column map once at beginning.
+ // clone featureRenderer settings to avoid race conditions... if state is
+ // updated just need to refresh again
+ for (int row = 0; row < od.getSequencesHeight() && !resizeAgain; row++)
+ {
+ boolean doCopy = true;
+ int currentrow = (int) (row * sampleRow);
+ if (currentrow != lastrow)
+ {
+ doCopy = false;
+
+ lastrow = currentrow;
+
+ // get the sequence which would be at alignment index 'lastrow' if no
+ // rows were hidden, and determine whether it is hidden or not
+ hiddenRow = av.getAlignment().isHidden(lastrow);
+ seq = av.getAlignment().getSequenceAtAbsoluteIndex(lastrow);
+ }
+
+ for (int col = 0; col < od.getWidth() && !resizeAgain; col++)
+ {
+ if (doCopy)
+ {
+ color = miniMe.getRGB(col, row - 1);
+ }
+ else if ((int) (col * sampleCol) != lastcol
+ || (int) (row * sampleRow) != lastrow)
+ {
+ lastcol = (int) (col * sampleCol);
+ color = getColumnColourFromSequence(seq, hiddenRow, hasHiddenCols,
+ lastcol);
+ }
+ // else we just use the color we already have , so don't need to set it
+
+ miniMe.setRGB(col, row, color);
+ }
+ }
+ }
+
+ /*
+ * Find the colour of a sequence at a specified column position
+ */
+ private int getColumnColourFromSequence(jalview.datamodel.SequenceI seq,
+ boolean hiddenRow, boolean hasHiddenCols, int lastcol)
+ {
+ int color;
+
+ if (seq == null)
+ {
+ color = Color.white.getRGB();
+ }
+ else if (seq.getLength() > lastcol)
+ {
+ color = sr.getResidueBoxColour(seq, lastcol).getRGB();
+
+ if (av.isShowSequenceFeatures())
+ {
+ color = fr.findFeatureColour(color, seq, lastcol);
+ }
+ }
+ else
+ {
+ color = Color.white.getRGB();
+ }
+
+ if (hiddenRow
+ || (hasHiddenCols && !av.getColumnSelection()
+ .isVisible(lastcol)))
+ {
+ color = new Color(color).darker().darker().getRGB();
+ }
+
+ return color;
+ }
+
+ /**
+ * Update the overview panel box when the associated alignment panel is
+ * changed
+ *
+ */
+ public void setBoxPosition()
+ {
+ od.setBoxPosition(av.getAlignment()
+ .getHiddenSequences(), av.getColumnSelection(), av.getRanges());
+ repaint();
+ }
+
+
+ @Override
+ public void paintComponent(Graphics g)
+ {
+ if (resizing || resizeAgain)
+ {
+ if (lastMiniMe == null)
+ {
+ g.setColor(Color.white);
+ g.fillRect(0, 0, getWidth(), getHeight());
+ }
+ else
+ {
+ g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this);
+ }
+ g.setColor(TRANS_GREY);
+ g.fillRect(0, 0, getWidth(), getHeight());
+ }
+ else if (lastMiniMe != null)
+ {
+ g.drawImage(lastMiniMe, 0, 0, this);
+ if (lastMiniMe != miniMe)
+ {
+ g.setColor(TRANS_GREY);
+ g.fillRect(0, 0, getWidth(), getHeight());
+ }
+ }
+
+ g.setColor(Color.red);
+ od.drawBox(g);
+ }
+}
import jalview.api.FeatureSettingsControllerI;
import jalview.api.SplitContainerI;
import jalview.api.ViewStyleI;
-import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityParamsI;
import jalview.bin.Cache;
import jalview.bin.Jalview;
import jalview.commands.CommandI;
import jalview.datamodel.AlignmentOrder;
import jalview.datamodel.AlignmentView;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.HiddenSequences;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SeqCigar;
import jalview.io.FileFormatI;
import jalview.io.FileFormats;
import jalview.io.FileLoader;
+import jalview.io.FileParse;
import jalview.io.FormatAdapter;
import jalview.io.HtmlSvgOutput;
import jalview.io.IdentifyFile;
import jalview.io.JalviewFileView;
import jalview.io.JnetAnnotationMaker;
import jalview.io.NewickFile;
+import jalview.io.ScoreMatrixFile;
import jalview.io.TCoffeeScoreFile;
import jalview.jbgui.GAlignFrame;
import jalview.schemes.ColourSchemeI;
import jalview.schemes.ColourSchemes;
import jalview.schemes.ResidueColourScheme;
-import jalview.schemes.ResidueProperties;
import jalview.schemes.TCoffeeColourScheme;
import jalview.util.MessageManager;
import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
import jalview.ws.DBRefFetcher;
import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
import jalview.ws.jws1.Discoverer;
AlignViewport viewport;
+ ViewportRanges vpRanges;
+
public AlignViewControllerI avc;
List<AlignmentPanel> alignPanels = new ArrayList<AlignmentPanel>();
* @param height
* height of frame.
*/
- public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
+ public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns,
int width, int height)
{
this(al, hiddenColumns, width, height, null);
* @param sequenceSetId
* (may be null)
*/
- public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
+ public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns,
int width, int height, String sequenceSetId)
{
this(al, hiddenColumns, width, height, sequenceSetId, null);
* @param viewId
* (may be null)
*/
- public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
+ public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns,
int width, int height, String sequenceSetId, String viewId)
{
setSize(width, height);
}
public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs,
- ColumnSelection hiddenColumns, int width, int height)
+ HiddenColumns hiddenColumns, int width, int height)
{
setSize(width, height);
progressBar = new ProgressBar(this.statusPanel, this.statusBar);
}
+ vpRanges = viewport.getRanges();
avc = new jalview.controller.AlignViewController(this, viewport,
alignPanel);
if (viewport.getAlignmentConservationAnnotation() == null)
setMenusFromViewport(viewport);
buildSortByAnnotationScoresMenu();
- buildTreeMenu();
+ calculateTree.addActionListener(new ActionListener()
+ {
+
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ openTreePcaDialog();
+ }
+ });
buildColourMenu();
if (Desktop.desktop != null)
new String[] { (viewport.cursorMode ? "on" : "off") }));
if (viewport.cursorMode)
{
- alignPanel.getSeqPanel().seqCanvas.cursorX = viewport.startRes;
- alignPanel.getSeqPanel().seqCanvas.cursorY = viewport.startSeq;
+ alignPanel.getSeqPanel().seqCanvas.cursorX = vpRanges
+ .getStartRes();
+ alignPanel.getSeqPanel().seqCanvas.cursorY = vpRanges
+ .getStartSeq();
}
alignPanel.getSeqPanel().seqCanvas.repaint();
break;
case KeyEvent.VK_PAGE_UP:
if (viewport.getWrapAlignment())
{
- alignPanel.scrollUp(true);
+ vpRanges.scrollUp(true);
}
else
{
- alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
- - viewport.endSeq + viewport.startSeq);
+ vpRanges.pageUp();
}
break;
case KeyEvent.VK_PAGE_DOWN:
if (viewport.getWrapAlignment())
{
- alignPanel.scrollUp(false);
+ vpRanges.scrollUp(false);
}
else
{
- alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
- + viewport.endSeq - viewport.startSeq);
+ vpRanges.pageDown();
}
break;
}
exportData.getAlignment(), // class cast exceptions will
// occur in the distant future
exportData.getOmitHidden(), exportData.getStartEndPostions(),
- f.getCacheSuffixDefault(format),
- viewport.getColumnSelection());
+ f.getCacheSuffixDefault(format), viewport.getAlignment()
+ .getHiddenColumns());
if (output == null)
{
cap.setText(new FormatAdapter(alignPanel, exportData.getSettings())
.formatSequences(format, exportData.getAlignment(),
exportData.getOmitHidden(),
- exportData.getStartEndPostions(),
- viewport.getColumnSelection()));
+ exportData
+ .getStartEndPostions(), viewport
+ .getAlignment().getHiddenColumns()));
Desktop.addInternalFrame(cap, MessageManager.formatMessage(
"label.alignment_output_command",
new Object[] { e.getActionCommand() }), 600, 500);
alignmentToExport = viewport.getAlignment();
}
alignmentStartEnd = alignmentToExport
- .getVisibleStartAndEndIndex(viewport.getColumnSelection()
- .getHiddenColumns());
+ .getVisibleStartAndEndIndex(viewport.getAlignment()
+ .getHiddenColumns()
+ .getHiddenRegions());
AlignmentExportData ed = new AlignmentExportData(alignmentToExport,
omitHidden, alignmentStartEnd, settings);
return ed;
hiddenColumns = new ArrayList<int[]>();
int hiddenOffset = viewport.getSelectionGroup().getStartRes(), hiddenCutoff = viewport
.getSelectionGroup().getEndRes();
- for (int[] region : viewport.getColumnSelection().getHiddenColumns())
+ for (int[] region : viewport.getAlignment().getHiddenColumns()
+ .getHiddenRegions())
{
if (region[0] >= hiddenOffset && region[1] <= hiddenCutoff)
{
{
// propagate alignment changed.
- viewport.setEndSeq(alignment.getHeight());
+ vpRanges.setEndSeq(alignment.getHeight());
if (annotationAdded)
{
// Duplicate sequence annotation in all views.
{
trimRegion = new TrimRegionCommand("Remove Left", true, seqs,
column, viewport.getAlignment());
- viewport.setStartRes(0);
+ vpRanges.setStartRes(0);
}
else
{
// This is to maintain viewport position on first residue
// of first sequence
SequenceI seq = viewport.getAlignment().getSequenceAt(0);
- int startRes = seq.findPosition(viewport.startRes);
+ int startRes = seq.findPosition(vpRanges.getStartRes());
// ShiftList shifts;
// viewport.getAlignment().removeGaps(shifts=new ShiftList());
// edit.alColumnChanges=shifts.getInverse();
// if (viewport.hasHiddenColumns)
// viewport.getColumnSelection().compensateForEdits(shifts);
- viewport.setStartRes(seq.findIndex(startRes) - 1);
+ vpRanges.setStartRes(seq.findIndex(startRes) - 1);
viewport.firePropertyChange("alignment", null, viewport.getAlignment()
.getSequences());
// This is to maintain viewport position on first residue
// of first sequence
SequenceI seq = viewport.getAlignment().getSequenceAt(0);
- int startRes = seq.findPosition(viewport.startRes);
+ int startRes = seq.findPosition(vpRanges.getStartRes());
addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
viewport.getAlignment()));
- viewport.setStartRes(seq.findIndex(startRes) - 1);
+ vpRanges.setStartRes(seq.findIndex(startRes) - 1);
viewport.firePropertyChange("alignment", null, viewport.getAlignment()
.getSequences());
*/
newap.av.replaceMappings(viewport.getAlignment());
+ /*
+ * start up cDNA consensus (if applicable) now mappings are in place
+ */
+ if (newap.av.initComplementConsensus())
+ {
+ newap.refresh(true); // adjust layout of annotations
+ }
+
newap.av.viewName = getNewViewName(viewTitle);
addAlignmentPanel(newap, true);
frame.setContentPane(overview);
Desktop.addInternalFrame(frame, MessageManager.formatMessage(
"label.overview_params", new Object[] { this.getTitle() }),
- frame.getWidth(), frame.getHeight());
+ true, frame.getWidth(), frame.getHeight(), true, true);
frame.pack();
frame.setLayer(JLayeredPane.PALETTE_LAYER);
frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
*/
if (ResidueColourScheme.USER_DEFINED.equals(name))
{
- new UserDefinedColours(alignPanel, null);
+ new UserDefinedColours(alignPanel);
return;
}
public void changeColour(ColourSchemeI cs)
{
// TODO: pull up to controller method
- if (cs != null)
- {
- ColourMenuHelper.setColourSelected(colourMenu, cs.getSchemeName());
- }
+ ColourMenuHelper.setColourSelected(colourMenu, cs);
viewport.setGlobalColourScheme(cs);
{
SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
AlignmentSorter.sortByPID(viewport.getAlignment(), viewport
- .getAlignment().getSequenceAt(0), null);
+ .getAlignment().getSequenceAt(0));
addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
viewport.getAlignment()));
alignPanel.paintAlignment(true);
}
}
- /**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
- */
- @Override
- public void PCAMenuItem_actionPerformed(ActionEvent e)
- {
- if (((viewport.getSelectionGroup() != null)
- && (viewport.getSelectionGroup().getSize() < 4) && (viewport
- .getSelectionGroup().getSize() > 0))
- || (viewport.getAlignment().getHeight() < 4))
- {
- JvOptionPane
- .showInternalMessageDialog(
- this,
- MessageManager
- .getString("label.principal_component_analysis_must_take_least_four_input_sequences"),
- MessageManager
- .getString("label.sequence_selection_insufficient"),
- JvOptionPane.WARNING_MESSAGE);
-
- return;
- }
-
- new PCAPanel(alignPanel);
- }
-
@Override
public void autoCalculate_actionPerformed(ActionEvent e)
{
}
/**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
- */
- @Override
- public void averageDistanceTreeMenuItem_actionPerformed(ActionEvent e)
- {
- newTreePanel("AV", "PID", "Average distance tree using PID");
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
- */
- @Override
- public void neighbourTreeMenuItem_actionPerformed(ActionEvent e)
- {
- newTreePanel("NJ", "PID", "Neighbour joining tree using PID");
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
- */
- @Override
- protected void njTreeBlosumMenuItem_actionPerformed(ActionEvent e)
- {
- newTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
- */
- @Override
- protected void avTreeBlosumMenuItem_actionPerformed(ActionEvent e)
- {
- newTreePanel("AV", "BL", "Average distance tree using BLOSUM62");
- }
-
- /**
- * DOCUMENT ME!
+ * Constructs a tree panel and adds it to the desktop
*
* @param type
- * DOCUMENT ME!
- * @param pwType
- * DOCUMENT ME!
- * @param title
- * DOCUMENT ME!
+ * tree type (NJ or AV)
+ * @param modelName
+ * name of score model used to compute the tree
+ * @param options
+ * parameters for the distance or similarity calculation
*/
- void newTreePanel(String type, String pwType, String title)
+ void newTreePanel(String type, String modelName, SimilarityParamsI options)
{
+ String frameTitle = "";
TreePanel tp;
+ boolean onSelection = false;
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 */
return;
}
}
-
- title = title + " on region";
- tp = new TreePanel(alignPanel, type, pwType);
+ onSelection = true;
}
else
{
- // are the visible sequences aligned?
- if (!viewport.getAlignment().isAligned(false))
- {
- JvOptionPane
- .showMessageDialog(
- Desktop.desktop,
- MessageManager
- .getString("label.sequences_must_be_aligned_before_creating_tree"),
- MessageManager
- .getString("label.sequences_not_aligned"),
- JvOptionPane.WARNING_MESSAGE);
-
- return;
- }
-
if (viewport.getAlignment().getHeight() < 2)
{
return;
}
-
- tp = new TreePanel(alignPanel, type, pwType);
}
- title += " from ";
+ tp = new TreePanel(alignPanel, type, modelName, options);
+ frameTitle = tp.getPanelTitle() + (onSelection ? " on region" : "");
+
+ frameTitle += " from ";
if (viewport.viewName != null)
{
- title += viewport.viewName + " of ";
+ frameTitle += viewport.viewName + " of ";
}
- title += this.title;
+ frameTitle += this.title;
- Desktop.addInternalFrame(tp, title, 600, 500);
+ Desktop.addInternalFrame(tp, frameTitle, 600, 500);
}
/**
* call. Listeners are added to remove the menu item when the treePanel is
* closed, and adjust the tree leaf to sequence mapping when the alignment is
* modified.
- *
- * @param treePanel
- * Displayed tree window.
- * @param title
- * SortBy menu item title.
*/
@Override
- public void buildTreeMenu()
+ public void buildTreeSortMenu()
{
- calculateTree.removeAll();
- // build the calculate menu
-
- for (final String type : new String[] { "NJ", "AV" })
- {
- String treecalcnm = MessageManager.getString("label.tree_calc_"
- + type.toLowerCase());
- for (final String pwtype : ResidueProperties.scoreMatrices.keySet())
- {
- JMenuItem tm = new JMenuItem();
- ScoreModelI sm = ResidueProperties.scoreMatrices.get(pwtype);
- if (sm.isDNA() == viewport.getAlignment().isNucleotide()
- || sm.isProtein() == !viewport.getAlignment()
- .isNucleotide())
- {
- String smn = MessageManager.getStringOrReturn(
- "label.score_model_", sm.getName());
- final String title = MessageManager.formatMessage(
- "label.treecalc_title", treecalcnm, smn);
- tm.setText(title);//
- tm.addActionListener(new java.awt.event.ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- newTreePanel(type, pwtype, title);
- }
- });
- calculateTree.add(tm);
- }
-
- }
- }
sortByTreeMenu.removeAll();
List<Component> comps = PaintRefresher.components.get(viewport
if (value == JalviewFileChooser.APPROVE_OPTION)
{
- String choice = chooser.getSelectedFile().getPath();
- jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
- jalview.io.NewickFile fin = null;
+ String filePath = chooser.getSelectedFile().getPath();
+ Cache.setProperty("LAST_DIRECTORY", filePath);
+ NewickFile fin = null;
try
{
- fin = new NewickFile(choice, DataSourceType.FILE);
- viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());
+ fin = new NewickFile(filePath, DataSourceType.FILE);
+ viewport.setCurrentTree(showNewickTree(fin, filePath).getTree());
} catch (Exception ex)
{
JvOptionPane
}
}
- public TreePanel ShowNewickTree(NewickFile nf, String title)
+ public TreePanel showNewickTree(NewickFile nf, String treeTitle)
{
- return ShowNewickTree(nf, title, 600, 500, 4, 5);
+ return showNewickTree(nf, treeTitle, 600, 500, 4, 5);
}
- public TreePanel ShowNewickTree(NewickFile nf, String title,
- AlignmentView input)
- {
- return ShowNewickTree(nf, title, input, 600, 500, 4, 5);
- }
-
- public TreePanel ShowNewickTree(NewickFile nf, String title, int w,
+ public TreePanel showNewickTree(NewickFile nf, String treeTitle, int w,
int h, int x, int y)
{
- return ShowNewickTree(nf, title, null, w, h, x, y);
+ return showNewickTree(nf, treeTitle, null, w, h, x, y);
}
/**
- * Add a treeviewer for the tree extracted from a newick file object to the
+ * Add a treeviewer for the tree extracted from a Newick file object to the
* current alignment view
*
* @param nf
* position
* @return TreePanel handle
*/
- public TreePanel ShowNewickTree(NewickFile nf, String title,
+ public TreePanel showNewickTree(NewickFile nf, String treeTitle,
AlignmentView input, int w, int h, int x, int y)
{
TreePanel tp = null;
if (nf.getTree() != null)
{
- tp = new TreePanel(alignPanel, "FromFile", title, nf, input);
+ tp = new TreePanel(alignPanel, nf, treeTitle, input);
tp.setSize(w, h);
tp.setLocation(x, y);
}
- Desktop.addInternalFrame(tp, title, w, h);
+ Desktop.addInternalFrame(tp, treeTitle, w, h);
}
} catch (Exception ex)
{
}
/**
- * Attempt to load a "dropped" file or URL string: First by testing whether
- * it's an Annotation file, then a JNet file, and finally a features file. If
- * all are false then the user may have dropped an alignment file onto this
- * AlignFrame.
+ * Attempt to load a "dropped" file or URL string, by testing in turn for
+ * <ul>
+ * <li>an Annotation file</li>
+ * <li>a JNet file</li>
+ * <li>a features file</li>
+ * <li>else try to interpret as an alignment file</li>
+ * </ul>
*
* @param file
* either a filename or a URL string.
{
format = new IdentifyFile().identify(file, sourceType);
}
- if (FileFormat.Jnet.equals(format))
+ if (FileFormat.ScoreMatrix == format)
+ {
+ ScoreMatrixFile sm = new ScoreMatrixFile(new FileParse(file,
+ sourceType));
+ sm.parse();
+ // todo: i18n this message
+ statusBar
+ .setText(MessageManager.formatMessage(
+ "label.successfully_loaded_matrix",
+ sm.getMatrixName()));
+ }
+ else if (FileFormat.Jnet.equals(format))
{
JPredFile predictions = new JPredFile(file, sourceType);
new JnetAnnotationMaker();
viewport.getAlignment(), 0, false);
SequenceI repseq = viewport.getAlignment().getSequenceAt(0);
viewport.getAlignment().setSeqrep(repseq);
- ColumnSelection cs = new ColumnSelection();
+ HiddenColumns cs = new HiddenColumns();
cs.hideInsertionsFor(repseq);
- viewport.setColumnSelection(cs);
+ viewport.getAlignment().setHiddenColumns(cs);
isAnnotation = true;
}
// else if (IdentifyFile.FeaturesFile.equals(format))
colourMenu.add(annotationColour);
ColourSchemeI colourScheme = viewport.getGlobalColourScheme();
- String schemeName = colourScheme == null ? null : colourScheme
- .getSchemeName();
+ ColourMenuHelper.setColourSelected(colourMenu, colourScheme);
+ }
- ColourMenuHelper.setColourSelected(colourMenu, schemeName);
+ /**
+ * Open a dialog (if not already open) that allows the user to select and
+ * calculate PCA or Tree analysis
+ */
+ protected void openTreePcaDialog()
+ {
+ if (alignPanel.getCalculationDialog() == null)
+ {
+ new CalculationChooser(AlignFrame.this);
+ }
}
}
import jalview.analysis.AlignmentUtils;
import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
-import jalview.analysis.NJTree;
+import jalview.analysis.TreeModel;
import jalview.api.AlignViewportI;
import jalview.api.AlignmentViewPanel;
import jalview.api.FeatureColourI;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SearchResults;
import jalview.datamodel.SearchResultsI;
import jalview.schemes.ColourSchemeProperty;
import jalview.schemes.ResidueColourScheme;
import jalview.schemes.UserColourScheme;
-import jalview.structure.CommandListener;
import jalview.structure.SelectionSource;
import jalview.structure.StructureSelectionManager;
import jalview.structure.VamsasSource;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
+import java.awt.FontMetrics;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Hashtable;
* @version $Revision: 1.141 $
*/
public class AlignViewport extends AlignmentViewport implements
- SelectionSource, CommandListener
+ SelectionSource
{
Font font;
- NJTree currentTree = null;
+ TreeModel currentTree = null;
boolean cursorMode = false;
*/
public AlignViewport(AlignmentI al)
{
- setAlignment(al);
+ super(al);
init();
}
public AlignViewport(AlignmentI al, String seqsetid, String viewid)
{
+ super(al);
sequenceSetID = seqsetid;
viewId = viewid;
// TODO remove these once 2.4.VAMSAS release finished
{
Cache.log.debug("Setting viewport's view id : " + viewId);
}
- setAlignment(al);
init();
+
}
/**
* @param hiddenColumns
* ColumnSelection
*/
- public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns)
+ public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns)
{
- setAlignment(al);
+ super(al);
if (hiddenColumns != null)
{
- colSel = hiddenColumns;
+ al.setHiddenColumns(hiddenColumns);
}
init();
}
* @param seqsetid
* (may be null)
*/
- public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns,
+ public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns,
String seqsetid)
{
this(al, hiddenColumns, seqsetid, null);
* @param viewid
* (may be null)
*/
- public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns,
+ public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns,
String seqsetid, String viewid)
{
+ super(al);
sequenceSetID = seqsetid;
viewId = viewid;
// TODO remove these once 2.4.VAMSAS release finished
{
Cache.log.debug("Setting viewport's view id : " + viewId);
}
- setAlignment(al);
+
if (hiddenColumns != null)
{
- colSel = hiddenColumns;
+ al.setHiddenColumns(hiddenColumns);
}
init();
}
void init()
{
- this.startRes = 0;
- this.endRes = alignment.getWidth() - 1;
- this.startSeq = 0;
- this.endSeq = alignment.getHeight() - 1;
applyViewProperties();
String fontName = Cache.getDefault("FONT_NAME", "SansSerif");
false);
showGroupConsensus = Cache.getDefault("SHOW_GROUP_CONSENSUS", false);
showConsensus = Cache.getDefault("SHOW_IDENTITY", true);
+
+ showOccupancy = Cache.getDefault(Preferences.SHOW_OCCUPANCY, true);
}
initAutoAnnotation();
String colourProperty = alignment.isNucleotide() ? Preferences.DEFAULT_COLOUR_NUC
boolean validCharWidth;
/**
- * update view settings with the given font. You may need to call
- * alignPanel.fontChanged to update the layout geometry
- *
- * @param setGrid
- * when true, charWidth/height is set according to font mentrics
+ * {@inheritDoc}
*/
+ @Override
public void setFont(Font f, boolean setGrid)
{
font = f;
Container c = new Container();
- java.awt.FontMetrics fm = c.getFontMetrics(font);
- int w = viewStyle.getCharWidth(), ww = fm.charWidth('M'), h = viewStyle
- .getCharHeight();
if (setGrid)
{
+ FontMetrics fm = c.getFontMetrics(font);
+ int ww = fm.charWidth('M');
setCharHeight(fm.getHeight());
setCharWidth(ww);
}
* @param tree
* DOCUMENT ME!
*/
- public void setCurrentTree(NJTree tree)
+ public void setCurrentTree(TreeModel tree)
{
currentTree = tree;
}
*
* @return DOCUMENT ME!
*/
- public NJTree getCurrentTree()
+ public TreeModel getCurrentTree()
{
return currentTree;
}
{
end = alignment.getWidth();
}
- viscontigs = colSel.getVisibleContigs(start, end);
+ viscontigs = alignment.getHiddenColumns().getVisibleContigs(start, end);
return viscontigs;
}
jalview.structure.StructureSelectionManager
.getStructureSelectionManager(Desktop.instance).sendSelection(
new SequenceGroup(getSelectionGroup()),
- new ColumnSelection(getColumnSelection()), this);
+ new ColumnSelection(getColumnSelection()),
+ new HiddenColumns(getAlignment().getHiddenColumns()),
+ this);
}
/**
}
}
- setEndSeq(getAlignment().getHeight());
+ ranges.setEndSeq(getAlignment().getHeight());
firePropertyChange("alignment", null, getAlignment().getSequences());
}
// TODO would like next line without cast but needs more refactoring...
final AlignmentPanel complementPanel = ((AlignViewport) getCodingComplement())
.getAlignPanel();
- complementPanel.setDontScrollComplement(true);
+ complementPanel.setToScrollComplementPanel(false);
complementPanel.scrollToCentre(sr, verticalOffset);
+ complementPanel.setToScrollComplementPanel(true);
}
}
import jalview.api.AlignmentViewPanel;
import jalview.bin.Cache;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceGroup;
import jalview.structure.StructureSelectionManager;
import jalview.util.MessageManager;
import jalview.util.Platform;
+import jalview.viewmodel.ViewportListenerI;
+import jalview.viewmodel.ViewportRanges;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Insets;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
* @version $Revision: 1.161 $
*/
public class AlignmentPanel extends GAlignmentPanel implements
- AdjustmentListener, Printable, AlignmentViewPanel
+ AdjustmentListener, Printable, AlignmentViewPanel,
+ ViewportListenerI
{
public AlignViewport av;
+ ViewportRanges vpRanges;
+
OverviewPanel overviewPanel;
private SeqPanel seqPanel;
// this value is set false when selection area being dragged
boolean fastPaint = true;
- int hextent = 0;
+ private int hextent = 0;
- int vextent = 0;
+ private int vextent = 0;
/*
* Flag set while scrolling to follow complementary cDNA/protein scroll. When
- * true, suppresses invoking the same method recursively.
+ * false, suppresses invoking the same method recursively.
*/
- private boolean dontScrollComplement;
+ private boolean scrollComplementaryPanel = true;
private PropertyChangeListener propertyChangeListener;
+ private CalculationChooser calculationDialog;
+
/**
* Creates a new AlignmentPanel object.
*
{
alignFrame = af;
this.av = av;
+ vpRanges = av.getRanges();
setSeqPanel(new SeqPanel(av, this));
setIdPanel(new IdPanel(av, this));
hscroll.addAdjustmentListener(this);
vscroll.addAdjustmentListener(this);
+ addComponentListener(new ComponentAdapter()
+ {
+ @Override
+ public void componentResized(ComponentEvent evt)
+ {
+ // reset the viewport ranges when the alignment panel is resized
+ // in particular, this initialises the end residue value when Jalview
+ // is initialised
+ if (av.getWrapAlignment())
+ {
+ int widthInRes = getSeqPanel().seqCanvas
+ .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
+ vpRanges.setViewportWidth(widthInRes);
+ }
+ else
+ {
+ int widthInRes = getSeqPanel().seqCanvas.getWidth()
+ / av.getCharWidth();
+ int heightInSeq = getSeqPanel().seqCanvas.getHeight()
+ / av.getCharHeight();
+
+ vpRanges.setViewportWidth(widthInRes);
+ vpRanges.setViewportHeight(heightInSeq);
+ }
+ }
+
+ });
+
final AlignmentPanel ap = this;
propertyChangeListener = new PropertyChangeListener()
{
}
};
av.addPropertyChangeListener(propertyChangeListener);
+
+ av.getRanges().addPropertyChangeListener(this);
fontChanged();
adjustAnnotationHeight();
updateLayout();
{
av.alignmentChanged(this);
+ if (getCalculationDialog() != null)
+ {
+ getCalculationDialog().validateCalcTypes();
+ }
+
alignFrame.updateEditMenuBar();
paintAlignment(true);
getIdPanel().getIdCanvas().setPreferredSize(d);
hscrollFillerPanel.setPreferredSize(d);
- if (overviewPanel != null)
- {
- overviewPanel.setBoxPosition();
- }
if (this.alignFrame.getSplitViewContainer() != null)
{
((SplitFrame) this.alignFrame.getSplitViewContainer()).adjustLayout();
}
int start = r[0];
int end = r[1];
- // DEBUG
- // System.err.println(this.av.viewName + " Seq : " + seqIndex
- // + " Scroll to " + start + "," + end);
/*
* To centre results, scroll to positions half the visible width
*/
if (centre)
{
- int offset = (av.getEndRes() - av.getStartRes() + 1) / 2 - 1;
+ int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2
+ - 1;
start = Math.max(start - offset, 0);
end = end + offset - 1;
}
}
if (av.hasHiddenColumns())
{
- start = av.getColumnSelection().findColumnPosition(start);
- end = av.getColumnSelection().findColumnPosition(end);
+ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+ start = hidden.findColumnPosition(start);
+ end = hidden.findColumnPosition(end);
if (start == end)
{
- if (!av.getColumnSelection().isVisible(r[0]))
+ if (!hidden.isVisible(r[0]))
{
// don't scroll - position isn't visible
return false;
*/
seqIndex = Math.max(0, seqIndex - verticalOffset);
- // System.out.println("start=" + start + ", end=" + end + ", startv="
- // + av.getStartRes() + ", endv=" + av.getEndRes() + ", starts="
- // + av.getStartSeq() + ", ends=" + av.getEndSeq());
if (!av.getWrapAlignment())
{
- if ((startv = av.getStartRes()) >= start)
+ if ((startv = vpRanges.getStartRes()) >= start)
{
/*
* Scroll left to make start of search results visible
*/
- // setScrollValues(start - 1, seqIndex); // plus one residue
setScrollValues(start, seqIndex);
}
- else if ((endv = av.getEndRes()) <= end)
+ else if ((endv = vpRanges.getEndRes()) <= end)
{
/*
* Scroll right to make end of search results visible
*/
- // setScrollValues(startv + 1 + end - endv, seqIndex); // plus one
setScrollValues(startv + end - endv, seqIndex);
}
- else if ((starts = av.getStartSeq()) > seqIndex)
+ else if ((starts = vpRanges.getStartSeq()) > seqIndex)
{
/*
* Scroll up to make start of search results visible
*/
- setScrollValues(av.getStartRes(), seqIndex);
+ setScrollValues(vpRanges.getStartRes(), seqIndex);
}
- else if ((ends = av.getEndSeq()) <= seqIndex)
+ else if ((ends = vpRanges.getEndSeq()) <= seqIndex)
{
/*
* Scroll down to make end of search results visible
*/
- setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1);
+ setScrollValues(vpRanges.getStartRes(), starts + seqIndex - ends
+ + 1);
}
/*
* Else results are already visible - no need to scroll
}
else
{
- scrollToWrappedVisible(start);
+ vpRanges.scrollToWrappedVisible(start);
}
}
- if (redrawOverview && overviewPanel != null)
- {
- overviewPanel.setBoxPosition();
- }
+
paintAlignment(redrawOverview);
return true;
}
- void scrollToWrappedVisible(int res)
- {
- int cwidth = getSeqPanel().seqCanvas
- .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
- if (res < av.getStartRes() || res >= (av.getStartRes() + cwidth))
- {
- vscroll.setValue((res / cwidth));
- av.startRes = vscroll.getValue() * cwidth;
- }
-
- }
-
/**
* DOCUMENT ME!
*
fontChanged();
setAnnotationVisible(av.isShowAnnotation());
boolean wrap = av.getWrapAlignment();
- av.startSeq = 0;
+ vpRanges.setStartSeq(0);
scalePanelHolder.setVisible(!wrap);
hscroll.setVisible(!wrap);
idwidthAdjuster.setVisible(!wrap);
annotationSpaceFillerHolder.setVisible(true);
}
- idSpaceFillerPanel1.setVisible(!wrap);
-
- repaint();
- }
-
- // return value is true if the scroll is valid
- public boolean scrollUp(boolean up)
- {
- if (up)
+ if (wrap)
{
- if (vscroll.getValue() < 1)
- {
- return false;
- }
-
- fastPaint = false;
- vscroll.setValue(vscroll.getValue() - 1);
+ int widthInRes = getSeqPanel().seqCanvas
+ .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
+ vpRanges.setViewportWidth(widthInRes);
}
else
{
- if ((vextent + vscroll.getValue()) >= av.getAlignment().getHeight())
- {
- return false;
- }
+ int widthInRes = (getSeqPanel().seqCanvas.getWidth() / av
+ .getCharWidth()) - 1;
+ int heightInSeq = (getSeqPanel().seqCanvas.getHeight() / av
+ .getCharHeight()) - 1;
- fastPaint = false;
- vscroll.setValue(vscroll.getValue() + 1);
+ vpRanges.setViewportWidth(widthInRes);
+ vpRanges.setViewportHeight(heightInSeq);
}
- fastPaint = true;
+ idSpaceFillerPanel1.setVisible(!wrap);
- return true;
+ repaint();
}
- /**
- * DOCUMENT ME!
- *
- * @param right
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public boolean scrollRight(boolean right)
- {
- if (!right)
- {
- if (hscroll.getValue() < 1)
- {
- return false;
- }
-
- fastPaint = false;
- hscroll.setValue(hscroll.getValue() - 1);
- }
- else
- {
- if ((hextent + hscroll.getValue()) >= av.getAlignment().getWidth())
- {
- return false;
- }
-
- fastPaint = false;
- hscroll.setValue(hscroll.getValue() + 1);
- }
-
- fastPaint = true;
-
- return true;
- }
/**
* Adjust row/column scrollers to show a visible position in the alignment.
* visible row to scroll to
*
*/
- public void setScrollValues(int x, int y)
+ public void setScrollValues(int xpos, int ypos)
{
- // System.err.println("Scroll " + this.av.viewName + " to " + x + "," + y);
+ int x = xpos;
+ int y = ypos;
+
if (av == null || av.getAlignment() == null)
{
return;
}
- int width = av.getAlignment().getWidth();
- int height = av.getAlignment().getHeight();
- if (av.hasHiddenColumns())
+ if (av.getWrapAlignment())
{
- width = av.getColumnSelection().findColumnPosition(width);
+ setScrollingForWrappedPanel(x);
}
+ else
+ {
+ int width = av.getAlignment().getWidth();
+ int height = av.getAlignment().getHeight();
- av.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
- .getCharWidth())) - 1);
+ if (av.hasHiddenColumns())
+ {
+ // reset the width to exclude hidden columns
+ width = av.getAlignment().getHiddenColumns().findColumnPosition(width);
+ }
- hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
- vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight();
+ hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
+ vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight();
- if (hextent > width)
- {
- hextent = width;
- }
+ if (hextent > width)
+ {
+ hextent = width;
+ }
- if (vextent > height)
- {
- vextent = height;
- }
+ if (vextent > height)
+ {
+ vextent = height;
+ }
- if ((hextent + x) > width)
- {
- x = width - hextent;
- }
+ if ((hextent + x) > width)
+ {
+ x = width - hextent;
+ }
- if ((vextent + y) > height)
- {
- y = height - vextent;
- }
+ if ((vextent + y) > height)
+ {
+ y = height - vextent;
+ }
- if (y < 0)
- {
- y = 0;
- }
+ if (y < 0)
+ {
+ y = 0;
+ }
- if (x < 0)
- {
- x = 0;
- }
+ if (x < 0)
+ {
+ x = 0;
+ }
- /*
- * each scroll adjustment triggers adjustmentValueChanged, which resets the
- * 'do not scroll complement' flag; ensure it is the same for both
- * operations
- */
- boolean flag = isDontScrollComplement();
- hscroll.setValues(x, hextent, 0, width);
- setDontScrollComplement(flag);
- vscroll.setValues(y, vextent, 0, height);
+ // update the scroll values
+ hscroll.setValues(x, hextent, 0, width);
+ vscroll.setValues(y, vextent, 0, height);
+ }
}
/**
- * DOCUMENT ME!
+ * Respond to adjustment event when horizontal or vertical scrollbar is
+ * changed
*
* @param evt
- * DOCUMENT ME!
+ * adjustment event encoding whether hscroll or vscroll changed
*/
@Override
public void adjustmentValueChanged(AdjustmentEvent evt)
{
- int oldX = av.getStartRes();
- int oldY = av.getStartSeq();
-
- if (evt.getSource() == hscroll)
- {
- int x = hscroll.getValue();
- av.setStartRes(x);
- av.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
- .getCharWidth())) - 1);
- }
+ int oldX = vpRanges.getStartRes();
+ int oldwidth = vpRanges.getViewportWidth();
+ int oldY = vpRanges.getStartSeq();
+ int oldheight = vpRanges.getViewportHeight();
- if (evt.getSource() == vscroll)
+ if (av.getWrapAlignment())
{
- int offy = vscroll.getValue();
-
- if (av.getWrapAlignment())
+ if (evt.getSource() == hscroll)
+ {
+ return; // no horizontal scroll when wrapped
+ }
+ else if (evt.getSource() == vscroll)
{
- if (offy > -1)
+ int offy = vscroll.getValue();
+ int rowSize = getSeqPanel().seqCanvas
+ .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
+
+ // if we're scrolling to the position we're already at, stop
+ // this prevents infinite recursion of events when the scroll/viewport
+ // ranges values are the same
+ if ((offy * rowSize == oldX) && (oldwidth == rowSize))
{
- int rowSize = getSeqPanel().seqCanvas
- .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
- av.setStartRes(offy * rowSize);
- av.setEndRes((offy + 1) * rowSize);
+ return;
}
- else
+ else if (offy > -1)
{
- // This is only called if file loaded is a jar file that
- // was wrapped when saved and user has wrap alignment true
- // as preference setting
- SwingUtilities.invokeLater(new Runnable()
- {
- @Override
- public void run()
- {
- setScrollValues(av.getStartRes(), av.getStartSeq());
- }
- });
+ vpRanges.setViewportStartAndWidth(offy * rowSize, rowSize);
}
}
else
{
- av.setStartSeq(offy);
- av.setEndSeq(offy
- + (getSeqPanel().seqCanvas.getHeight() / av.getCharHeight()));
+ // This is only called if file loaded is a jar file that
+ // was wrapped when saved and user has wrap alignment true
+ // as preference setting
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ // When updating scrolling to use ViewportChange events, this code
+ // could not be validated and it is not clear if it is now being
+ // called. Log warning here in case it is called and unforeseen
+ // problems occur
+ Cache.log
+ .warn("Unexpected path through code: Wrapped jar file opened with wrap alignment set in preferences");
+
+ // scroll to start of panel
+ vpRanges.setStartRes(0);
+ vpRanges.setStartSeq(0);
+ }
+ });
}
- }
-
- if (overviewPanel != null)
- {
- overviewPanel.setBoxPosition();
- }
-
- int scrollX = av.startRes - oldX;
- int scrollY = av.startSeq - oldY;
-
- if (av.getWrapAlignment() || !fastPaint)
- {
repaint();
}
else
{
- // Make sure we're not trying to draw a panel
- // larger than the visible window
- if (scrollX > av.endRes - av.startRes)
- {
- scrollX = av.endRes - av.startRes;
- }
- else if (scrollX < av.startRes - av.endRes)
+ // horizontal scroll
+ if (evt.getSource() == hscroll)
{
- scrollX = av.startRes - av.endRes;
- }
+ int x = hscroll.getValue();
+ int width = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
- if (scrollX != 0 || scrollY != 0)
+ // if we're scrolling to the position we're already at, stop
+ // this prevents infinite recursion of events when the scroll/viewport
+ // ranges values are the same
+ if ((x == oldX) && (width == oldwidth))
+ {
+ return;
+ }
+ vpRanges.setViewportStartAndWidth(x, width);
+ }
+ else if (evt.getSource() == vscroll)
{
- getIdPanel().getIdCanvas().fastPaint(scrollY);
- getSeqPanel().seqCanvas.fastPaint(scrollX, scrollY);
- getScalePanel().repaint();
-
- if (av.isShowAnnotation() && scrollX != 0)
+ int y = vscroll.getValue();
+ int height = getSeqPanel().seqCanvas.getHeight()
+ / av.getCharHeight();
+
+ // if we're scrolling to the position we're already at, stop
+ // this prevents infinite recursion of events when the scroll/viewport
+ // ranges values are the same
+ if ((y == oldY) && (height == oldheight))
{
- getAnnotationPanel().fastPaint(scrollX);
+ return;
}
+ vpRanges.setViewportStartAndHeight(y, height);
+ }
+ if (!fastPaint)
+ {
+ repaint();
}
- }
- /*
- * If there is one, scroll the (Protein/cDNA) complementary alignment to
- * match, unless we are ourselves doing that.
- */
- if (isDontScrollComplement())
- {
- setDontScrollComplement(false);
- }
- else
- {
- av.scrollComplementaryAlignment();
}
}
validate();
/*
- * set scroll bar positions; first suppress this being 'followed' in any
- * complementary split pane
+ * set scroll bar positions
*/
- setDontScrollComplement(true);
+ setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
+ }
- if (av.getWrapAlignment())
+ /*
+ * Set vertical scroll bar parameters for wrapped panel
+ * @param res
+ * the residue to scroll to
+ */
+ private void setScrollingForWrappedPanel(int res)
+ {
+ // get the width of the alignment in residues
+ int maxwidth = av.getAlignment().getWidth();
+ if (av.hasHiddenColumns())
{
- int maxwidth = av.getAlignment().getWidth();
-
- if (av.hasHiddenColumns())
- {
- maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
- }
-
- int canvasWidth = getSeqPanel().seqCanvas
- .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
- if (canvasWidth > 0)
- {
- int max = maxwidth
- / getSeqPanel().seqCanvas
- .getWrappedCanvasWidth(getSeqPanel().seqCanvas
- .getWidth()) + 1;
- vscroll.setMaximum(max);
- vscroll.setUnitIncrement(1);
- vscroll.setVisibleAmount(1);
- }
+ maxwidth = av.getAlignment().getHiddenColumns()
+ .findColumnPosition(maxwidth) - 1;
}
- else
+
+ // get the width of the canvas in residues
+ int canvasWidth = getSeqPanel().seqCanvas
+ .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
+ if (canvasWidth > 0)
{
- setScrollValues(av.getStartRes(), av.getStartSeq());
+ // position we want to scroll to is number of canvasWidth's to get there
+ int current = res / canvasWidth;
+
+ // max scroll position: add one because extent is 1 and scrollbar value
+ // can only be set to at most max - extent
+ int max = maxwidth / canvasWidth + 1;
+ vscroll.setUnitIncrement(1);
+ vscroll.setValues(current, 1, 0, max);
}
}
int maxwidth = av.getAlignment().getWidth();
if (av.hasHiddenColumns())
{
- maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+ maxwidth = av.getAlignment().getHiddenColumns()
+ .findColumnPosition(maxwidth) - 1;
}
int resWidth = getSeqPanel().seqCanvas.getWrappedCanvasWidth(pwidth
int maxwidth = av.getAlignment().getWidth();
if (av.hasHiddenColumns())
{
- maxwidth = av.getColumnSelection().findColumnPosition(maxwidth);
+ maxwidth = av.getAlignment().getHiddenColumns()
+ .findColumnPosition(maxwidth);
}
int height = ((av.getAlignment().getHeight() + 1) * av.getCharHeight())
int maxwidth = av.getAlignment().getWidth();
if (av.hasHiddenColumns())
{
- maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+ maxwidth = av.getAlignment().getHiddenColumns()
+ .findColumnPosition(maxwidth) - 1;
}
int height = ((maxwidth / chunkWidth) + 1) * cHeight;
PaintRefresher.RemoveComponent(getIdPanel().getIdCanvas());
PaintRefresher.RemoveComponent(this);
+ closeChildFrames();
+
/*
* try to ensure references are nulled
*/
}
/**
+ * Close any open dialogs that would be orphaned when this one is closed
+ */
+ protected void closeChildFrames()
+ {
+ if (calculationDialog != null)
+ {
+ calculationDialog.closeFrame();
+ }
+ }
+
+ /**
* hides or shows dynamic annotation rows based on groups and av state flags
*/
public void updateAnnotation()
*
* @param b
*/
- protected void setDontScrollComplement(boolean b)
+ protected void setToScrollComplementPanel(boolean b)
{
- this.dontScrollComplement = b;
+ this.scrollComplementaryPanel = b;
}
- protected boolean isDontScrollComplement()
+ /**
+ * Get whether to scroll complement panel
+ *
+ * @return true if cDNA/protein complement panels should be scrolled
+ */
+ protected boolean isSetToScrollComplementPanel()
+ {
+ return this.scrollComplementaryPanel;
+ }
+
+ /**
+ * Redraw sensibly.
+ *
+ * @adjustHeight if true, try to recalculate panel height for visible
+ * annotations
+ */
+ protected void refresh(boolean adjustHeight)
+ {
+ validateAnnotationDimensions(adjustHeight);
+ addNotify();
+ if (adjustHeight)
+ {
+ // sort, repaint, update overview
+ paintAlignment(true);
+ }
+ else
+ {
+ // lightweight repaint
+ repaint();
+ }
+ }
+
+ @Override
+ /**
+ * Property change event fired when a change is made to the viewport ranges
+ * object associated with this alignment panel's viewport
+ */
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ // update this panel's scroll values based on the new viewport ranges values
+ int x = vpRanges.getStartRes();
+ int y = vpRanges.getStartSeq();
+ setScrollValues(x, y);
+
+ // now update any complementary alignment (its viewport ranges object
+ // is different so does not get automatically updated)
+ if (isSetToScrollComplementPanel())
+ {
+ setToScrollComplementPanel(false);
+ av.scrollComplementaryAlignment();
+ setToScrollComplementPanel(true);
+ }
+ }
+
+ /**
+ * Set the reference to the PCA/Tree chooser dialog for this panel. This
+ * reference should be nulled when the dialog is closed.
+ *
+ * @param calculationChooser
+ */
+ public void setCalculationDialog(CalculationChooser calculationChooser)
+ {
+ calculationDialog = calculationChooser;
+ }
+
+ /**
+ * Returns the reference to the PCA/Tree chooser dialog for this panel (null
+ * if none is open)
+ */
+ public CalculationChooser getCalculationDialog()
{
- return this.dontScrollComplement;
+ return calculationDialog;
}
}
package jalview.gui;
import jalview.bin.Cache;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.GraphLine;
import jalview.datamodel.SequenceGroup;
import jalview.schemes.AnnotationColourGradient;
import jalview.schemes.ColourSchemeI;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Hashtable;
+import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.JButton;
+import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JInternalFrame;
@SuppressWarnings("serial")
public class AnnotationColourChooser extends AnnotationRowFilter
{
+ private static final int ONETHOUSAND = 1000;
- ColourSchemeI oldcs;
+ private ColourSchemeI oldcs;
- Hashtable<SequenceGroup, ColourSchemeI> oldgroupColours;
+ private JButton defColours;
- /**
- * enabled if the user is dragging the slider - try to keep updates to a
- * minimun
- */
+ private Hashtable<SequenceGroup, ColourSchemeI> oldgroupColours;
- JComboBox<String> annotations;
+ private JCheckBox useOriginalColours = new JCheckBox();
- JButton defColours = new JButton();
+ private JPanel minColour = new JPanel();
- JPanel jPanel1 = new JPanel();
+ private JPanel maxColour = new JPanel();
- JPanel jPanel2 = new JPanel();
+ private JCheckBox thresholdIsMin = new JCheckBox();
- BorderLayout borderLayout1 = new BorderLayout();
+ protected static final int MIN_WIDTH = 500;
- private JComboBox<String> threshold = new JComboBox<String>();
+ protected static final int MIN_HEIGHT = 240;
public AnnotationColourChooser(AlignViewport av, final AlignmentPanel ap)
{
Desktop.addInternalFrame(frame,
MessageManager.getString("label.colour_by_annotation"), 520,
215);
-
+ frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
addSliderChangeListener();
addSliderMouseListeners();
if (oldcs instanceof AnnotationColourGradient)
{
AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
- currentColours.setSelected(acg.isPredefinedColours()
+ useOriginalColours.setSelected(acg.isPredefinedColours()
|| acg.getBaseColour() != null);
if (!acg.isPredefinedColours() && acg.getBaseColour() == null)
{
seqAssociated.setSelected(acg.isSeqAssociated());
}
- annotations = new JComboBox<String>(
- getAnnotationItems(seqAssociated.isSelected()));
+ Vector<String> annotItems = getAnnotationItems(seqAssociated
+ .isSelected());
+ annotations = new JComboBox<String>(annotItems);
populateThresholdComboBox(threshold);
if (oldcs instanceof AnnotationColourGradient)
{
AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
- annotations.setSelectedItem(acg.getAnnotation());
+ String label = getAnnotationMenuLabel(acg.getAnnotation());
+ annotations.setSelectedItem(label);
switch (acg.getAboveThreshold())
{
case AnnotationColourGradient.NO_THRESHOLD:
MessageManager
.getString("error.implementation_error_dont_know_about_threshold_setting"));
}
- thresholdIsMin.setSelected(acg.thresholdIsMinMax);
+ thresholdIsMin.setSelected(acg.isThresholdIsMinMax());
thresholdValue.setText("" + acg.getAnnotationThreshold());
}
- try
- {
- jbInit();
- } catch (Exception ex)
- {
- }
+ jbInit();
adjusting = false;
updateView();
frame.pack();
}
- public AnnotationColourChooser()
+ @Override
+ protected void jbInit()
{
- try
- {
- jbInit();
- } catch (Exception ex)
- {
- ex.printStackTrace();
- }
- }
+ super.jbInit();
- private void jbInit() throws Exception
- {
minColour.setFont(JvSwingUtils.getLabelFont());
minColour.setBorder(BorderFactory.createEtchedBorder());
minColour.setPreferredSize(new Dimension(40, 20));
}
}
});
- ok.setOpaque(false);
- ok.setText(MessageManager.getString("action.ok"));
- ok.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- ok_actionPerformed();
- }
- });
- cancel.setOpaque(false);
- cancel.setText(MessageManager.getString("action.cancel"));
- cancel.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- cancel_actionPerformed();
- }
- });
+
+ defColours = new JButton();
defColours.setOpaque(false);
defColours.setText(MessageManager.getString("action.set_defaults"));
defColours.setToolTipText(MessageManager
}
});
- annotations.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- annotations_actionPerformed();
- }
- });
- getThreshold().addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- threshold_actionPerformed();
- }
- });
- thresholdValue.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- thresholdValue_actionPerformed();
- }
- });
- slider.setPaintLabels(false);
- slider.setPaintTicks(true);
- slider.setBackground(Color.white);
- slider.setEnabled(false);
- slider.setOpaque(false);
- slider.setPreferredSize(new Dimension(100, 32));
- thresholdValue.setEnabled(false);
- thresholdValue.setColumns(7);
- currentColours.setFont(JvSwingUtils.getLabelFont());
- currentColours.setOpaque(false);
- currentColours.setText(MessageManager
+ useOriginalColours.setFont(JvSwingUtils.getLabelFont());
+ useOriginalColours.setOpaque(false);
+ useOriginalColours.setText(MessageManager
.getString("label.use_original_colours"));
- currentColours.addActionListener(new ActionListener()
+ useOriginalColours.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
- currentColours_actionPerformed();
+ originalColours_actionPerformed();
}
});
thresholdIsMin.setBackground(Color.white);
}
});
- this.setLayout(borderLayout1);
+ this.setLayout(new BorderLayout());
+ JPanel jPanel1 = new JPanel();
+ JPanel jPanel2 = new JPanel();
jPanel2.setLayout(new MigLayout("", "[left][center][right]", "[][][]"));
jPanel1.setBackground(Color.white);
jPanel2.setBackground(Color.white);
jPanel1.add(cancel);
jPanel2.add(annotations, "grow, wrap");
jPanel2.add(seqAssociated);
- jPanel2.add(currentColours);
+ jPanel2.add(useOriginalColours);
JPanel colpanel = new JPanel(new FlowLayout());
colpanel.setBackground(Color.white);
colpanel.add(minColour);
{
if (slider.isEnabled())
{
- if (currentColours.isSelected()
+ if (useOriginalColours.isSelected()
&& !(av.getGlobalColourScheme() instanceof AnnotationColourGradient))
{
updateView();
}
}
- public JComboBox<String> getThreshold()
+ public void originalColours_actionPerformed()
{
- return threshold;
- }
-
- public void setThreshold(JComboBox<String> threshold)
- {
- this.threshold = threshold;
- }
-
- public void currentColours_actionPerformed()
- {
- if (currentColours.isSelected())
+ boolean selected = useOriginalColours.isSelected();
+ if (selected)
{
reset();
}
- maxColour.setEnabled(!currentColours.isSelected());
- minColour.setEnabled(!currentColours.isSelected());
+ maxColour.setEnabled(!selected);
+ minColour.setEnabled(!selected);
+ thresholdIsMin.setEnabled(!selected);
updateView();
}
slider.setEnabled(true);
thresholdValue.setEnabled(true);
- thresholdIsMin.setEnabled(true);
+ thresholdIsMin.setEnabled(!useOriginalColours.isSelected());
if (selectedThresholdItem == AnnotationColourGradient.NO_THRESHOLD)
{
{
getCurrentAnnotation()
.setThreshold(
- new jalview.datamodel.GraphLine(
+ new GraphLine(
(getCurrentAnnotation().graphMax - getCurrentAnnotation().graphMin) / 2f,
"Threshold", Color.black));
}
if (selectedThresholdItem != AnnotationColourGradient.NO_THRESHOLD)
{
adjusting = true;
- float range = getCurrentAnnotation().graphMax * 1000
- - getCurrentAnnotation().graphMin * 1000;
+ float range = getCurrentAnnotation().graphMax * ONETHOUSAND
+ - getCurrentAnnotation().graphMin * ONETHOUSAND;
- slider.setMinimum((int) (getCurrentAnnotation().graphMin * 1000));
- slider.setMaximum((int) (getCurrentAnnotation().graphMax * 1000));
- slider.setValue((int) (getCurrentAnnotation().threshold.value * 1000));
+ slider.setMinimum((int) (getCurrentAnnotation().graphMin * ONETHOUSAND));
+ slider.setMaximum((int) (getCurrentAnnotation().graphMax * ONETHOUSAND));
+ slider.setValue((int) (getCurrentAnnotation().threshold.value * ONETHOUSAND));
thresholdValue.setText(getCurrentAnnotation().threshold.value + "");
slider.setMajorTickSpacing((int) (range / 10f));
slider.setEnabled(true);
thresholdValue.setEnabled(true);
adjusting = false;
}
- colorAlignmContaining(getCurrentAnnotation(), selectedThresholdItem);
+ colorAlignmentContaining(getCurrentAnnotation(), selectedThresholdItem);
ap.alignmentChanged();
// ensure all associated views (overviews, structures, etc) are notified of
ap.paintAlignment(true);
}
+ protected boolean colorAlignmentContaining(AlignmentAnnotation currentAnn, int selectedThresholdOption)
+ {
+
+ AnnotationColourGradient acg = null;
+ if (useOriginalColours.isSelected())
+ {
+ acg = new AnnotationColourGradient(currentAnn,
+ av.getGlobalColourScheme(), selectedThresholdOption);
+ }
+ else
+ {
+ acg = new AnnotationColourGradient(currentAnn,
+ minColour.getBackground(), maxColour.getBackground(),
+ selectedThresholdOption);
+ }
+ acg.setSeqAssociated(seqAssociated.isSelected());
+
+ if (currentAnn.graphMin == 0f && currentAnn.graphMax == 0f)
+ {
+ acg.setPredefinedColours(true);
+ }
+
+ acg.setThresholdIsMinMax(thresholdIsMin.isSelected());
+
+ av.setGlobalColourScheme(acg);
+
+ if (av.getAlignment().getGroups() != null)
+ {
+
+ for (SequenceGroup sg : ap.av.getAlignment().getGroups())
+ {
+ if (sg.cs == null)
+ {
+ continue;
+ }
+
+ if (useOriginalColours.isSelected())
+ {
+ sg.setColourScheme(new AnnotationColourGradient(currentAnn, sg
+ .getColourScheme(), selectedThresholdOption));
+ ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
+ .isSelected());
+ }
+ else
+ {
+ sg.setColourScheme(new AnnotationColourGradient(currentAnn,
+ minColour.getBackground(), maxColour.getBackground(),
+ selectedThresholdOption));
+ ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
+ .isSelected());
+ }
+ }
+ }
+ return false;
+ }
+
}
package jalview.gui;
-import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
+import jalview.io.cache.JvCacheableInputBox;
import jalview.schemes.AnnotationColourGradient;
import jalview.util.MessageManager;
import jalview.viewmodel.annotationfilter.AnnotationFilterParameter;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
+import java.awt.event.KeyEvent;
import java.util.Iterator;
import javax.swing.ButtonGroup;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
-import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
import net.miginfocom.swing.MigLayout;
public class AnnotationColumnChooser extends AnnotationRowFilter implements
ItemListener
{
-
- private JComboBox<String> annotations;
-
- private JPanel actionPanel = new JPanel();
-
- private JPanel thresholdPanel = new JPanel();
-
private JPanel switchableViewsPanel = new JPanel(new CardLayout());
- private CardLayout switchableViewsLayout = (CardLayout) (switchableViewsPanel
- .getLayout());
-
- private JPanel noGraphFilterView = new JPanel();
-
- private JPanel graphFilterView = new JPanel();
-
private JPanel annotationComboBoxPanel = new JPanel();
- private BorderLayout borderLayout1 = new BorderLayout();
-
- private JComboBox<String> threshold = new JComboBox<String>();
-
private StructureFilterPanel gStructureFilterPanel;
private StructureFilterPanel ngStructureFilterPanel;
private int actionOption = ACTION_OPTION_SELECT;
- private ColumnSelection oldColumnSelection;
+ private HiddenColumns oldHiddenColumns;
- public AnnotationColumnChooser()
- {
- try
- {
- jbInit();
- } catch (Exception ex)
- {
- ex.printStackTrace();
- }
- }
+ protected int MIN_WIDTH = 420;
+
+ protected int MIN_HEIGHT = 430;
public AnnotationColumnChooser(AlignViewport av, final AlignmentPanel ap)
{
Desktop.addInternalFrame(frame,
MessageManager.getString("label.select_by_annotation"), 520,
215);
+ frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
addSliderChangeListener();
addSliderMouseListeners();
{
return;
}
- setOldColumnSelection(av.getColumnSelection());
+ setOldHiddenColumns(av.getAlignment().getHiddenColumns());
adjusting = true;
- setAnnotations(new JComboBox<String>(getAnnotationItems(false)));
+ setAnnotations(new JComboBox<>(getAnnotationItems(false)));
populateThresholdComboBox(threshold);
-
+ AnnotationColumnChooser lastChooser = av
+ .getAnnotationColumnSelectionState();
// restore Object state from the previous session if one exists
- if (av.getAnnotationColumnSelectionState() != null)
+ if (lastChooser != null)
{
- currentSearchPanel = av.getAnnotationColumnSelectionState()
+ currentSearchPanel = lastChooser
.getCurrentSearchPanel();
- currentStructureFilterPanel = av.getAnnotationColumnSelectionState()
+ currentStructureFilterPanel = lastChooser
.getCurrentStructureFilterPanel();
- annotations.setSelectedIndex(av.getAnnotationColumnSelectionState()
+ annotations.setSelectedIndex(lastChooser
.getAnnotations().getSelectedIndex());
- threshold.setSelectedIndex(av.getAnnotationColumnSelectionState()
+ threshold.setSelectedIndex(lastChooser
.getThreshold().getSelectedIndex());
- actionOption = av.getAnnotationColumnSelectionState()
+ actionOption = lastChooser
.getActionOption();
+ percentThreshold.setSelected(lastChooser.percentThreshold
+ .isSelected());
}
try
frame.pack();
}
- private void jbInit() throws Exception
+ @Override
+ protected void jbInit()
{
- ok.setOpaque(false);
- ok.setText(MessageManager.getString("action.ok"));
- ok.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- ok_actionPerformed();
- }
- });
-
- cancel.setOpaque(false);
- cancel.setText(MessageManager.getString("action.cancel"));
- cancel.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- cancel_actionPerformed();
- }
- });
-
- annotations.addItemListener(this);
- annotations.setToolTipText(MessageManager
- .getString("info.select_annotation_row"));
- threshold.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- threshold_actionPerformed();
- }
- });
-
- thresholdValue.setEnabled(false);
- thresholdValue.setColumns(7);
- thresholdValue.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- thresholdValue_actionPerformed();
- }
- });
-
- slider.setPaintLabels(false);
- slider.setPaintTicks(true);
- slider.setBackground(Color.white);
- slider.setEnabled(false);
- slider.setOpaque(false);
- slider.setPreferredSize(new Dimension(100, 32));
+ super.jbInit();
+ JPanel thresholdPanel = new JPanel();
thresholdPanel.setBorder(new TitledBorder(MessageManager
.getString("label.threshold_filter")));
thresholdPanel.setBackground(Color.white);
thresholdPanel.setFont(JvSwingUtils.getLabelFont());
thresholdPanel.setLayout(new MigLayout("", "[left][right]", "[][]"));
+ percentThreshold.setBackground(Color.white);
+ percentThreshold.setFont(JvSwingUtils.getLabelFont());
+
+ JPanel actionPanel = new JPanel();
actionPanel.setBackground(Color.white);
actionPanel.setFont(JvSwingUtils.getLabelFont());
+ JPanel graphFilterView = new JPanel();
graphFilterView.setLayout(new MigLayout("", "[left][right]", "[][]"));
graphFilterView.setBackground(Color.white);
+ JPanel noGraphFilterView = new JPanel();
noGraphFilterView.setLayout(new MigLayout("", "[left][right]", "[][]"));
noGraphFilterView.setBackground(Color.white);
ngStructureFilterPanel = new StructureFilterPanel(this);
thresholdPanel.add(getThreshold());
- thresholdPanel.add(thresholdValue, "wrap");
- thresholdPanel.add(slider, "grow, span, wrap");
+ thresholdPanel.add(percentThreshold, "wrap");
+ thresholdPanel.add(slider, "grow");
+ thresholdPanel.add(thresholdValue, "span, wrap");
actionPanel.add(ok);
actionPanel.add(cancel);
switchableViewsPanel.add(graphFilterView,
AnnotationColumnChooser.GRAPH_VIEW);
- this.setLayout(borderLayout1);
+ this.setLayout(new BorderLayout());
this.add(annotationComboBoxPanel, java.awt.BorderLayout.PAGE_START);
this.add(switchableViewsPanel, java.awt.BorderLayout.CENTER);
this.add(actionPanel, java.awt.BorderLayout.SOUTH);
this.validate();
}
- public void updateThresholdPanelToolTip()
+ protected void updateThresholdPanelToolTip()
{
thresholdValue.setToolTipText("");
slider.setToolTipText("");
}
@Override
- public void reset()
+ protected void reset()
{
- if (this.getOldColumnSelection() != null)
+ if (this.getOldHiddenColumns() != null)
{
av.getColumnSelection().clear();
if (av.getAnnotationColumnSelectionState() != null)
{
- ColumnSelection oldSelection = av
+ HiddenColumns oldHidden = av
.getAnnotationColumnSelectionState()
- .getOldColumnSelection();
- if (oldSelection != null && oldSelection.getHiddenColumns() != null
- && !oldSelection.getHiddenColumns().isEmpty())
+ .getOldHiddenColumns();
+ if (oldHidden != null && oldHidden.getHiddenRegions() != null
+ && !oldHidden.getHiddenRegions().isEmpty())
{
- for (Iterator<int[]> itr = oldSelection.getHiddenColumns()
+ for (Iterator<int[]> itr = oldHidden.getHiddenRegions()
.iterator(); itr.hasNext();)
{
int positions[] = itr.next();
av.hideColumns(positions[0], positions[1]);
}
}
- av.setColumnSelection(oldSelection);
+ av.getAlignment().setHiddenColumns(oldHidden);
}
ap.paintAlignment(true);
}
}
}
- public JComboBox<String> getThreshold()
- {
- return threshold;
- }
-
- public void setThreshold(JComboBox<String> threshold)
- {
- this.threshold = threshold;
- }
-
- public JComboBox<String> getAnnotations()
- {
- return annotations;
- }
-
- public void setAnnotations(JComboBox<String> annotations)
- {
- this.annotations = annotations;
- }
-
@Override
public void updateView()
{
slider.setEnabled(true);
thresholdValue.setEnabled(true);
+ percentThreshold.setEnabled(true);
if (selectedThresholdItem == AnnotationColourGradient.NO_THRESHOLD)
{
slider.setEnabled(false);
thresholdValue.setEnabled(false);
thresholdValue.setText("");
+ percentThreshold.setEnabled(false);
// build filter params
}
else if (selectedThresholdItem != AnnotationColourGradient.NO_THRESHOLD)
slider.setMinimum((int) (getCurrentAnnotation().graphMin * 1000));
slider.setMaximum((int) (getCurrentAnnotation().graphMax * 1000));
slider.setValue((int) (getCurrentAnnotation().threshold.value * 1000));
- thresholdValue.setText(getCurrentAnnotation().threshold.value + "");
+
+ setThresholdValueText();
+
slider.setMajorTickSpacing((int) (range / 10f));
slider.setEnabled(true);
thresholdValue.setEnabled(true);
// build filter params
filterParams
.setThresholdType(AnnotationFilterParameter.ThresholdType.NO_THRESHOLD);
- if (getCurrentAnnotation().graph != AlignmentAnnotation.NO_GRAPH)
+ if (getCurrentAnnotation().isQuantitative())
{
filterParams
.setThresholdValue(getCurrentAnnotation().threshold.value);
if (currentSearchPanel != null)
{
-
- if (!currentSearchPanel.searchBox.getText().isEmpty())
+ if (!currentSearchPanel.searchBox.getUserInput().isEmpty())
{
- currentSearchPanel.description.setEnabled(true);
- currentSearchPanel.displayName.setEnabled(true);
- filterParams.setRegexString(currentSearchPanel.searchBox.getText());
+ filterParams.setRegexString(currentSearchPanel.searchBox
+ .getUserInput());
if (currentSearchPanel.displayName.isSelected())
{
filterParams
.addRegexSearchField(AnnotationFilterParameter.SearchableAnnotationField.DESCRIPTION);
}
}
- else
- {
- currentSearchPanel.description.setEnabled(false);
- currentSearchPanel.displayName.setEnabled(false);
- }
}
+ // show hidden columns here, before changing the column selection in
+ // filterAnnotations, because showing hidden columns has the side effect of
+ // adding them to the selection
+ av.showAllHiddenColumns();
av.getColumnSelection().filterAnnotations(
getCurrentAnnotation().annotations, filterParams);
- av.showAllHiddenColumns();
if (getActionOption() == ACTION_OPTION_HIDE)
{
av.hideSelectedColumns();
ap.paintAlignment(true);
}
- public ColumnSelection getOldColumnSelection()
+ public HiddenColumns getOldHiddenColumns()
{
- return oldColumnSelection;
+ return oldHiddenColumns;
}
- public void setOldColumnSelection(ColumnSelection currentColumnSelection)
+ public void setOldHiddenColumns(HiddenColumns currentHiddenColumns)
{
- if (currentColumnSelection != null)
+ if (currentHiddenColumns != null)
{
- this.oldColumnSelection = new ColumnSelection(currentColumnSelection);
+ this.oldHiddenColumns = new HiddenColumns(currentHiddenColumns);
}
}
selectedAnnotationChanged();
}
+ @Override
public void selectedAnnotationChanged()
{
String currentView = AnnotationColumnChooser.NO_GRAPH_VIEW;
- if (av.getAlignment().getAlignmentAnnotation()[annmap[getAnnotations()
- .getSelectedIndex()]].graph != AlignmentAnnotation.NO_GRAPH)
+ if (av.getAlignment()
+ .getAlignmentAnnotation()[annmap[getAnnotations()
+ .getSelectedIndex()]].isQuantitative())
{
currentView = AnnotationColumnChooser.GRAPH_VIEW;
}
-
+ saveCache();
gSearchPanel.syncState();
gFurtherActionPanel.syncState();
gStructureFilterPanel.syncState();
ngFurtherActionPanel.syncState();
ngStructureFilterPanel.syncState();
+ CardLayout switchableViewsLayout = (CardLayout) switchableViewsPanel
+ .getLayout();
switchableViewsLayout.show(switchableViewsPanel, currentView);
updateView();
}
private JCheckBox description = new JCheckBox();
- private JTextField searchBox = new JTextField(10);
+ private static final String FILTER_BY_ANN_CACHE_KEY = "CACHE.SELECT_FILTER_BY_ANNOT";
+
+ public JvCacheableInputBox<String> searchBox = new JvCacheableInputBox<String>(
+ FILTER_BY_ANN_CACHE_KEY);
public SearchPanel(AnnotationColumnChooser aColChooser)
{
this.setBorder(new TitledBorder(MessageManager
.getString("label.search_filter")));
- JvSwingUtils.jvInitComponent(searchBox);
+ searchBox.setPrototypeDisplayValue("XXXXXXXXXXXXXXXXXXXXXXX");
searchBox.setToolTipText(MessageManager
.getString("info.enter_search_text_here"));
- searchBox.getDocument().addDocumentListener(new DocumentListener()
- {
- @Override
- public void insertUpdate(DocumentEvent e)
- {
- searchStringAction();
- }
+ searchBox.getEditor().getEditorComponent()
+ .addKeyListener(new java.awt.event.KeyAdapter()
+ {
+ @Override
+ public void keyPressed(KeyEvent e)
+ {
+ if (e.getKeyCode() == KeyEvent.VK_ENTER)
+ {
+ e.consume();
+ searchStringAction();
+ }
+ }
+ });
- @Override
- public void removeUpdate(DocumentEvent e)
- {
- searchStringAction();
- }
- @Override
- public void changedUpdate(DocumentEvent e)
- {
- searchStringAction();
- }
- });
JvSwingUtils.jvInitComponent(displayName, "label.label");
- displayName.setEnabled(false);
displayName.addActionListener(new ActionListener()
{
@Override
});
JvSwingUtils.jvInitComponent(description, "label.description");
- description.setEnabled(false);
description.addActionListener(new ActionListener()
{
@Override
aColChooser.setCurrentSearchPanel(this);
aColChooser.updateView();
updateSearchPanelToolTips();
+ searchBox.updateCache();
}
public void syncState()
displayName.setEnabled(sp.displayName.isEnabled());
displayName.setSelected(sp.displayName.isSelected());
- searchBox.setText(sp.searchBox.getText());
+ searchBox.setSelectedItem(sp.searchBox.getUserInput());
}
updateSearchPanelToolTips();
}
}
}
+ @Override
+ public void ok_actionPerformed()
+ {
+ saveCache();
+ super.ok_actionPerformed();
+ }
+
+ @Override
+ public void cancel_actionPerformed()
+ {
+ saveCache();
+ super.cancel_actionPerformed();
+ }
+
+ private void saveCache()
+ {
+ gSearchPanel.searchBox.persistCache();
+ ngSearchPanel.searchBox.persistCache();
+ gSearchPanel.searchBox.updateCache();
+ ngSearchPanel.searchBox.updateCache();
+ }
}
aa[selectedRow].scaleColLabel = !aa[selectedRow].scaleColLabel;
}
- refresh(fullRepaint);
+ ap.refresh(fullRepaint);
}
/**
- * Redraw sensibly.
- *
- * @adjustHeight if true, try to recalculate panel height for visible
- * annotations
- */
- protected void refresh(boolean adjustHeight)
- {
- ap.validateAnnotationDimensions(adjustHeight);
- ap.addNotify();
- if (adjustHeight)
- {
- // sort, repaint, update overview
- ap.paintAlignment(true);
- }
- else
- {
- // lightweight repaint
- ap.repaint();
- }
- }
-
- /**
* DOCUMENT ME!
*
* @param e
// ann.visible = false;
// }
// }
- refresh(true);
+ ap.refresh(true);
}
});
pop.add(hideType);
Alignment ds = new Alignment(dseqs);
if (av.hasHiddenColumns())
{
- omitHidden = av.getColumnSelection().getVisibleSequenceStrings(0,
+ omitHidden = av.getAlignment().getHiddenColumns()
+ .getVisibleSequenceStrings(0,
sq.getLength(), seqs);
}
int[] alignmentStartEnd = new int[] { 0, ds.getWidth() - 1 };
- List<int[]> hiddenCols = av.getColumnSelection().getHiddenColumns();
+ List<int[]> hiddenCols = av.getAlignment().getHiddenColumns()
+ .getHiddenRegions();
if (hiddenCols != null)
{
alignmentStartEnd = av.getAlignment().getVisibleStartAndEndIndex(
if (av.hasHiddenColumns())
{
hiddenColumns = new ArrayList<int[]>();
- for (int[] region : av.getColumnSelection().getHiddenColumns())
+ for (int[] region : av.getAlignment().getHiddenColumns()
+ .getHiddenRegions())
{
hiddenColumns.add(new int[] { region[0], region[1] });
}
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.Annotation;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceI;
import jalview.renderer.AnnotationRenderer;
import jalview.renderer.AwtRenderPanelI;
import jalview.schemes.ResidueProperties;
import jalview.util.Comparison;
import jalview.util.MessageManager;
+import jalview.viewmodel.ViewportListenerI;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JColorChooser;
import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.Scrollable;
*/
public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
MouseListener, MouseWheelListener, MouseMotionListener,
- ActionListener, AdjustmentListener, Scrollable
+ ActionListener, AdjustmentListener, Scrollable, ViewportListenerI
{
String HELIX = MessageManager.getString("label.helix");
// and then set our own listener to consume all mousewheel events
ap.annotationScroller.addMouseWheelListener(this);
renderer = new AnnotationRenderer();
+
+ av.getRanges().addPropertyChangeListener(this);
}
public AnnotationPanel(AlignViewport av)
e.consume();
if (e.getWheelRotation() > 0)
{
- ap.scrollRight(true);
+ av.getRanges().scrollRight(true);
}
else
{
- ap.scrollRight(false);
+ av.getRanges().scrollRight(false);
}
}
else
{
for (int index : av.getColumnSelection().getSelected())
{
- if (av.getColumnSelection().isVisible(index))
+ if (av.getAlignment().getHiddenColumns().isVisible(index))
{
anot[index] = null;
}
for (int index : av.getColumnSelection().getSelected())
{
- if (!av.getColumnSelection().isVisible(index))
+ if (!av.getAlignment().getHiddenColumns().isVisible(index))
{
continue;
}
for (int index : av.getColumnSelection().getSelected())
{
- if (!av.getColumnSelection().isVisible(index))
+ if (!av.getAlignment().getHiddenColumns().isVisible(index))
{
continue;
}
}
for (int index : av.getColumnSelection().getSelected())
{
- if (!av.getColumnSelection().isVisible(index))
+ if (!av.getAlignment().getHiddenColumns().isVisible(index))
{
continue;
}
StringBuilder collatedInput = new StringBuilder(64);
String last = "";
ColumnSelection viscols = av.getColumnSelection();
+ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
/*
* the selection list (read-only view) is in selection order, not
for (int index : selected)
{
// always check for current display state - just in case
- if (!viscols.isVisible(index))
+ if (!hidden.isVisible(index))
{
continue;
}
return;
}
- int column = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int column = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
if (av.hasHiddenColumns())
{
- column = av.getColumnSelection().adjustForHiddenColumns(column);
+ column = av.getAlignment().getHiddenColumns()
+ .adjustForHiddenColumns(column);
}
AlignmentAnnotation ann = aa[row];
return;
}
}
- imgWidth = (av.endRes - av.startRes + 1) * av.getCharWidth();
+ imgWidth = (av.getRanges().getEndRes() - av.getRanges().getStartRes() + 1)
+ * av.getCharWidth();
if (imgWidth < 1)
{
return;
imageFresh = true;
}
- drawComponent(gg, av.startRes, av.endRes + 1);
+ drawComponent(gg, av.getRanges().getStartRes(), av.getRanges()
+ .getEndRes() + 1);
imageFresh = false;
g.drawImage(image, 0, 0, this);
}
gg.copyArea(0, 0, imgWidth, getHeight(),
-horizontal * av.getCharWidth(), 0);
long mtime = System.currentTimeMillis();
- int sr = av.startRes;
- int er = av.endRes + 1;
+ int sr = av.getRanges().getStartRes();
+ int er = av.getRanges().getEndRes() + 1;
int transX = 0;
if (horizontal > 0) // scrollbar pulled right, image to the left
renderer.dispose();
}
}
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ // Respond to viewport range changes (e.g. alignment panel was scrolled)
+ if (evt.getPropertyName().equals("startres")
+ || evt.getPropertyName().equals("endres"))
+ {
+ fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
+ }
+ }
}
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.GraphLine;
-import jalview.datamodel.SequenceGroup;
import jalview.schemes.AnnotationColourGradient;
import jalview.util.MessageManager;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Vector;
import javax.swing.JButton;
protected int[] annmap;
- protected boolean enableSeqAss = false;
-
- private AlignmentAnnotation currentAnnotation;
-
protected boolean adjusting = false;
- protected JCheckBox currentColours = new JCheckBox();
-
- protected JPanel minColour = new JPanel();
-
- protected JPanel maxColour = new JPanel();
-
protected JCheckBox seqAssociated = new JCheckBox();
- protected JCheckBox thresholdIsMin = new JCheckBox();
+ protected JCheckBox percentThreshold = new JCheckBox();
protected JSlider slider = new JSlider();
*/
protected boolean sliderDragging = false;
+ protected JComboBox<String> threshold = new JComboBox<String>();
+
+ protected JComboBox<String> annotations;
+
+ /*
+ * map from annotation to its menu item display label
+ * - so we know which item to pre-select on restore
+ */
+ private Map<AlignmentAnnotation, String> annotationLabels;
+
+ private AlignmentAnnotation currentAnnotation;
+
+ /**
+ * Constructor
+ *
+ * @param viewport
+ * @param alignPanel
+ */
+ public AnnotationRowFilter(AlignViewport viewport, final AlignmentPanel alignPanel)
+ {
+ this.av = viewport;
+ this.ap = alignPanel;
+ thresholdValue.addFocusListener(new FocusAdapter()
+ {
+ @Override
+ public void focusLost(FocusEvent e)
+ {
+ thresholdValue_actionPerformed();
+ }
+ });
+ }
+
protected void addSliderChangeListener()
{
{
if (!adjusting)
{
- thresholdValue.setText((slider.getValue() / 1000f) + "");
+ setThresholdValueText();
valueChanged(!sliderDragging);
}
}
});
}
+ /**
+ * update the text field from the threshold slider. preserves state of
+ * 'adjusting' so safe to call in init.
+ */
+ protected void setThresholdValueText()
+ {
+ boolean oldadj = adjusting;
+ adjusting = true;
+ if (percentThreshold.isSelected())
+ {
+ thresholdValue.setText("" + (slider.getValue() - slider.getMinimum())
+ * 100f / (slider.getMaximum() - slider.getMinimum()));
+ }
+ else
+ {
+ thresholdValue.setText((slider.getValue() / 1000f) + "");
+ }
+ adjusting = oldadj;
+ }
protected void addSliderMouseListeners()
{
});
}
- public AnnotationRowFilter(AlignViewport av, final AlignmentPanel ap)
- {
- this.av = av;
- this.ap = ap;
- }
-
- public AnnotationRowFilter()
- {
-
- }
-
+/**
+ * Builds and returns a list of menu items (display text) for choice of
+ * annotation. Also builds maps between annotations, their positions in the
+ * list, and their display labels in the list.
+ *
+ * @param isSeqAssociated
+ * @return
+ */
public Vector<String> getAnnotationItems(boolean isSeqAssociated)
{
+ annotationLabels = new HashMap<AlignmentAnnotation, String>();
+
Vector<String> list = new Vector<String>();
int index = 1;
int[] anmap = new int[av.getAlignment().getAlignmentAnnotation().length];
+ seqAssociated.setEnabled(false);
for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
{
- if (av.getAlignment().getAlignmentAnnotation()[i].sequenceRef == null)
+ AlignmentAnnotation annotation = av.getAlignment()
+ .getAlignmentAnnotation()[i];
+ if (annotation.sequenceRef == null)
{
if (isSeqAssociated)
{
}
else
{
- enableSeqAss = true;
+ seqAssociated.setEnabled(true);
}
- String label = av.getAlignment().getAlignmentAnnotation()[i].label;
+ String label = annotation.label;
// add associated sequence ID if available
- if (!isSeqAssociated
- && av.getAlignment().getAlignmentAnnotation()[i].sequenceRef != null)
+ if (!isSeqAssociated && annotation.sequenceRef != null)
{
- label = label
- + "_"
- + av.getAlignment().getAlignmentAnnotation()[i].sequenceRef
- .getName();
+ label = label + "_" + annotation.sequenceRef.getName();
}
// make label unique
if (!list.contains(label))
{
anmap[list.size()] = i;
list.add(label);
+ annotationLabels.put(annotation, label);
}
else
{
if (!isSeqAssociated)
{
anmap[list.size()] = i;
- list.add(label + "_" + (index++));
+ label = label + "_" + (index++);
+ list.add(label);
+ annotationLabels.put(annotation, label);
}
}
}
return selectedThresholdItem;
}
- public void modelChanged()
- {
- seqAssociated.setEnabled(enableSeqAss);
- }
-
public void ok_actionPerformed()
{
try
}
}
- public void thresholdCheck_actionPerformed()
+ protected void thresholdCheck_actionPerformed()
{
updateView();
}
- public void annotations_actionPerformed()
+ protected void selectedAnnotationChanged()
{
updateView();
}
- public void threshold_actionPerformed()
+ protected void threshold_actionPerformed()
{
updateView();
}
- public void thresholdValue_actionPerformed()
+ protected void thresholdValue_actionPerformed()
{
try
{
float f = Float.parseFloat(thresholdValue.getText());
- slider.setValue((int) (f * 1000));
+ if (percentThreshold.isSelected())
+ {
+ slider.setValue(slider.getMinimum()
+ + ((int) ((f / 100f) * (slider.getMaximum() - slider
+ .getMinimum()))));
+ }
+ else
+ {
+ slider.setValue((int) (f * 1000));
+ }
updateView();
} catch (NumberFormatException ex)
{
}
}
- public void thresholdIsMin_actionPerformed()
+ protected void percentageValue_actionPerformed()
+ {
+ setThresholdValueText();
+ }
+
+ protected void thresholdIsMin_actionPerformed()
{
updateView();
}
- protected void populateThresholdComboBox(JComboBox<String> threshold)
+ protected void populateThresholdComboBox(JComboBox<String> thresh)
{
- threshold.addItem(MessageManager
+ thresh.addItem(MessageManager
.getString("label.threshold_feature_no_threshold"));
- threshold.addItem(MessageManager
+ thresh.addItem(MessageManager
.getString("label.threshold_feature_above_threshold"));
- threshold.addItem(MessageManager
+ thresh.addItem(MessageManager
.getString("label.threshold_feature_below_threshold"));
}
- protected void seqAssociated_actionPerformed(JComboBox<String> annotations)
+ /**
+ * Rebuilds the drop-down list of annotations to choose from when the 'per
+ * sequence only' checkbox is checked or unchecked.
+ *
+ * @param anns
+ */
+ protected void seqAssociated_actionPerformed(JComboBox<String> anns)
{
adjusting = true;
- String cursel = (String) annotations.getSelectedItem();
- boolean isvalid = false, isseqs = seqAssociated.isSelected();
- annotations.removeAllItems();
+ String cursel = (String) anns.getSelectedItem();
+ boolean isvalid = false;
+ boolean isseqs = seqAssociated.isSelected();
+ anns.removeAllItems();
for (String anitem : getAnnotationItems(seqAssociated.isSelected()))
{
if (anitem.equals(cursel) || (isseqs && cursel.startsWith(anitem)))
isvalid = true;
cursel = anitem;
}
- annotations.addItem(anitem);
+ anns.addItem(anitem);
}
- adjusting = false;
if (isvalid)
{
- annotations.setSelectedItem(cursel);
+ anns.setSelectedItem(cursel);
}
else
{
- if (annotations.getItemCount() > 0)
+ if (anns.getItemCount() > 0)
{
- annotations.setSelectedIndex(0);
+ anns.setSelectedIndex(0);
}
}
+ adjusting = false;
+
+ updateView();
}
protected void propagateSeqAssociatedThreshold(boolean allAnnotation,
}
}
- protected boolean colorAlignmContaining(AlignmentAnnotation currentAnn,
- int selectedThresholdOption)
+ public AlignmentAnnotation getCurrentAnnotation()
{
+ return currentAnnotation;
+ }
- AnnotationColourGradient acg = null;
- if (currentColours.isSelected())
- {
- acg = new AnnotationColourGradient(currentAnn,
- av.getGlobalColourScheme(), selectedThresholdOption);
- }
- else
- {
- acg = new AnnotationColourGradient(currentAnn,
- minColour.getBackground(), maxColour.getBackground(),
- selectedThresholdOption);
- }
- acg.setSeqAssociated(seqAssociated.isSelected());
+ protected void setCurrentAnnotation(AlignmentAnnotation annotation)
+ {
+ this.currentAnnotation = annotation;
+ }
+
+ protected abstract void valueChanged(boolean updateAllAnnotation);
+
+ protected abstract void updateView();
- if (currentAnn.graphMin == 0f && currentAnn.graphMax == 0f)
+ protected abstract void reset();
+
+ protected String getAnnotationMenuLabel(AlignmentAnnotation ann)
+ {
+ return annotationLabels.get(ann);
+ }
+
+ protected void jbInit()
+ {
+ ok.setOpaque(false);
+ ok.setText(MessageManager.getString("action.ok"));
+ ok.addActionListener(new ActionListener()
{
- acg.setPredefinedColours(true);
- }
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ ok_actionPerformed();
+ }
+ });
- acg.thresholdIsMinMax = thresholdIsMin.isSelected();
+ cancel.setOpaque(false);
+ cancel.setText(MessageManager.getString("action.cancel"));
+ cancel.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ cancel_actionPerformed();
+ }
+ });
- av.setGlobalColourScheme(acg);
+ annotations.addItemListener(new ItemListener()
+ {
+ @Override
+ public void itemStateChanged(ItemEvent e)
+ {
+ selectedAnnotationChanged();
+ }
+ });
+ annotations.setToolTipText(MessageManager
+ .getString("info.select_annotation_row"));
- if (av.getAlignment().getGroups() != null)
+ threshold.addActionListener(new ActionListener()
{
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ threshold_actionPerformed();
+ }
+ });
- for (SequenceGroup sg : ap.av.getAlignment().getGroups())
+ thresholdValue.setEnabled(false);
+ thresholdValue.setColumns(7);
+ thresholdValue.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
{
- if (sg.cs == null)
- {
- continue;
- }
+ thresholdValue_actionPerformed();
+ }
+ });
- AnnotationColourGradient scheme = null;
- if (currentColours.isSelected())
- {
- scheme = new AnnotationColourGradient(currentAnn,
- sg.getColourScheme(), selectedThresholdOption);
- }
- else
+ percentThreshold.setText(MessageManager.getString("label.as_percentage"));
+ percentThreshold.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ if (!adjusting)
{
- scheme = new AnnotationColourGradient(currentAnn,
- minColour.getBackground(), maxColour.getBackground(),
- selectedThresholdOption);
+ percentageValue_actionPerformed();
}
- scheme.setSeqAssociated(seqAssociated.isSelected());
- sg.setColourScheme(scheme);
}
- }
- return false;
+ });
+ slider.setPaintLabels(false);
+ slider.setPaintTicks(true);
+ slider.setBackground(Color.white);
+ slider.setEnabled(false);
+ slider.setOpaque(false);
+ slider.setPreferredSize(new Dimension(100, 32));
}
- public jalview.datamodel.AlignmentAnnotation getCurrentAnnotation()
+ public JComboBox<String> getThreshold()
{
- return currentAnnotation;
+ return threshold;
}
- public void setCurrentAnnotation(
- jalview.datamodel.AlignmentAnnotation currentAnnotation)
+ public void setThreshold(JComboBox<String> thresh)
{
- this.currentAnnotation = currentAnnotation;
+ this.threshold = thresh;
}
- public abstract void valueChanged(boolean updateAllAnnotation);
-
- public abstract void updateView();
+ public JComboBox<String> getAnnotations()
+ {
+ return annotations;
+ }
- public abstract void reset();
+ public void setAnnotations(JComboBox<String> anns)
+ {
+ this.annotations = anns;
+ }
}
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JInternalFrame;
-import javax.swing.JMenu;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
{
super.initMenus();
- viewerActionMenu = new JMenu(MessageManager.getString("label.jmol"));
+ viewerActionMenu.setText(MessageManager.getString("label.jmol"));
viewerColour
.setText(MessageManager.getString("label.colour_with_jmol"));
int waitFor = 35;
int waitTotal = 0;
while (addingStructures ? lastnotify >= jmb.getLoadNotifiesHandled()
- : !(jmb.isFinishedInit() && jmb.getPdbFile() != null && jmb
- .getPdbFile().length == files.size()))
+ : !(jmb.isFinishedInit() && jmb.getStructureFiles() != null && jmb
+ .getStructureFiles().length == files.size()))
{
try
{
// System.err.println("finished: " + jmb.isFinishedInit()
// + "; loaded: " + Arrays.toString(jmb.getPdbFile())
// + "; files: " + files.toString());
- jmb.getPdbFile();
+ jmb.getStructureFiles();
break;
}
}
String pdbid = "";
try
{
- String[] filesInViewer = jmb.getPdbFile();
+ String[] filesInViewer = jmb.getStructureFiles();
// TODO: replace with reference fetching/transfer code (validate PDBentry
// as a DBRef?)
Pdb pdbclient = new Pdb();
{
private AppJmol appJmolWindow;
- private FeatureRenderer fr = null;
-
public AppJmolBinding(AppJmol appJmol, StructureSelectionManager sSm,
PDBEntry[] pdbentry, SequenceI[][] sequenceIs, DataSourceType protocol)
{
}
@Override
- public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
- {
- AlignmentPanel ap = (alignment == null) ? appJmolWindow
- .getAlignmentPanel() : (AlignmentPanel) alignment;
- if (ap.av.isShowSequenceFeatures())
- {
- if (fr == null)
- {
- fr = (jalview.gui.FeatureRenderer) ap.cloneFeatureRenderer();
- }
- else
- {
- ap.updateFeatureRenderer(fr);
- }
- }
-
- return fr;
- }
-
- @Override
public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment)
{
return new SequenceRenderer(((AlignmentPanel) alignment).av);
{
return appJmolWindow;
}
+
+ @Override
+ public jalview.api.FeatureRenderer getFeatureRenderer(
+ AlignmentViewPanel alignment)
+ {
+ AlignmentPanel ap = (alignment == null) ? appJmolWindow
+ .getAlignmentPanel() : (AlignmentPanel) alignment;
+ if (ap.av.isShowSequenceFeatures())
+ {
+ return ap.av.getAlignPanel().getSeqPanel().seqCanvas.fr;
+ }
+
+ return null;
+ }
}
import jalview.analysis.AlignSeq;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.RnaViewerModel;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
@Override
public void selection(SequenceGroup seqsel, ColumnSelection colsel,
- SelectionSource source)
+ HiddenColumns hidden, SelectionSource source)
{
if (source != ap.av)
{
}
@Override
- public String[] getPdbFile()
+ public String[] getStructureFiles()
{
return null;
}
--- /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.
+ */
+package jalview.gui;
+
+import jalview.analysis.TreeBuilder;
+import jalview.analysis.scoremodels.ScoreModels;
+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;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.GridLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.beans.PropertyVetoException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JInternalFrame;
+import javax.swing.JLabel;
+import javax.swing.JLayeredPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.event.InternalFrameAdapter;
+import javax.swing.event.InternalFrameEvent;
+
+/**
+ * A dialog where a user can choose and action Tree or PCA calculation options
+ */
+public class CalculationChooser extends JPanel
+{
+ /*
+ * flag for whether gap matches residue in the PID calculation for a Tree
+ * - true gives Jalview 2.10.1 behaviour
+ * - set to false (using Groovy) for a more correct tree
+ * (JAL-374)
+ */
+ private static boolean treeMatchGaps = true;
+
+ 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;
+
+ JRadioButton neighbourJoining;
+
+ JRadioButton averageDistance;
+
+ JComboBox<String> modelNames;
+
+ JButton calculate;
+
+ private JInternalFrame frame;
+
+ private JCheckBox includeGaps;
+
+ private JCheckBox matchGaps;
+
+ private JCheckBox includeGappedColumns;
+
+ private JCheckBox shorterSequence;
+
+ final ComboBoxTooltipRenderer renderer = new ComboBoxTooltipRenderer();
+
+ List<String> tips = new ArrayList<String>();
+
+ /**
+ * Constructor
+ *
+ * @param af
+ */
+ public CalculationChooser(AlignFrame alignFrame)
+ {
+ this.af = alignFrame;
+ init();
+ af.alignPanel.setCalculationDialog(this);
+ }
+
+ /**
+ * Lays out the panel and adds it to the desktop
+ */
+ void init()
+ {
+ setLayout(new BorderLayout());
+ frame = new JInternalFrame();
+ frame.setContentPane(this);
+ this.setBackground(Color.white);
+ frame.addFocusListener(new FocusListener()
+ {
+
+ @Override
+ public void focusLost(FocusEvent e)
+ {
+ }
+
+ @Override
+ public void focusGained(FocusEvent e)
+ {
+ validateCalcTypes();
+ }
+ });
+ /*
+ * Layout consists of 3 or 4 panels:
+ * - first with choice of PCA or tree method NJ or AV
+ * - second with choice of score model
+ * - third with score model parameter options [suppressed]
+ * - fourth with OK and Cancel
+ */
+ pca = new JRadioButton(
+ MessageManager.getString("label.principal_component_analysis"));
+ 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);
+
+ JPanel calcChoicePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ calcChoicePanel.setOpaque(false);
+
+ // first create the Tree calculation's border panel
+ JPanel treePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ treePanel.setOpaque(false);
+
+ treePanel.setBorder(BorderFactory.createTitledBorder(MessageManager
+ .getString("label.tree")));
+
+ // then copy the inset dimensions for the border-less PCA panel
+ JPanel pcaBorderless = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ Insets b = treePanel.getBorder().getBorderInsets(treePanel);
+ pcaBorderless.setBorder(BorderFactory.createEmptyBorder(2, b.left, 2,
+ b.right));
+ pcaBorderless.setOpaque(false);
+
+ pcaBorderless.add(pca, FlowLayout.LEFT);
+ calcChoicePanel.add(pcaBorderless, FlowLayout.LEFT);
+
+ treePanel.add(neighbourJoining);
+ treePanel.add(averageDistance);
+
+ calcChoicePanel.add(treePanel);
+
+ ButtonGroup calcTypes = new ButtonGroup();
+ calcTypes.add(pca);
+ calcTypes.add(neighbourJoining);
+ calcTypes.add(averageDistance);
+
+ ActionListener calcChanged = new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ validateCalcTypes();
+ }
+ };
+ pca.addActionListener(calcChanged);
+ neighbourJoining.addActionListener(calcChanged);
+ averageDistance.addActionListener(calcChanged);
+
+ /*
+ * score models drop-down - with added tooltips!
+ */
+ modelNames = buildModelOptionsList();
+
+ JPanel scoreModelPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
+ scoreModelPanel.setOpaque(false);
+ scoreModelPanel.add(modelNames);
+
+ /*
+ * score model parameters
+ */
+ JPanel paramsPanel = new JPanel(new GridLayout(5, 1));
+ paramsPanel.setOpaque(false);
+ includeGaps = new JCheckBox("Include gaps");
+ matchGaps = new JCheckBox("Match gaps");
+ includeGappedColumns = new JCheckBox("Include gapped columns");
+ shorterSequence = new JCheckBox("Match on shorter sequence");
+ paramsPanel.add(new JLabel("Pairwise sequence scoring options"));
+ paramsPanel.add(includeGaps);
+ paramsPanel.add(matchGaps);
+ paramsPanel.add(includeGappedColumns);
+ paramsPanel.add(shorterSequence);
+
+ /*
+ * OK / Cancel buttons
+ */
+ calculate = new JButton(MessageManager.getString("action.calculate"));
+ calculate.setFont(VERDANA_11PT);
+ calculate.addActionListener(new java.awt.event.ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ calculate_actionPerformed();
+ }
+ });
+ 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)
+ {
+ close_actionPerformed();
+ }
+ });
+ JPanel actionPanel = new JPanel();
+ actionPanel.setOpaque(false);
+ actionPanel.add(calculate);
+ actionPanel.add(close);
+
+ boolean includeParams = false;
+ this.add(calcChoicePanel, BorderLayout.CENTER);
+ calcChoicePanel.add(scoreModelPanel);
+ if (includeParams)
+ {
+ scoreModelPanel.add(paramsPanel);
+ }
+ this.add(actionPanel, BorderLayout.SOUTH);
+
+ int width = 350;
+ int height = includeParams ? 420 : 240;
+
+ setMinimumSize(new Dimension(325, height - 10));
+ String title = MessageManager.getString("label.choose_calculation");
+ if (af.getViewport().viewName != null)
+ {
+ title = title + " (" + af.getViewport().viewName + ")";
+ }
+
+ Desktop.addInternalFrame(frame, title, width, height, false);
+ calcChoicePanel.doLayout();
+ revalidate();
+ /*
+ * null the AlignmentPanel's reference to the dialog when it is closed
+ */
+ frame.addInternalFrameListener(new InternalFrameAdapter()
+ {
+ @Override
+ public void internalFrameClosed(InternalFrameEvent evt)
+ {
+ af.alignPanel.setCalculationDialog(null);
+ };
+ });
+
+ frame.setLayer(JLayeredPane.PALETTE_LAYER);
+ }
+
+ /**
+ * enable calculations applicable for the current alignment or selection.
+ */
+ protected void validateCalcTypes()
+ {
+ int size = af.getViewport().getAlignment().getHeight();
+ if (af.getViewport().getSelectionGroup() != null)
+ {
+ size = af.getViewport().getSelectionGroup().getSize();
+ }
+
+ /*
+ * 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)
+ {
+ calculate.setToolTipText(null);
+ calculate.setEnabled(true);
+ }
+ else
+ {
+ calculate.setEnabled(false);
+ }
+ updateScoreModels(modelNames, tips);
+ }
+
+ /**
+ * Check the input and disable a calculation's radio button if necessary. A
+ * tooltip is shown for disabled calculations.
+ *
+ * @param calc
+ * - radio button for the calculation being validated
+ * @param size
+ * - size of input to calculation
+ * @param minsize
+ * - minimum size for calculation
+ * @return true if size >= minsize and calc.isSelected
+ */
+ private boolean checkEnabled(JRadioButton calc, int size, int minsize)
+ {
+ String ttip = MessageManager.formatMessage(
+ "label.you_need_at_least_n_sequences", minsize);
+
+ calc.setEnabled(size >= minsize);
+ if (!calc.isEnabled())
+ {
+ calc.setToolTipText(ttip);
+ }
+ else
+ {
+ calc.setToolTipText(null);
+ }
+ if (calc.isSelected())
+ {
+ modelNames.setEnabled(calc.isEnabled());
+ if (calc.isEnabled())
+ {
+ return true;
+ }
+ else
+ {
+ calculate.setToolTipText(ttip);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * A rather elaborate helper method (blame Swing, not me) that builds a
+ * drop-down list of score models (by name) with descriptions as tooltips.
+ * There is also a tooltip shown for the currently selected item when hovering
+ * over it (without opening the list).
+ */
+ protected JComboBox<String> buildModelOptionsList()
+ {
+ final JComboBox<String> scoreModelsCombo = new JComboBox<String>();
+ scoreModelsCombo.setRenderer(renderer);
+
+ /*
+ * show tooltip on mouse over the combobox
+ * note the listener has to be on the components that make up
+ * the combobox, doesn't work if just on the combobox
+ */
+ final MouseAdapter mouseListener = new MouseAdapter()
+ {
+ @Override
+ public void mouseEntered(MouseEvent e)
+ {
+ scoreModelsCombo.setToolTipText(tips.get(scoreModelsCombo.getSelectedIndex()));
+ }
+
+ @Override
+ public void mouseExited(MouseEvent e)
+ {
+ scoreModelsCombo.setToolTipText(null);
+ }
+ };
+ for (Component c : scoreModelsCombo.getComponents())
+ {
+ c.addMouseListener(mouseListener);
+ }
+
+ updateScoreModels(scoreModelsCombo, tips);
+
+ /*
+ * set the list of tooltips on the combobox's renderer
+ */
+ renderer.setTooltips(tips);
+
+ return scoreModelsCombo;
+ }
+
+ private void updateScoreModels(JComboBox<String> comboBox,
+ List<String> toolTips)
+ {
+ Object curSel = comboBox.getSelectedItem();
+ toolTips.clear();
+ DefaultComboBoxModel<String> model = new DefaultComboBoxModel<String>();
+
+ /*
+ * now we can actually add entries to the combobox,
+ * remembering their descriptions for tooltips
+ */
+ ScoreModels scoreModels = ScoreModels.getInstance();
+ boolean selectedIsPresent = false;
+ for (ScoreModelI sm : scoreModels.getModels())
+ {
+ boolean nucleotide = af.getViewport().getAlignment().isNucleotide();
+ if (sm.isDNA() && nucleotide || sm.isProtein() && !nucleotide)
+ {
+ if (curSel != null && sm.getName().equals(curSel))
+ {
+ selectedIsPresent = true;
+ curSel = sm.getName();
+ }
+ model.addElement(sm.getName());
+
+ /*
+ * tooltip is description if provided, else text lookup with
+ * fallback on the model name
+ */
+ String tooltip = sm.getDescription();
+ if (tooltip == null)
+ {
+ tooltip = MessageManager.getStringOrReturn("label.score_model_",
+ sm.getName());
+ }
+ toolTips.add(tooltip);
+ }
+ }
+ if (selectedIsPresent)
+ {
+ model.setSelectedItem(curSel);
+ }
+ // finally, update the model
+ comboBox.setModel(model);
+ }
+
+ /**
+ * Open and calculate the selected tree or PCA on 'OK'
+ */
+ protected void calculate_actionPerformed()
+ {
+ boolean doPCA = pca.isSelected();
+ String modelName = modelNames.getSelectedItem().toString();
+ SimilarityParamsI params = getSimilarityParameters(doPCA);
+
+ if (doPCA)
+ {
+ openPcaPanel(modelName, params);
+ }
+ else
+ {
+ openTreePanel(modelName, params);
+ }
+
+ // closeFrame();
+ }
+
+ /**
+ * Open a new Tree panel on the desktop
+ *
+ * @param modelName
+ * @param params
+ */
+ 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);
+ }
+
+ /**
+ * Open a new PCA panel on the desktop
+ *
+ * @param modelName
+ * @param 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() < MIN_PCA_SELECTION) && (viewport
+ .getSelectionGroup().getSize() > 0))
+ || (viewport.getAlignment().getHeight() < MIN_PCA_SELECTION))
+ {
+ 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);
+ }
+
+ /**
+ *
+ */
+ protected void closeFrame()
+ {
+ try
+ {
+ frame.setClosed(true);
+ } catch (PropertyVetoException ex)
+ {
+ }
+ }
+
+ /**
+ * Returns a data bean holding parameters for similarity (or distance) model
+ * calculation
+ *
+ * @param doPCA
+ * @return
+ */
+ protected SimilarityParamsI getSimilarityParameters(boolean doPCA)
+ {
+ // commented out: parameter choices read from gui widgets
+ // SimilarityParamsI params = new SimilarityParams(
+ // includeGappedColumns.isSelected(), matchGaps.isSelected(),
+ // includeGaps.isSelected(), shorterSequence.isSelected());
+
+ boolean includeGapGap = true;
+ boolean includeGapResidue = true;
+ boolean matchOnShortestLength = false;
+
+ /*
+ * 'matchGaps' flag is only used in the PID calculation
+ * - set to false for PCA so that PCA using PID reproduces SeqSpace PCA
+ * - set to true for Tree to reproduce Jalview 2.10.1 calculation
+ * - set to false for Tree for a more correct calculation (JAL-374)
+ */
+ boolean matchGap = doPCA ? false : treeMatchGaps;
+
+ return new SimilarityParams(includeGapGap, matchGap, includeGapResidue, matchOnShortestLength);
+ }
+
+ /**
+ * Closes dialog on Close button press
+ */
+ protected void close_actionPerformed()
+ {
+ try
+ {
+ frame.setClosed(true);
+ } catch (Exception ex)
+ {
+ }
+ }
+}
*/
package jalview.gui;
+import jalview.api.FeatureRenderer;
import jalview.bin.Cache;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
+import jalview.ext.rbvi.chimera.ChimeraCommands;
import jalview.ext.rbvi.chimera.JalviewChimeraBinding;
import jalview.gui.StructureViewer.ViewerType;
import jalview.io.DataSourceType;
import jalview.ws.dbsources.Pdb;
import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JInternalFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
{
private JalviewChimeraBinding jmb;
- private boolean allChainsSelected = false;
-
private IProgressIndicator progressBar = null;
/*
private Random random = new Random();
+ private int myWidth = 500;
+
+ private int myHeight = 150;
+
/**
* Initialise menu options.
*/
helpItem.setText(MessageManager.getString("label.chimera_help"));
savemenu.setVisible(false); // not yet implemented
viewMenu.add(fitToWindow);
+
+ /*
+ * exchange of Jalview features and Chimera attributes is for now
+ * an optionally enabled experimental feature
+ */
+ if (Desktop.instance.showExperimental())
+ {
+ JMenuItem writeFeatures = new JMenuItem(
+ MessageManager.getString("label.create_chimera_attributes"));
+ writeFeatures.setToolTipText(MessageManager
+ .getString("label.create_chimera_attributes_tip"));
+ writeFeatures.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ sendFeaturesToChimera();
+ }
+ });
+ viewerActionMenu.add(writeFeatures);
+
+ final JMenu fetchAttributes = new JMenu(
+ MessageManager.getString("label.fetch_chimera_attributes"));
+ fetchAttributes.setToolTipText(MessageManager
+ .getString("label.fetch_chimera_attributes_tip"));
+ fetchAttributes.addMouseListener(new MouseAdapter()
+ {
+
+ @Override
+ public void mouseEntered(MouseEvent e)
+ {
+ buildAttributesMenu(fetchAttributes);
+ }
+ });
+ viewerActionMenu.add(fetchAttributes);
+ }
+ }
+
+ /**
+ * Query Chimera for its residue attribute names and add them as items off the
+ * attributes menu
+ *
+ * @param attributesMenu
+ */
+ protected void buildAttributesMenu(JMenu attributesMenu)
+ {
+ List<String> atts = jmb.sendChimeraCommand("list resattr", true);
+ if (atts == null)
+ {
+ return;
+ }
+ attributesMenu.removeAll();
+ Collections.sort(atts);
+ for (String att : atts)
+ {
+ final String attName = att.split(" ")[1];
+
+ /*
+ * ignore 'jv_*' attributes, as these are Jalview features that have
+ * been transferred to residue attributes in Chimera!
+ */
+ if (!attName.startsWith(ChimeraCommands.NAMESPACE_PREFIX))
+ {
+ JMenuItem menuItem = new JMenuItem(attName);
+ menuItem.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ getChimeraAttributes(attName);
+ }
+ });
+ attributesMenu.add(menuItem);
+ }
+ }
+ }
+
+ /**
+ * Read residues in Chimera with the given attribute name, and set as features
+ * on the corresponding sequence positions (if any)
+ *
+ * @param attName
+ */
+ protected void getChimeraAttributes(String attName)
+ {
+ jmb.copyStructureAttributesToFeatures(attName, getAlignmentPanel());
+ }
+
+ /**
+ * Send a command to Chimera to create residue attributes for Jalview features
+ * <p>
+ * The syntax is: setattr r <attName> <attValue> <atomSpec>
+ * <p>
+ * For example: setattr r jv:chain "Ferredoxin-1, Chloroplastic" #0:94.A
+ */
+ protected void sendFeaturesToChimera()
+ {
+ int count = jmb.sendFeaturesToViewer(getAlignmentPanel());
+ statusBar.setText(MessageManager.formatMessage("label.attributes_set",
+ count));
}
/**
SequenceI[][] seqs)
{
createProgressBar();
- // FIXME extractChains needs pdbentries to match IDs to PDBEntry(s) on seqs
jmb = new JalviewChimeraBindingModel(this,
ap.getStructureSelectionManager(), pdbentrys, seqs, null);
addAlignmentPanel(ap);
useAlignmentPanelForSuperposition(ap);
}
jmb.setColourBySequence(true);
- setSize(400, 400); // probably should be a configurable/dynamic default here
+ setSize(myWidth, myHeight);
initMenus();
addingStructures = false;
void initChimera()
{
jmb.setFinishedInit(false);
- jalview.gui.Desktop.addInternalFrame(this,
+ Desktop.addInternalFrame(this,
jmb.getViewerTitle(getViewerName(), true), getBounds().width,
getBounds().height);
+ chimeraSessionFile);
}
}
- jmb.setFinishedInit(true);
jmb.startChimeraListener();
}
-
/**
* Show only the selected chain(s) in the viewer
*/
StructureFile pdb = null;
try
{
- String[] curfiles = jmb.getPdbFile(); // files currently in viewer
+ String[] curfiles = jmb.getStructureFiles(); // files currently in viewer
// TODO: replace with reference fetching/transfer code (validate PDBentry
// as a DBRef?)
for (int pi = 0; pi < jmb.getPdbCount(); pi++)
if (files.length() > 0)
{
+ jmb.setFinishedInit(false);
if (!addingStructures)
{
try
}
}
}
+
jmb.refreshGUI();
jmb.setFinishedInit(true);
jmb.setLoadingFromArchive(false);
+ /*
+ * ensure that any newly discovered features (e.g. RESNUM)
+ * are added to any open feature settings dialog
+ */
+ FeatureRenderer fr = getBinding().getFeatureRenderer(null);
+ if (fr != null)
+ {
+ fr.featuresAdded();
+ }
+
// refresh the sequence colours for the new structure(s)
for (AlignmentPanel ap : _colourwith)
{
{
BrowserLauncher
.openURL("https://www.cgl.ucsf.edu/chimera/docs/UsersGuide");
- } catch (Exception ex)
+ } catch (IOException ex)
{
}
}
{
return "Chimera";
}
+
+ /**
+ * Sends commands to align structures according to associated alignment(s).
+ *
+ * @return
+ */
+ @Override
+ protected String alignStructs_withAllAlignPanels()
+ {
+ String reply = super.alignStructs_withAllAlignPanels();
+ if (reply != null)
+ {
+ statusBar.setText("Superposition failed: " + reply);
+ }
+ return reply;
+ }
}
import jalview.bin.Cache;
import jalview.datamodel.AnnotatedCollectionI;
import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemeLoader;
import jalview.schemes.ColourSchemes;
import jalview.schemes.ResidueColourScheme;
import jalview.schemes.UserColourScheme;
{
public interface ColourChangeListener
{
+ /**
+ * Change colour scheme to the selected scheme
+ *
+ * @param name
+ * the registered (unique) name of a colour scheme
+ */
void changeColour_actionPerformed(String name);
}
* <li>Clustal</li>
* <li>...other 'built-in' colours</li>
* <li>...any user-defined colours</li>
- * <li>User Defined..</li>
+ * <li>User Defined..(only for AlignFrame menu)</li>
* </ul>
*
* @param colourMenu
}
/*
- * scan registered colour schemes (built-in or user-defined
+ * scan registered colour schemes (built-in or user-defined)
* and add them to the menu (in the order they were registered)
*/
Iterable<ColourSchemeI> colourSchemes = ColourSchemes.getInstance()
/*
* user-defined colour scheme loaded on startup or during the
* Jalview session; right-click on this offers the option to
- * remove it as a colour choice
+ * remove it as a colour choice (unless currently selected)
*/
radioItem.addMouseListener(new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent evt)
{
- if (evt.isPopupTrigger()) // Mac
+ if (evt.isPopupTrigger() && !radioItem.isSelected()) // Mac
{
offerRemoval();
}
@Override
public void mouseReleased(MouseEvent evt)
{
- if (evt.isPopupTrigger()) // Windows
+ if (evt.isPopupTrigger() && !radioItem.isSelected()) // Windows
{
offerRemoval();
}
final String label = MessageManager.getString("action.user_defined");
JRadioButtonMenuItem userDefinedColour = new JRadioButtonMenuItem(
label);
+ userDefinedColour.setName(ResidueColourScheme.USER_DEFINED);
userDefinedColour.addActionListener(new ActionListener()
{
@Override
}
/**
- * Marks as selected the colour menu item matching the given name, or the
- * first item ('None') if no match is found
+ * Marks as selected the colour menu item matching the given colour scheme, or
+ * the first item ('None') if no match is found. If the colour scheme is a
+ * user defined scheme, but not in the menu (this arises if a new scheme is
+ * defined and applied but not saved to file), then menu option
+ * "User Defined.." is selected.
*
* @param colourMenu
- * @param colourName
+ * @param cs
*/
- public static void setColourSelected(JMenu colourMenu, String colourName)
+ public static void setColourSelected(JMenu colourMenu, ColourSchemeI cs)
{
- if (colourName == null)
- {
- return;
- }
+ String colourName = cs == null ? ResidueColourScheme.NONE : cs
+ .getSchemeName();
JRadioButtonMenuItem none = null;
+ JRadioButtonMenuItem userDefined = null;
/*
* select the radio button whose name matches the colour name
{
if (menuItem instanceof JRadioButtonMenuItem)
{
- String buttonName = ((JRadioButtonMenuItem) menuItem).getName();
- if (colourName.equals(buttonName))
+ JRadioButtonMenuItem radioButton = (JRadioButtonMenuItem) menuItem;
+ String buttonName = radioButton.getName();
+ if (buttonName.equals(colourName))
{
- ((JRadioButtonMenuItem) menuItem).setSelected(true);
+ radioButton.setSelected(true);
return;
}
if (ResidueColourScheme.NONE.equals(buttonName))
{
- none = (JRadioButtonMenuItem) menuItem;
+ none = radioButton;
+ }
+ if (ResidueColourScheme.USER_DEFINED.equals(buttonName))
+ {
+ userDefined = radioButton;
}
}
}
- if (none != null)
+
+ /*
+ * no match by name; select User Defined.. if current scheme is a
+ * user defined one, else select None
+ */
+ if (cs instanceof UserColourScheme && userDefined != null)
+ {
+ userDefined.setSelected(true);
+ }
+ else if (none != null)
{
none.setSelected(true);
}
}
/**
- * Marks as selected the colour menu item matching the given colour scheme, or
- * the first item ('None') if no match is found
- *
- * @param colourMenu
- * @param cs
- */
- public static void setColourSelected(JMenu colourMenu, ColourSchemeI cs)
- {
- setColourSelected(colourMenu, cs == null ? ResidueColourScheme.NONE
- : cs.getSchemeName());
- }
-
- /**
* Updates the USER_DEFINE_COLOURS preference to remove any de-registered
* colour scheme
*/
{
try
{
- UserColourScheme ucs = ColourSchemes.loadColourScheme(file);
+ UserColourScheme ucs = ColourSchemeLoader.loadColourScheme(file);
if (ucs != null
&& ColourSchemes.getInstance().nameExists(ucs.getName()))
{
--- /dev/null
+package jalview.gui;
+
+import java.awt.Component;
+import java.util.List;
+
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JComponent;
+import javax.swing.JList;
+
+/**
+ * A helper class to render a combobox with tooltips
+ *
+ * @see http
+ * ://stackoverflow.com/questions/480261/java-swing-mouseover-text-on-jcombobox
+ * -items
+ */
+public class ComboBoxTooltipRenderer extends DefaultListCellRenderer
+{
+ private static final long serialVersionUID = 1L;
+
+ List<String> tooltips;
+
+ @Override
+ public Component getListCellRendererComponent(JList list, Object value,
+ int index, boolean isSelected, boolean cellHasFocus)
+ {
+
+ JComponent comp = (JComponent) super.getListCellRendererComponent(list,
+ value, index, isSelected, cellHasFocus);
+
+ if (-1 < index && null != value && null != tooltips)
+ {
+ list.setToolTipText(tooltips.get(index));
+ }
+ return comp;
+ }
+
+ public void setTooltips(List<String> tips)
+ {
+ this.tooltips = tips;
+ }
+}
// are we attached to some parent Desktop
Desktop parent = null;
+ private int MIN_WIDTH = 300;
+
+ private int MIN_HEIGHT = 250;
+
public Console()
{
// create all components and add them
.getLocalGraphicsEnvironment();
String[] fontNames = ge.getAvailableFontFamilyNames();
for (int n = 0; n < fontNames.length; n++)
+ {
System.out.println(fontNames[n]);
+ }
// Testing part: simple an error thrown anywhere in this JVM will be printed
// on the Console
// We do it with a seperate Thread becasue we don't wan't to break a Thread
JFrame frame = new JFrame(string);
frame.setName(string);
if (x == -1)
- x = (int) (i / 2);
+ {
+ x = i / 2;
+ }
if (y == -1)
- y = (int) (j / 2);
+ {
+ y = j / 2;
+ }
frame.setBounds(x, y, i, j);
return frame;
}
frame = initFrame("Jalview Java Console", bounds.width,
bounds.height, bounds.x, bounds.y);
}
+ frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
// desktop.add(frame);
initConsole(false);
JalviewAppender jappender = new JalviewAppender();
// System.exit(0);
}
+ @Override
public synchronized void windowClosed(WindowEvent evt)
{
frame.setVisible(false);
}
}
+ @Override
public synchronized void windowClosing(WindowEvent evt)
{
frame.setVisible(false); // default behaviour of JFrame
// frame.dispose();
}
+ @Override
public synchronized void actionPerformed(ActionEvent evt)
{
trimBuffer(true);
// textArea.setText("");
}
+ @Override
public synchronized void run()
{
try
// lines++;
}
if (quit)
+ {
return;
+ }
}
while (Thread.currentThread() == reader2)
// lines++;
}
if (quit)
+ {
return;
+ }
}
while (Thread.currentThread() == textAppender)
{
long time = System.nanoTime();
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
+ @Override
public void run()
{
displayPipe.append(input); // change to stringBuffer
{
int available = in.available();
if (available == 0)
+ {
break;
+ }
byte b[] = new byte[available];
in.read(b);
input = input + new String(b, 0, b.length);
import jalview.api.FeaturesSourceI;
import jalview.bin.Jalview;
import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceI;
import jalview.io.AlignmentFileReaderI;
import jalview.io.AppletFormatAdapter;
AlignFrame af;
if (source instanceof ComplexAlignFile)
{
- ColumnSelection colSel = ((ComplexAlignFile) source)
- .getColumnSelection();
+ HiddenColumns hidden = ((ComplexAlignFile) source)
+ .getHiddenColumns();
SequenceI[] hiddenSeqs = ((ComplexAlignFile) source)
.getHiddenSequences();
boolean showSeqFeatures = ((ComplexAlignFile) source)
.getGlobalColourScheme();
FeaturesDisplayedI fd = ((ComplexAlignFile) source)
.getDisplayedFeatures();
- af = new AlignFrame(al, hiddenSeqs, colSel,
+ af = new AlignFrame(al, hiddenSeqs, hidden,
AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
af.getViewport().setShowSequenceFeatures(showSeqFeatures);
af.getViewport().setFeaturesDisplayed(fd);
DropTargetListener, ClipboardOwner, IProgressIndicator,
jalview.api.StructureSelectionManagerProvider
{
+ private static int DEFAULT_MIN_WIDTH = 300;
+
+ private static int DEFAULT_MIN_HEIGHT = 250;
+
+ private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
+
+ private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
+
+ private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
instance = this;
doVamsasClientCheck();
- groovyShell = new JMenuItem();
- groovyShell.setText(MessageManager.getString("label.groovy_console"));
- groovyShell.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- groovyShell_actionPerformed();
- }
- });
- toolsMenu.add(groovyShell);
- groovyShell.setVisible(true);
-
doConfigureStructurePrefs();
setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
showConsole(showjconsole);
showNews.setVisible(false);
+
+ experimentalFeatures.setSelected(showExperimental());
getIdentifiersOrgData();
});
}
+ /**
+ * Answers true if user preferences to enable experimental features is True
+ * (on), else false
+ *
+ * @return
+ */
+ public boolean showExperimental()
+ {
+ String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
+ Boolean.FALSE.toString());
+ return Boolean.valueOf(experimental).booleanValue();
+ }
+
public void doConfigureStructurePrefs()
{
// configure services
public static synchronized void addInternalFrame(
final JInternalFrame frame, String title, int w, int h)
{
- addInternalFrame(frame, title, true, w, h, true);
+ addInternalFrame(frame, title, true, w, h, true, false);
}
/**
final JInternalFrame frame, String title, boolean makeVisible,
int w, int h)
{
- addInternalFrame(frame, title, makeVisible, w, h, true);
+ addInternalFrame(frame, title, makeVisible, w, h, true, false);
}
/**
final JInternalFrame frame, String title, int w, int h,
boolean resizable)
{
- addInternalFrame(frame, title, true, w, h, resizable);
+ addInternalFrame(frame, title, true, w, h, resizable, false);
}
/**
* height
* @param resizable
* Allow resize
+ * @param ignoreMinSize
+ * Do not set the default minimum size for frame
*/
public static synchronized void addInternalFrame(
final JInternalFrame frame, String title, boolean makeVisible,
- int w, int h, boolean resizable)
+ int w, int h, boolean resizable, boolean ignoreMinSize)
{
// TODO: allow callers to determine X and Y position of frame (eg. via
openFrameCount++;
+ if (!ignoreMinSize)
+ {
+ frame.setMinimumSize(new Dimension(DEFAULT_MIN_WIDTH,
+ DEFAULT_MIN_HEIGHT));
+
+ // Set default dimension for Alignment Frame window.
+ // The Alignment Frame window could be added from a number of places,
+ // hence,
+ // I did this here in order not to miss out on any Alignment frame.
+ if (frame instanceof AlignFrame)
+ {
+ frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
+ ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
+ }
+ }
+
+
frame.setVisible(makeVisible);
frame.setClosable(true);
frame.setResizable(resizable);
}
- protected JMenuItem groovyShell;
-
/**
* Accessor method to quickly get all the AlignmentFrames loaded.
*
/**
* Add Groovy Support to Jalview
*/
+ @Override
public void groovyShell_actionPerformed()
{
try
if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
{
- if (jalview.ws.jws2.Jws2Discoverer.getDiscoverer().isRunning())
- {
- jalview.ws.jws2.Jws2Discoverer.getDiscoverer().setAborted(true);
- }
t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer().startDiscoverer(
changeSupport);
-
}
Thread t3 = null;
{
}
}
}
+
+ /**
+ * Sets the Preferences property for experimental features to True or False
+ * depending on the state of the controlling menu item
+ */
+ @Override
+ protected void showExperimental_actionPerformed(boolean selected)
+ {
+ Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
+ }
}
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.io.FeaturesFile;
import jalview.schemes.FeatureColour;
import jalview.util.ColorUtils;
import jalview.util.MessageManager;
import java.awt.event.MouseEvent;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.List;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JLabel;
-import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
/**
* DOCUMENT ME!
* @version $Revision$
*/
public class FeatureRenderer extends
- jalview.renderer.seqfeatures.FeatureRenderer implements
- jalview.api.FeatureRenderer
+ jalview.renderer.seqfeatures.FeatureRenderer
{
+ /*
+ * defaults for creating a new feature are the last created
+ * feature type and group
+ */
+ static String lastFeatureAdded = "feature_1";
+
+ static String lastFeatureGroupAdded = "Jalview";
+
Color resBoxColour;
AlignmentPanel ap;
/**
- * Creates a new FeatureRenderer object.
+ * Creates a new FeatureRenderer object
*
- * @param av
- * DOCUMENT ME!
+ * @param alignPanel
*/
- public FeatureRenderer(AlignmentPanel ap)
+ public FeatureRenderer(AlignmentPanel alignPanel)
{
- super(ap.av);
- this.ap = ap;
- if (ap != null && ap.getSeqPanel() != null
- && ap.getSeqPanel().seqCanvas != null
- && ap.getSeqPanel().seqCanvas.fr != null)
+ super(alignPanel.av);
+ this.ap = alignPanel;
+ if (alignPanel.getSeqPanel() != null
+ && alignPanel.getSeqPanel().seqCanvas != null
+ && alignPanel.getSeqPanel().seqCanvas.fr != null)
{
- transferSettings(ap.getSeqPanel().seqCanvas.fr);
+ transferSettings(alignPanel.getSeqPanel().seqCanvas.fr);
}
}
- // // /////////////
- // // Feature Editing Dialog
- // // Will be refactored in next release.
-
- static String lastFeatureAdded;
-
- static String lastFeatureGroupAdded;
-
- static String lastDescriptionAdded;
-
FeatureColourI oldcol, fcol;
int featureIndex = 0;
- boolean amendFeatures(final SequenceI[] sequences,
- final SequenceFeature[] features, boolean newFeatures,
- final AlignmentPanel ap)
+ /**
+ * Presents a dialog allowing the user to add new features, or amend or delete
+ * existing features. Currently this can be on
+ * <ul>
+ * <li>double-click on a sequence - Amend/Delete features at position</li>
+ * <li>Create sequence feature from pop-up menu on selected region</li>
+ * <li>Create features for pattern matches from Find</li>
+ * </ul>
+ * If the supplied feature type is null, show (and update on confirm) the type
+ * and group of the last new feature created (with initial defaults of
+ * "feature_1" and "Jalview").
+ *
+ * @param sequences
+ * the sequences features are to be created on (if creating
+ * features), or a single sequence (if amending features)
+ * @param features
+ * the current features at the position (if amending), or template
+ * new feature(s) with start/end position set (if creating)
+ * @param create
+ * true to create features, false to amend or delete
+ * @param alignPanel
+ * @return
+ */
+ protected boolean amendFeatures(final List<SequenceI> sequences,
+ final List<SequenceFeature> features, boolean create,
+ final AlignmentPanel alignPanel)
{
-
featureIndex = 0;
- final JPanel bigPanel = new JPanel(new BorderLayout());
- final JComboBox overlaps;
+ final JPanel mainPanel = new JPanel(new BorderLayout());
+
final JTextField name = new JTextField(25);
- final JTextField source = new JTextField(25);
+ name.getDocument().addDocumentListener(new DocumentListener()
+ {
+ @Override
+ public void insertUpdate(DocumentEvent e)
+ {
+ warnIfTypeHidden(mainPanel, name.getText());
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent e)
+ {
+ warnIfTypeHidden(mainPanel, name.getText());
+ }
+
+ @Override
+ public void changedUpdate(DocumentEvent e)
+ {
+ warnIfTypeHidden(mainPanel, name.getText());
+ }
+ });
+
+ final JTextField group = new JTextField(25);
+ group.getDocument().addDocumentListener(new DocumentListener()
+ {
+ @Override
+ public void insertUpdate(DocumentEvent e)
+ {
+ warnIfGroupHidden(mainPanel, group.getText());
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent e)
+ {
+ warnIfGroupHidden(mainPanel, group.getText());
+ }
+
+ @Override
+ public void changedUpdate(DocumentEvent e)
+ {
+ warnIfGroupHidden(mainPanel, group.getText());
+ }
+ });
+
final JTextArea description = new JTextArea(3, 25);
final JSpinner start = new JSpinner();
final JSpinner end = new JSpinner();
if (col != null)
{
fcol = new FeatureColour(col);
- updateColourButton(bigPanel, colour, new FeatureColour(col));
+ updateColourButton(mainPanel, colour, fcol);
}
}
else
{
if (fcc == null)
{
- final String type = features[featureIndex].getType();
+ final String ft = features.get(featureIndex).getType();
+ final String type = ft == null ? lastFeatureAdded : ft;
fcc = new FeatureColourChooser(me, type);
fcc.setRequestFocusEnabled(true);
fcc.requestFocus();
fcol = fcc.getLastColour();
fcc = null;
setColour(type, fcol);
- updateColourButton(bigPanel, colour, fcol);
+ updateColourButton(mainPanel, colour, fcol);
}
});
}
}
});
- JPanel tmp = new JPanel();
- JPanel panel = new JPanel(new GridLayout(3, 1));
+ JPanel gridPanel = new JPanel(new GridLayout(3, 1));
- // /////////////////////////////////////
- // /MULTIPLE FEATURES AT SELECTED RESIDUE
- if (!newFeatures && features.length > 1)
+ if (!create && features.size() > 1)
{
- panel = new JPanel(new GridLayout(4, 1));
- tmp = new JPanel();
- tmp.add(new JLabel(MessageManager.getString("label.select_feature")
+ /*
+ * more than one feature at selected position - add a drop-down
+ * to choose the feature to amend
+ */
+ gridPanel = new JPanel(new GridLayout(4, 1));
+ JPanel choosePanel = new JPanel();
+ choosePanel.add(new JLabel(MessageManager
+ .getString("label.select_feature")
+ ":"));
- overlaps = new JComboBox();
- for (int i = 0; i < features.length; i++)
+ final JComboBox<String> overlaps = new JComboBox<String>();
+ for (SequenceFeature sf : features)
{
- overlaps.addItem(features[i].getType() + "/"
- + features[i].getBegin() + "-" + features[i].getEnd()
- + " (" + features[i].getFeatureGroup() + ")");
+ String text = sf.getType() + "/" + sf.getBegin() + "-"
+ + sf.getEnd() + " (" + sf.getFeatureGroup() + ")";
+ overlaps.addItem(text);
}
-
- tmp.add(overlaps);
+ choosePanel.add(overlaps);
overlaps.addItemListener(new ItemListener()
{
if (index != -1)
{
featureIndex = index;
- name.setText(features[index].getType());
- description.setText(features[index].getDescription());
- source.setText(features[index].getFeatureGroup());
- start.setValue(new Integer(features[index].getBegin()));
- end.setValue(new Integer(features[index].getEnd()));
+ SequenceFeature sf = features.get(index);
+ name.setText(sf.getType());
+ description.setText(sf.getDescription());
+ group.setText(sf.getFeatureGroup());
+ start.setValue(new Integer(sf.getBegin()));
+ end.setValue(new Integer(sf.getEnd()));
SearchResultsI highlight = new SearchResults();
- highlight.addResult(sequences[0], features[index].getBegin(),
- features[index].getEnd());
+ highlight.addResult(sequences.get(0), sf.getBegin(),
+ sf.getEnd());
- ap.getSeqPanel().seqCanvas.highlightSearchResults(highlight);
+ alignPanel.getSeqPanel().seqCanvas.highlightSearchResults(highlight);
}
FeatureColourI col = getFeatureStyle(name.getText());
.createColourFromName(name.getText()));
}
oldcol = fcol = col;
- updateColourButton(bigPanel, colour, col);
+ updateColourButton(mainPanel, colour, col);
}
});
- panel.add(tmp);
+ gridPanel.add(choosePanel);
}
- // ////////
- // ////////////////////////////////////
- tmp = new JPanel();
- panel.add(tmp);
- tmp.add(new JLabel(MessageManager.getString("label.name:"),
+ JPanel namePanel = new JPanel();
+ gridPanel.add(namePanel);
+ namePanel.add(new JLabel(MessageManager.getString("label.name:"),
JLabel.RIGHT));
- tmp.add(name);
+ namePanel.add(name);
- tmp = new JPanel();
- panel.add(tmp);
- tmp.add(new JLabel(MessageManager.getString("label.group:"),
+ JPanel groupPanel = new JPanel();
+ gridPanel.add(groupPanel);
+ groupPanel.add(new JLabel(MessageManager.getString("label.group:"),
JLabel.RIGHT));
- tmp.add(source);
+ groupPanel.add(group);
- tmp = new JPanel();
- panel.add(tmp);
- tmp.add(new JLabel(MessageManager.getString("label.colour"),
+ JPanel colourPanel = new JPanel();
+ gridPanel.add(colourPanel);
+ colourPanel.add(new JLabel(MessageManager.getString("label.colour"),
JLabel.RIGHT));
- tmp.add(colour);
+ colourPanel.add(colour);
colour.setPreferredSize(new Dimension(150, 15));
colour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 9));
colour.setForeground(Color.black);
colour.setVerticalAlignment(SwingConstants.CENTER);
colour.setHorizontalTextPosition(SwingConstants.CENTER);
colour.setVerticalTextPosition(SwingConstants.CENTER);
- bigPanel.add(panel, BorderLayout.NORTH);
+ mainPanel.add(gridPanel, BorderLayout.NORTH);
- panel = new JPanel();
- panel.add(new JLabel(MessageManager.getString("label.description:"),
+ JPanel descriptionPanel = new JPanel();
+ descriptionPanel.add(new JLabel(MessageManager
+ .getString("label.description:"),
JLabel.RIGHT));
description.setFont(JvSwingUtils.getTextAreaFont());
description.setLineWrap(true);
- panel.add(new JScrollPane(description));
+ descriptionPanel.add(new JScrollPane(description));
- if (!newFeatures)
+ if (!create)
{
- bigPanel.add(panel, BorderLayout.SOUTH);
+ mainPanel.add(descriptionPanel, BorderLayout.SOUTH);
- panel = new JPanel();
- panel.add(new JLabel(MessageManager.getString("label.start"),
+ JPanel startEndPanel = new JPanel();
+ startEndPanel.add(new JLabel(MessageManager.getString("label.start"),
JLabel.RIGHT));
- panel.add(start);
- panel.add(new JLabel(MessageManager.getString("label.end"),
+ startEndPanel.add(start);
+ startEndPanel.add(new JLabel(MessageManager.getString("label.end"),
JLabel.RIGHT));
- panel.add(end);
- bigPanel.add(panel, BorderLayout.CENTER);
+ startEndPanel.add(end);
+ mainPanel.add(startEndPanel, BorderLayout.CENTER);
}
else
{
- bigPanel.add(panel, BorderLayout.CENTER);
+ mainPanel.add(descriptionPanel, BorderLayout.CENTER);
}
- if (lastFeatureAdded == null)
- {
- if (features[0].type != null)
- {
- lastFeatureAdded = features[0].type;
- }
- else
- {
- lastFeatureAdded = "feature_1";
- }
- }
-
- if (lastFeatureGroupAdded == null)
- {
- if (features[0].featureGroup != null)
- {
- lastFeatureGroupAdded = features[0].featureGroup;
- }
- else
- {
- lastFeatureGroupAdded = "Jalview";
- }
- }
-
- if (newFeatures)
- {
- name.setText(lastFeatureAdded);
- source.setText(lastFeatureGroupAdded);
- }
- else
- {
- name.setText(features[0].getType());
- source.setText(features[0].getFeatureGroup());
- }
-
- start.setValue(new Integer(features[0].getBegin()));
- end.setValue(new Integer(features[0].getEnd()));
- description.setText(features[0].getDescription());
- updateColourButton(bigPanel, colour,
- (oldcol = fcol = getFeatureStyle(name.getText())));
+ /*
+ * default feature type and group to that of the first feature supplied,
+ * or to the last feature created if not supplied (null value)
+ */
+ SequenceFeature firstFeature = features.get(0);
+ boolean useLastDefaults = firstFeature.getType() == null;
+ final String featureType = useLastDefaults ? lastFeatureAdded
+ : firstFeature.getType();
+ final String featureGroup = useLastDefaults ? lastFeatureGroupAdded
+ : firstFeature.getFeatureGroup();
+ name.setText(featureType);
+ group.setText(featureGroup);
+
+ start.setValue(new Integer(firstFeature.getBegin()));
+ end.setValue(new Integer(firstFeature.getEnd()));
+ description.setText(firstFeature.getDescription());
+ updateColourButton(mainPanel, colour,
+ (oldcol = fcol = getFeatureStyle(featureType)));
Object[] options;
- if (!newFeatures)
+ if (!create)
{
- options = new Object[] { "Amend", "Delete", "Cancel" };
+ options = new Object[] { MessageManager.getString("label.amend"),
+ MessageManager.getString("action.delete"),
+ MessageManager.getString("action.cancel") };
}
else
{
- options = new Object[] { "OK", "Cancel" };
+ options = new Object[] { MessageManager.getString("action.ok"),
+ MessageManager.getString("action.cancel") };
}
- String title = newFeatures ? MessageManager
+ String title = create ? MessageManager
.getString("label.create_new_sequence_features")
: MessageManager.formatMessage("label.amend_delete_features",
- new String[] { sequences[0].getName() });
+ new String[] { sequences.get(0).getName() });
+ /*
+ * show the dialog
+ */
int reply = JvOptionPane.showInternalOptionDialog(Desktop.desktop,
- bigPanel, title, JvOptionPane.YES_NO_CANCEL_OPTION,
+ mainPanel, title, JvOptionPane.YES_NO_CANCEL_OPTION,
JvOptionPane.QUESTION_MESSAGE, null, options,
MessageManager.getString("action.ok"));
- jalview.io.FeaturesFile ffile = new jalview.io.FeaturesFile();
+ FeaturesFile ffile = new FeaturesFile();
- if (reply == JvOptionPane.OK_OPTION && name.getText().length() > 0)
+ String enteredType = name.getText().trim();
+ if (reply == JvOptionPane.OK_OPTION && enteredType.length() > 0)
{
- // This ensures that the last sequence
- // is refreshed and new features are rendered
- lastSeq = null;
- lastFeatureAdded = name.getText().trim();
- lastFeatureGroupAdded = source.getText().trim();
- lastDescriptionAdded = description.getText().replaceAll("\n", " ");
- // TODO: determine if the null feature group is valid
- if (lastFeatureGroupAdded.length() < 1)
+ /*
+ * update default values only if creating using default values
+ */
+ if (useLastDefaults)
{
- lastFeatureGroupAdded = null;
+ lastFeatureAdded = enteredType;
+ lastFeatureGroupAdded = group.getText().trim();
+ // TODO: determine if the null feature group is valid
+ if (lastFeatureGroupAdded.length() < 1)
+ {
+ lastFeatureGroupAdded = null;
+ }
}
}
- if (!newFeatures)
+ if (!create)
{
- SequenceFeature sf = features[featureIndex];
+ SequenceFeature sf = features.get(featureIndex);
if (reply == JvOptionPane.NO_OPTION)
{
- sequences[0].getDatasetSequence().deleteFeature(sf);
+ /*
+ * NO_OPTION corresponds to the Delete button
+ */
+ sequences.get(0).getDatasetSequence().deleteFeature(sf);
+ // update Feature Settings for removal of feature / group
+ featuresAdded();
}
else if (reply == JvOptionPane.YES_OPTION)
{
- sf.type = lastFeatureAdded;
- sf.featureGroup = lastFeatureGroupAdded;
- sf.description = lastDescriptionAdded;
+ /*
+ * YES_OPTION corresponds to the Amend button
+ * need to refresh Feature Settings if type, group or colour changed
+ */
+ sf.type = enteredType;
+ sf.featureGroup = group.getText().trim();
+ sf.description = description.getText().replaceAll("\n", " ");
+ boolean refreshSettings = (!featureType.equals(sf.type) || !featureGroup
+ .equals(sf.featureGroup));
+ refreshSettings |= (fcol != oldcol);
setColour(sf.type, fcol);
- getFeaturesDisplayed().setVisible(sf.type);
try
{
}
ffile.parseDescriptionHTML(sf, false);
+ if (refreshSettings)
+ {
+ featuresAdded();
+ }
}
}
else
// NEW FEATURES ADDED
{
- if (reply == JvOptionPane.OK_OPTION && lastFeatureAdded.length() > 0)
+ if (reply == JvOptionPane.OK_OPTION && enteredType.length() > 0)
{
- for (int i = 0; i < sequences.length; i++)
+ for (int i = 0; i < sequences.size(); i++)
{
- features[i].type = lastFeatureAdded;
+ SequenceFeature sf = features.get(i);
+ sf.type = enteredType;
// fix for JAL-1538 - always set feature group here
- features[i].featureGroup = lastFeatureGroupAdded;
- features[i].description = lastDescriptionAdded;
- sequences[i].addSequenceFeature(features[i]);
- ffile.parseDescriptionHTML(features[i], false);
+ sf.featureGroup = group.getText().trim();
+ sf.description = description.getText().replaceAll("\n", " ");
+ sequences.get(i).addSequenceFeature(sf);
+ ffile.parseDescriptionHTML(sf, false);
}
- if (lastFeatureGroupAdded != null)
- {
- setGroupVisibility(lastFeatureGroupAdded, true);
- }
- setColour(lastFeatureAdded, fcol);
- setVisible(lastFeatureAdded);
+ setColour(enteredType, fcol);
- findAllFeatures(false);
+ featuresAdded();
- ap.paintAlignment(true);
+ alignPanel.paintAlignment(true);
return true;
}
}
}
- ap.paintAlignment(true);
+ alignPanel.paintAlignment(true);
return true;
}
/**
+ * Show a warning message if the entered type is one that is currently hidden
+ *
+ * @param panel
+ * @param type
+ */
+ protected void warnIfTypeHidden(JPanel panel, String type)
+ {
+ if (getRenderOrder().contains(type))
+ {
+ if (!showFeatureOfType(type))
+ {
+ String msg = MessageManager.formatMessage("label.warning_hidden",
+ MessageManager.getString("label.feature_type"), type);
+ JvOptionPane.showMessageDialog(panel, msg, "",
+ JvOptionPane.OK_OPTION);
+ }
+ }
+ }
+
+ /**
+ * Show a warning message if the entered group is one that is currently hidden
+ *
+ * @param panel
+ * @param group
+ */
+ protected void warnIfGroupHidden(JPanel panel, String group)
+ {
+ if (featureGroups.containsKey(group) && !featureGroups.get(group))
+ {
+ String msg = MessageManager.formatMessage("label.warning_hidden",
+ MessageManager.getString("label.group"), group);
+ JvOptionPane.showMessageDialog(panel, msg, "", JvOptionPane.OK_OPTION);
+ }
+ }
+
+ /**
* update the amend feature button dependent on the given style
*
* @param bigPanel
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
+import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
JPanel transPanel = new JPanel(new GridLayout(1, 2));
+ private static final int MIN_WIDTH = 400;
+
+ private static final int MIN_HEIGHT = 400;
+
+ /**
+ * Constructor
+ *
+ * @param af
+ */
public FeatureSettings(AlignFrame af)
{
this.af = af;
MessageManager.getString("label.sequence_feature_settings"),
400, 450);
}
+ frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
{
{
boolean visible = fr.checkGroupVisibility(group, true);
- if (groupPanel == null)
- {
- groupPanel = new JPanel();
- }
-
- boolean alreadyAdded = false;
for (int g = 0; g < groupPanel.getComponentCount(); g++)
{
if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
{
- alreadyAdded = true;
((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
- break;
+ return visible;
}
}
- if (alreadyAdded)
- {
-
- return visible;
- }
final String grp = group;
final JCheckBox check = new JCheckBox(group, visible);
check.setFont(new Font("Serif", Font.BOLD, 12));
SequenceFeature[] tmpfeatures;
String group = null, type;
Vector<String> visibleChecks = new Vector<String>();
+ Set<String> foundGroups = new HashSet<String>();
// Find out which features should be visible depending on which groups
// are selected / deselected
while (index < tmpfeatures.length)
{
group = tmpfeatures[index].featureGroup;
+ foundGroups.add(group);
if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
{
System.arraycopy(data[i], 0, originalData[i], 0, 3);
}
}
+ else
+ {
+ updateOriginalData(data);
+ }
table.setModel(new FeatureTableModel(data));
table.getColumnModel().getColumn(0).setPreferredWidth(200);
- if (groupPanel != null)
- {
- groupPanel.setLayout(new GridLayout(
- fr.getFeatureGroupsSize() / 4 + 1, 4));
-
- groupPanel.validate();
- bigPanel.add(groupPanel, BorderLayout.NORTH);
- }
+ groupPanel.setLayout(new GridLayout(fr.getFeatureGroupsSize() / 4 + 1,
+ 4));
+ pruneGroups(foundGroups);
+ groupPanel.validate();
updateFeatureRenderer(data, groupChanged != null);
resettingTable = false;
}
/**
+ * Updates 'originalData' (used for restore on Cancel) if we detect that
+ * changes have been made outwith this dialog
+ * <ul>
+ * <li>a new feature type added (and made visible)</li>
+ * <li>a feature colour changed (in the Amend Features dialog)</li>
+ * </ul>
+ *
+ * @param foundData
+ */
+ protected void updateOriginalData(Object[][] foundData)
+ {
+ // todo LinkedHashMap instead of Object[][] would be nice
+
+ Object[][] currentData = ((FeatureTableModel) table.getModel())
+ .getData();
+ for (Object[] row : foundData)
+ {
+ String type = (String) row[0];
+ boolean found = false;
+ for (Object[] current : currentData)
+ {
+ if (type.equals(current[0]))
+ {
+ found = true;
+ /*
+ * currently dependent on object equality here;
+ * really need an equals method on FeatureColour
+ */
+ if (!row[1].equals(current[1]))
+ {
+ /*
+ * feature colour has changed externally - update originalData
+ */
+ for (Object[] original : originalData)
+ {
+ if (type.equals(original[0]))
+ {
+ original[1] = row[1];
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ if (!found)
+ {
+ /*
+ * new feature detected - add to original data (on top)
+ */
+ Object[][] newData = new Object[originalData.length + 1][3];
+ for (int i = 0; i < originalData.length; i++)
+ {
+ System.arraycopy(originalData[i], 0, newData[i + 1], 0, 3);
+ }
+ newData[0] = row;
+ originalData = newData;
+ }
+ }
+ }
+
+ /**
+ * Remove from the groups panel any checkboxes for groups that are not in the
+ * foundGroups set. This enables removing a group from the display when the
+ * last feature in that group is deleted.
+ *
+ * @param foundGroups
+ */
+ protected void pruneGroups(Set<String> foundGroups)
+ {
+ for (int g = 0; g < groupPanel.getComponentCount(); g++)
+ {
+ JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g);
+ if (!foundGroups.contains(checkbox.getText()))
+ {
+ groupPanel.remove(checkbox);
+ }
+ }
+ }
+
+ /**
* reorder data based on the featureRenderers global priority list.
*
* @param data
settingsPane.setLayout(borderLayout2);
dasSettingsPane.setLayout(borderLayout3);
bigPanel.setLayout(borderLayout4);
+
+ groupPanel = new JPanel();
+ bigPanel.add(groupPanel, BorderLayout.NORTH);
+
invert.setFont(JvSwingUtils.getLabelFont());
invert.setText(MessageManager.getString("label.invert_selection"));
invert.addActionListener(new ActionListener()
import jalview.util.MessageManager;
import jalview.viewmodel.AlignmentViewport;
+import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Vector;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.JComponent;
import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
-import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
+import javax.swing.event.InternalFrameEvent;
/**
* Performs the menu option for searching the alignment, for the next or all
*/
public class Finder extends GFinder
{
- private static final int HEIGHT = 110;
+ private static final int MY_HEIGHT = 120;
- private static final int WIDTH = 340;
+ private static final int MY_WIDTH = 400;
AlignmentViewport av;
AlignmentPanel ap;
+ private static final int MIN_WIDTH = 350;
+
+ private static final int MIN_HEIGHT = 120;
+
JInternalFrame frame;
int seqIndex = 0;
frame = new JInternalFrame();
frame.setContentPane(this);
frame.setLayer(JLayeredPane.PALETTE_LAYER);
+ frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
+ {
+ @Override
+ public void internalFrameClosing(InternalFrameEvent e)
+ {
+ closeAction();
+ }
+ });
addEscapeHandler();
Desktop.addInternalFrame(frame, MessageManager.getString("label.find"),
- WIDTH, HEIGHT);
-
- textfield.requestFocus();
+ MY_WIDTH, MY_HEIGHT);
+ frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
+ searchBox.requestFocus();
}
/**
@Override
public void actionPerformed(ActionEvent e)
{
- escapeActionPerformed();
+ closeAction();
}
});
}
- /**
- * Close the panel on Escape key press
- */
- protected void escapeActionPerformed()
- {
- setVisible(false);
- frame.dispose();
- }
/**
* Performs the 'Find Next' action.
JInternalFrame[] frames = Desktop.desktop.getAllFrames();
for (int f = 0; f < frames.length; f++)
{
- JInternalFrame frame = frames[f];
- if (frame != null && frame instanceof AlignFrame)
+ JInternalFrame alignFrame = frames[f];
+ if (alignFrame != null && alignFrame instanceof AlignFrame)
{
- av = ((AlignFrame) frame).viewport;
- ap = ((AlignFrame) frame).alignPanel;
+ av = ((AlignFrame) alignFrame).viewport;
+ ap = ((AlignFrame) alignFrame).alignPanel;
return true;
}
}
}
/**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
+ * Opens a dialog that allows the user to create sequence features for the
+ * find match results.
*/
@Override
- public void createNewGroup_actionPerformed(ActionEvent e)
+ public void createFeatures_actionPerformed()
{
- SequenceI[] seqs = new SequenceI[searchResults.getSize()];
- SequenceFeature[] features = new SequenceFeature[searchResults
- .getSize()];
+ List<SequenceI> seqs = new ArrayList<SequenceI>();
+ List<SequenceFeature> features = new ArrayList<SequenceFeature>();
+
+ String searchString = searchBox.getEditor().getItem().toString().trim();
+ String desc = "Search Results";
- int i = 0;
+ /*
+ * assemble dataset sequences, and template new sequence features,
+ * for the amend features dialog
+ */
for (SearchResultMatchI match : searchResults.getResults())
{
- seqs[i] = match.getSequence().getDatasetSequence();
-
- features[i] = new SequenceFeature(textfield.getText().trim(),
- "Search Results", null, match.getStart(), match.getEnd(),
- "Search Results");
- i++;
+ seqs.add(match.getSequence().getDatasetSequence());
+ features.add(new SequenceFeature(searchString, desc, null, match
+ .getStart(), match.getEnd(), desc));
}
if (ap.getSeqPanel().seqCanvas.getFeatureRenderer().amendFeatures(seqs,
features, true, ap))
{
+ /*
+ * ensure feature display is turned on to show the new features,
+ * and remove them as highlighted regions
+ */
ap.alignFrame.showSeqFeatures.setSelected(true);
av.setShowSequenceFeatures(true);
ap.highlightSearchResults(null);
* Search the alignment for the next or all matches. If 'all matches', a
* dialog is shown with the number of sequence ids and subsequences matched.
*
- * @param findAll
+ * @param doFindAll
*/
- void doSearch(boolean findAll)
+ void doSearch(boolean doFindAll)
{
- createNewGroup.setEnabled(false);
+ createFeatures.setEnabled(false);
- String searchString = textfield.getText().trim();
+ String searchString = searchBox.getUserInput().trim();
if (isInvalidSearchString(searchString))
{
finder.setCaseSensitive(caseSensitive.isSelected());
finder.setIncludeDescription(searchDescription.isSelected());
- finder.setFindAll(findAll);
+ finder.setFindAll(doFindAll);
finder.find(searchString); // returns true if anything was actually found
if (searchResults.getSize() > 0)
{
haveResults = true;
- createNewGroup.setEnabled(true);
+ createFeatures.setEnabled(true);
}
else
{
}
else
{
- if (findAll)
+ if (doFindAll)
{
// then we report the matches that were found
String message = (idMatch.size() > 0) ? "" + idMatch.size()
seqIndex = 0;
}
}
-
+ searchBox.updateCache();
}
/**
}
return error;
}
+
+ protected void closeAction()
+ {
+ frame.setVisible(false);
+ frame.dispose();
+ searchBox.persistCache();
+ if (getFocusedViewport())
+ {
+ ap.alignFrame.requestFocus();
+ }
+ }
}
import java.awt.Font;
import java.awt.FontMetrics;
-import java.awt.event.ActionEvent;
import java.awt.geom.Rectangle2D;
import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
-import javax.swing.JOptionPane;
/**
* DOCUMENT ME!
*/
Font oldFont;
+ /*
+ * The font on opening the dialog (to be restored on Cancel)
+ * on the other half of a split frame (if applicable)
+ */
+ Font oldComplementFont;
+
+ /*
+ * the state of 'scale protein as cDNA' on opening the dialog
+ */
boolean oldProteinScale;
+ /*
+ * the state of 'same font for protein and cDNA' on opening the dialog
+ */
+ boolean oldMirrorFont;
+
boolean init = true;
JInternalFrame frame;
private boolean lastSelMono = false;
+ private boolean oldSmoothFont;
+
+ private boolean oldComplementSmooth;
+
/**
- * Creates a new FontChooser object.
+ * Creates a new FontChooser for a tree panel
*
- * @param ap
- * DOCUMENT ME!
+ * @param treePanel
*/
- public FontChooser(TreePanel tp)
+ public FontChooser(TreePanel treePanel)
{
- this.tp = tp;
- ap = tp.treeCanvas.ap;
- oldFont = tp.getTreeFont();
+ this.tp = treePanel;
+ ap = treePanel.treeCanvas.ap;
+ oldFont = treePanel.getTreeFont();
defaultButton.setVisible(false);
smoothFont.setEnabled(false);
init();
}
/**
- * Creates a new FontChooser object.
+ * Creates a new FontChooser for an alignment panel
*
- * @param ap
- * DOCUMENT ME!
+ * @param alignPanel
*/
- public FontChooser(AlignmentPanel ap)
+ public FontChooser(AlignmentPanel alignPanel)
{
- oldFont = ap.av.getFont();
- oldProteinScale = ap.av.isScaleProteinAsCdna();
-
- this.ap = ap;
+ oldFont = alignPanel.av.getFont();
+ oldProteinScale = alignPanel.av.isScaleProteinAsCdna();
+ oldMirrorFont = alignPanel.av.isProteinFontAsCdna();
+ oldSmoothFont = alignPanel.av.antiAlias;
+ this.ap = alignPanel;
init();
}
/*
* Enable 'scale protein as cDNA' in a SplitFrame view. The selection is
- * stored in the ViewStyle of both dna and protein Viewport
+ * stored in the ViewStyle of both dna and protein Viewport. Also enable
+ * checkbox for copy font changes to other half of split frame.
*/
- scaleAsCdna.setEnabled(false);
- if (ap.av.getCodingComplement() != null)
+ boolean inSplitFrame = ap.av.getCodingComplement() != null;
+ if (inSplitFrame)
{
- scaleAsCdna.setEnabled(true);
+ oldComplementFont = ((AlignViewport) ap.av.getCodingComplement())
+ .getFont();
+ oldComplementSmooth = ((AlignViewport) ap.av.getCodingComplement()).antiAlias;
scaleAsCdna.setVisible(true);
scaleAsCdna.setSelected(ap.av.isScaleProteinAsCdna());
+ fontAsCdna.setVisible(true);
+ fontAsCdna.setSelected(ap.av.isProteinFontAsCdna());
}
if (tp != null)
else
{
Desktop.addInternalFrame(frame,
- MessageManager.getString("action.change_font"), 380, 200,
+ MessageManager.getString("action.change_font"), 380, 220,
false);
}
}
@Override
- public void smoothFont_actionPerformed(ActionEvent e)
+ protected void smoothFont_actionPerformed()
{
ap.av.antiAlias = smoothFont.isSelected();
ap.getAnnotationPanel().image = null;
ap.paintAlignment(true);
+ if (ap.av.getCodingComplement() != null && ap.av.isProteinFontAsCdna())
+ {
+ ((AlignViewport) ap.av.getCodingComplement()).antiAlias = ap.av.antiAlias;
+ SplitFrame sv = (SplitFrame) ap.alignFrame.getSplitViewContainer();
+ sv.adjustLayout();
+ sv.repaint();
+ }
+
}
/**
* DOCUMENT ME!
*/
@Override
- protected void ok_actionPerformed(ActionEvent e)
+ protected void ok_actionPerformed()
{
try
{
* DOCUMENT ME!
*/
@Override
- protected void cancel_actionPerformed(ActionEvent e)
+ protected void cancel_actionPerformed()
{
if (ap != null)
{
ap.av.setFont(oldFont, true);
ap.av.setScaleProteinAsCdna(oldProteinScale);
+ ap.av.setProteinFontAsCdna(oldMirrorFont);
+ ap.av.antiAlias = oldSmoothFont;
ap.paintAlignment(true);
- if (scaleAsCdna.isEnabled())
+
+ if (scaleAsCdna.isVisible() && scaleAsCdna.isEnabled())
{
- ap.av.setScaleProteinAsCdna(oldProteinScale);
ap.av.getCodingComplement().setScaleProteinAsCdna(oldProteinScale);
+ ap.av.getCodingComplement().setProteinFontAsCdna(oldMirrorFont);
+ ((AlignViewport) ap.av.getCodingComplement()).antiAlias = oldComplementSmooth;
+ ap.av.getCodingComplement().setFont(oldComplementFont, true);
+ SplitFrame splitFrame = (SplitFrame) ap.alignFrame
+ .getSplitViewContainer();
+ splitFrame.adjustLayout();
+ splitFrame.repaint();
}
}
else if (tp != null)
{
tp.setTreeFont(oldFont);
}
- fontName.setSelectedItem(oldFont.getName());
- fontSize.setSelectedItem(oldFont.getSize());
- fontStyle.setSelectedIndex(oldFont.getStyle());
try
{
{
ap.av.setFont(newFont, true);
ap.fontChanged();
+
+ /*
+ * adjust other half of split frame if any, if either same
+ * font, or proportionate scaling, is selected
+ */
+ if (fontAsCdna.isEnabled())
+ {
+ if (fontAsCdna.isSelected())
+ {
+ /*
+ * copy the font
+ */
+ ap.av.getCodingComplement().setFont(newFont, true);
+ }
+
+ /*
+ * adjust layout for font change / reset / sizing
+ */
+ SplitFrame splitFrame = (SplitFrame) ap.alignFrame
+ .getSplitViewContainer();
+ splitFrame.adjustLayout();
+ splitFrame.repaint();
+ }
}
monospaced.setSelected(mw == iw);
}
/**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
+ * Updates on change of selected font name
*/
@Override
- protected void fontName_actionPerformed(ActionEvent e)
+ protected void fontName_actionPerformed()
{
if (init)
{
}
/**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
+ * Updates on change of selected font size
*/
@Override
- protected void fontSize_actionPerformed(ActionEvent e)
+ protected void fontSize_actionPerformed()
{
if (init)
{
}
/**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
+ * Updates on change of selected font style
*/
@Override
- protected void fontStyle_actionPerformed(ActionEvent e)
+ protected void fontStyle_actionPerformed()
{
if (init)
{
/**
* Make selected settings the defaults by storing them (via Cache class) in
* the .jalview_properties file (the file is only written when Jalview exits)
- *
- * @param e
*/
@Override
- public void defaultButton_actionPerformed(ActionEvent e)
+ public void defaultButton_actionPerformed()
{
Cache.setProperty("FONT_NAME", fontName.getSelectedItem().toString());
Cache.setProperty("FONT_STYLE", fontStyle.getSelectedIndex() + "");
* characters
*/
@Override
- protected void scaleAsCdna_actionPerformed(ActionEvent e)
+ protected void scaleAsCdna_actionPerformed()
{
ap.av.setScaleProteinAsCdna(scaleAsCdna.isSelected());
ap.av.getCodingComplement().setScaleProteinAsCdna(
.getSplitViewContainer();
splitFrame.adjustLayout();
splitFrame.repaint();
- // ap.paintAlignment(true);
- // TODO would like to repaint
+ }
+
+ /**
+ * Turn on/off mirroring of font across split frame. If turning on, also
+ * copies the current font across the split frame. If turning off, restores
+ * the other half of the split frame to its initial font.
+ */
+ @Override
+ protected void mirrorFonts_actionPerformed()
+ {
+ boolean selected = fontAsCdna.isSelected();
+ ap.av.setProteinFontAsCdna(selected);
+ ap.av.getCodingComplement().setProteinFontAsCdna(selected);
+
+ /*
+ * reset other half of split frame if turning option off
+ */
+ if (!selected)
+ {
+ ap.av.getCodingComplement().setFont(oldComplementFont, true);
+ }
+
+ changeFont();
}
}
package jalview.gui;
import jalview.datamodel.SequenceI;
+import jalview.viewmodel.ViewportListenerI;
+import jalview.viewmodel.ViewportRanges;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeEvent;
import java.util.List;
import javax.swing.JPanel;
* @author $author$
* @version $Revision$
*/
-public class IdCanvas extends JPanel
+public class IdCanvas extends JPanel implements ViewportListenerI
{
protected AlignViewport av;
setLayout(new BorderLayout());
this.av = av;
PaintRefresher.Register(this, av.getSequenceSetId());
+ av.getRanges().addPropertyChangeListener(this);
}
/**
return;
}
+ ViewportRanges ranges = av.getRanges();
+
gg.copyArea(0, 0, getWidth(), imgHeight, 0,
-vertical * av.getCharHeight());
- int ss = av.startSeq;
- int es = av.endSeq;
+ int ss = ranges.getStartSeq();
+ int es = ranges.getEndSeq();
int transY = 0;
if (vertical > 0) // scroll down
{
ss = es - vertical;
- if (ss < av.startSeq)
+ if (ss < ranges.getStartSeq())
{ // ie scrolling too fast, more than a page at a time
- ss = av.startSeq;
+ ss = ranges.getStartSeq();
}
else
{
- transY = imgHeight - (vertical * av.getCharHeight());
+ transY = imgHeight - ((vertical + 1) * av.getCharHeight());
}
}
- else if (vertical < 0)
+ else if (vertical < 0) // scroll up
{
es = ss - vertical;
- if (es > av.endSeq)
+ if (es > ranges.getEndSeq())
{
- es = av.endSeq;
+ es = ranges.getEndSeq();
}
}
gg.setColor(Color.white);
gg.fillRect(0, 0, getWidth(), imgHeight);
- drawIds(av.getStartSeq(), av.endSeq);
+ drawIds(av.getRanges().getStartSeq(), av.getRanges().getEndSeq());
g.drawImage(image, 0, 0, this);
}
if (av.hasHiddenColumns())
{
- maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+ maxwidth = av.getAlignment().getHiddenColumns()
+ .findColumnPosition(maxwidth) - 1;
}
int annotationHeight = 0;
int cHeight = alheight * av.getCharHeight() + hgap + annotationHeight;
- int rowSize = av.getEndRes() - av.getStartRes();
+ int rowSize = av.getRanges().getEndRes()
+ - av.getRanges().getStartRes();
// Draw the rest of the panels
- for (int ypos = hgap, row = av.startRes; (ypos <= getHeight())
+ for (int ypos = hgap, row = av.getRanges().getStartRes(); (ypos <= getHeight())
&& (row < maxwidth); ypos += cHeight, row += rowSize)
{
for (int i = starty; i < alheight; i++)
SequenceI sequence;
// Now draw the id strings
- for (int i = starty; i < endy; i++)
+ for (int i = starty; i <= endy; i++)
{
sequence = av.getAlignment().getSequenceAt(i);
{
this.idfont = idfont;
}
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ // Respond to viewport range changes (e.g. alignment panel was scrolled)
+ if (evt.getPropertyName().equals("startseq")
+ || evt.getPropertyName().equals("endseq"))
+ {
+ fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
+ }
+ }
}
{
if (e.isShiftDown())
{
- alignPanel.scrollRight(true);
+ av.getRanges().scrollRight(true);
}
else
{
- alignPanel.scrollUp(false);
+ av.getRanges().scrollUp(false);
}
}
else
{
if (e.isShiftDown())
{
- alignPanel.scrollRight(false);
+ av.getRanges().scrollRight(false);
}
else
{
- alignPanel.scrollUp(true);
+ av.getRanges().scrollUp(true);
}
}
}
return;
}
- if (mouseDragging && (e.getY() < 0) && (av.getStartSeq() > 0))
+ if (mouseDragging && (e.getY() < 0)
+ && (av.getRanges().getStartSeq() > 0))
{
scrollThread = new ScrollThread(true);
}
if (mouseDragging && (e.getY() >= getHeight())
- && (av.getAlignment().getHeight() > av.getEndSeq()))
+ && (av.getAlignment().getHeight() > av.getRanges().getEndSeq()))
{
scrollThread = new ScrollThread(false);
}
int index = av.getAlignment().findIndex(list.get(0));
// do we need to scroll the panel?
- if ((av.getStartSeq() > index) || (av.getEndSeq() < index))
+ if ((av.getRanges().getStartSeq() > index)
+ || (av.getRanges().getEndSeq() < index))
{
- alignPanel.setScrollValues(av.getStartRes(), index);
+ av.getRanges().setStartSeq(index);
}
}
while (running)
{
- if (alignPanel.scrollUp(up))
+ if (av.getRanges().scrollUp(up))
{
// scroll was ok, so add new sequence to selection
- int seq = av.getStartSeq();
+ int seq = av.getRanges().getStartSeq();
if (!up)
{
- seq = av.getEndSeq();
+ seq = av.getRanges().getEndSeq();
}
if (seq < lastid)
private JLabel dbstatus, dbstatex;
+ private JPanel mainPanel = new JPanel(new BorderLayout());
+
public JDatabaseTree(jalview.ws.SequenceFetcher sfetch)
{
- initDialogFrame(this, true, false,
+ mainPanel.add(this);
+ initDialogFrame(mainPanel, true, false,
MessageManager
.getString("label.select_database_retrieval_source"),
650, 490);
}
// and sort the tree
sortTreeNodes(root);
- svp = new JScrollPane();
- // svp.setAutoscrolls(true);
dbviews = new JTree(new DefaultTreeModel(root, false));
dbviews.setCellRenderer(new DbTreeRenderer(this));
dbviews.getSelectionModel().setSelectionMode(
TreeSelectionModel.SINGLE_TREE_SELECTION);
- svp.getViewport().setView(dbviews);
- // svp.getViewport().setMinimumSize(new Dimension(300,200));
- // svp.setSize(300,250);
- // JPanel panel=new JPanel();
- // panel.setSize(new Dimension(350,220));
- // panel.add(svp);
+ svp = new JScrollPane(dbviews);
+ svp.setMinimumSize(new Dimension(100, 200));
+ svp.setPreferredSize(new Dimension(200, 400));
+ svp.setMaximumSize(new Dimension(300, 600));
+
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.setSize(new Dimension(350, 220));
+ panel.add(svp);
dbviews.addTreeSelectionListener(new TreeSelectionListener()
{
dbstat.add(dbstatex);
jc.add(dbstat, BorderLayout.SOUTH);
jc.validate();
- // j.setPreferredSize(new Dimension(300,50));
add(jc, BorderLayout.CENTER);
ok.setEnabled(false);
j.add(ok);
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.GraphLine;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.RnaViewerModel;
import jalview.datamodel.SequenceGroup;
import jalview.schemes.ColourSchemeI;
import jalview.schemes.ColourSchemeProperty;
import jalview.schemes.FeatureColour;
-import jalview.schemes.ResidueColourScheme;
import jalview.schemes.ResidueProperties;
import jalview.schemes.UserColourScheme;
import jalview.structure.StructureSelectionManager;
import jalview.util.StringUtils;
import jalview.util.jarInputStreamProvider;
import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
import jalview.ws.jws2.Jws2Discoverer;
List<UserColourScheme> userColours = new ArrayList<UserColourScheme>();
AlignViewport av = ap.av;
+ ViewportRanges vpRanges = av.getRanges();
JalviewModel object = new JalviewModel();
object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel());
Tree tree = new Tree();
tree.setTitle(tp.getTitle());
tree.setCurrentTree((av.currentTree == tp.getTree()));
- tree.setNewick(tp.getTree().toString());
+ tree.setNewick(tp.getTree().print());
tree.setThreshold(tp.treeCanvas.threshold);
tree.setFitToWindow(tp.fitToWindow.getState());
view.setWidth(size.width);
view.setHeight(size.height);
- view.setStartRes(av.startRes);
- view.setStartSeq(av.startSeq);
+ view.setStartRes(vpRanges.getStartRes());
+ view.setStartSeq(vpRanges.getStartSeq());
if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme)
{
if (av.hasHiddenColumns())
{
- if (av.getColumnSelection() == null
- || av.getColumnSelection().getHiddenColumns() == null)
+ jalview.datamodel.HiddenColumns hidden = av.getAlignment()
+ .getHiddenColumns();
+ if (hidden == null || hidden.getHiddenRegions() == null)
{
warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
}
else
{
- for (int c = 0; c < av.getColumnSelection().getHiddenColumns()
+ for (int c = 0; c < hidden.getHiddenRegions()
.size(); c++)
{
- int[] region = av.getColumnSelection().getHiddenColumns()
+ int[] region = hidden.getHiddenRegions()
.get(c);
HiddenColumns hc = new HiddenColumns();
hc.setStart(region[0]);
return matchedFile;
}
+ /**
+ * Populates the AnnotationColours xml for save. This captures the settings of
+ * the options in the 'Colour by Annotation' dialog.
+ *
+ * @param acg
+ * @param userColours
+ * @param jms
+ * @return
+ */
private AnnotationColours constructAnnotationColours(
AnnotationColourGradient acg, List<UserColourScheme> userColours,
JalviewModelSequence jms)
AnnotationColours ac = new AnnotationColours();
ac.setAboveThreshold(acg.getAboveThreshold());
ac.setThreshold(acg.getAnnotationThreshold());
- ac.setAnnotation(acg.getAnnotation());
- if (acg.getBaseColour() instanceof jalview.schemes.UserColourScheme)
+ // 2.10.2 save annotationId (unique) not annotation label
+ ac.setAnnotation(acg.getAnnotation().annotationId);
+ if (acg.getBaseColour() instanceof UserColourScheme)
{
ac.setColourScheme(setUserColourScheme(acg.getBaseColour(),
userColours, jms));
@Override
public void run()
{
- JvOptionPane.showInternalMessageDialog(Desktop.desktop,
- finalErrorMessage, "Error "
- + (saving ? "saving" : "loading")
- + " Jalview file", JvOptionPane.WARNING_MESSAGE);
+ JvOptionPane
+ .showInternalMessageDialog(Desktop.desktop,
+ finalErrorMessage, "Error "
+ + (saving ? "saving" : "loading")
+ + " Jalview file",
+ JvOptionPane.WARNING_MESSAGE);
}
});
}
TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
if (tp == null)
{
- tp = af.ShowNewickTree(
+ tp = af.showNewickTree(
new jalview.io.NewickFile(tree.getNewick()),
tree.getTitle(), tree.getWidth(), tree.getHeight(),
tree.getXpos(), tree.getYpos());
af.viewport.setThresholdTextColour(view.getTextColThreshold());
af.viewport.setShowUnconserved(view.hasShowUnconserved() ? view
.isShowUnconserved() : false);
- af.viewport.setStartRes(view.getStartRes());
- af.viewport.setStartSeq(view.getStartSeq());
+ af.viewport.getRanges().setStartRes(view.getStartRes());
+ // startSeq set in af.alignPanel.updateLayout below
af.alignPanel.updateLayout();
ColourSchemeI cs = null;
// apply colourschemes
return af;
}
+ /**
+ * Reads saved data to restore Colour by Annotation settings
+ *
+ * @param viewAnnColour
+ * @param af
+ * @param al
+ * @param jms
+ * @param checkGroupAnnColour
+ * @return
+ */
private ColourSchemeI constructAnnotationColour(
AnnotationColours viewAnnColour, AlignFrame af, AlignmentI al,
JalviewModelSequence jms, boolean checkGroupAnnColour)
{
boolean propagateAnnColour = false;
- ColourSchemeI cs = null;
AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al;
if (checkGroupAnnColour && al.getGroups() != null
&& al.getGroups().size() > 0)
// pre 2.8.1 behaviour
// check to see if we should transfer annotation colours
propagateAnnColour = true;
- for (jalview.datamodel.SequenceGroup sg : al.getGroups())
+ for (SequenceGroup sg : al.getGroups())
{
if (sg.getColourScheme() instanceof AnnotationColourGradient)
{
}
}
}
- // int find annotation
- if (annAlignment.getAlignmentAnnotation() != null)
+
+ /*
+ * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
+ */
+ String annotationId = viewAnnColour.getAnnotation();
+ AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
+
+ /*
+ * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
+ */
+ if (matchedAnnotation == null && annAlignment.getAlignmentAnnotation() != null)
{
for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
{
- if (annAlignment.getAlignmentAnnotation()[i].label
- .equals(viewAnnColour.getAnnotation()))
+ if (annotationId
+ .equals(annAlignment.getAlignmentAnnotation()[i].label))
{
- if (annAlignment.getAlignmentAnnotation()[i].getThreshold() == null)
- {
- annAlignment.getAlignmentAnnotation()[i]
- .setThreshold(new jalview.datamodel.GraphLine(
- viewAnnColour.getThreshold(), "Threshold",
- java.awt.Color.black)
-
- );
- }
-
- if (viewAnnColour.getColourScheme().equals(
- ResidueColourScheme.NONE))
- {
- cs = new AnnotationColourGradient(
- annAlignment.getAlignmentAnnotation()[i],
- new java.awt.Color(viewAnnColour.getMinColour()),
- new java.awt.Color(viewAnnColour.getMaxColour()),
- viewAnnColour.getAboveThreshold());
- }
- else if (viewAnnColour.getColourScheme().startsWith("ucs"))
- {
- cs = new AnnotationColourGradient(
- annAlignment.getAlignmentAnnotation()[i],
- getUserColourScheme(jms,
- viewAnnColour.getColourScheme()),
- viewAnnColour.getAboveThreshold());
- }
- else
- {
- cs = new AnnotationColourGradient(
- annAlignment.getAlignmentAnnotation()[i],
- ColourSchemeProperty.getColourScheme(al,
- viewAnnColour.getColourScheme()),
- viewAnnColour.getAboveThreshold());
- }
- if (viewAnnColour.hasPerSequence())
- {
- ((AnnotationColourGradient) cs).setSeqAssociated(viewAnnColour
- .isPerSequence());
- }
- if (viewAnnColour.hasPredefinedColours())
- {
- ((AnnotationColourGradient) cs)
- .setPredefinedColours(viewAnnColour
- .isPredefinedColours());
- }
- if (propagateAnnColour && al.getGroups() != null)
- {
- // Also use these settings for all the groups
- for (int g = 0; g < al.getGroups().size(); g++)
- {
- jalview.datamodel.SequenceGroup sg = al.getGroups().get(g);
-
- if (sg.cs == null)
- {
- continue;
- }
+ matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
+ break;
+ }
+ }
+ }
+ if (matchedAnnotation == null)
+ {
+ System.err.println("Failed to match annotation colour scheme for "
+ + annotationId);
+ return null;
+ }
+ if (matchedAnnotation.getThreshold() == null)
+ {
+ matchedAnnotation.setThreshold(new GraphLine(viewAnnColour.getThreshold(),
+ "Threshold", Color.black));
+ }
- /*
- * if (viewAnnColour.getColourScheme().equals(ResidueColourScheme.NONE)) { sg.cs =
- * new AnnotationColourGradient(
- * annAlignment.getAlignmentAnnotation()[i], new
- * java.awt.Color(viewAnnColour. getMinColour()), new
- * java.awt.Color(viewAnnColour. getMaxColour()),
- * viewAnnColour.getAboveThreshold()); } else
- */
- {
- sg.setColourScheme(new AnnotationColourGradient(
- annAlignment.getAlignmentAnnotation()[i], sg
- .getColourScheme(), viewAnnColour
- .getAboveThreshold()));
- if (cs instanceof AnnotationColourGradient)
- {
- if (viewAnnColour.hasPerSequence())
- {
- ((AnnotationColourGradient) cs)
- .setSeqAssociated(viewAnnColour.isPerSequence());
- }
- if (viewAnnColour.hasPredefinedColours())
- {
- ((AnnotationColourGradient) cs)
- .setPredefinedColours(viewAnnColour
- .isPredefinedColours());
- }
- }
- }
+ AnnotationColourGradient cs = null;
+ if (viewAnnColour.getColourScheme().equals("None"))
+ {
+ cs = new AnnotationColourGradient(matchedAnnotation, new Color(
+ viewAnnColour.getMinColour()), new Color(
+ viewAnnColour.getMaxColour()),
+ viewAnnColour.getAboveThreshold());
+ }
+ else if (viewAnnColour.getColourScheme().startsWith("ucs"))
+ {
+ cs = new AnnotationColourGradient(matchedAnnotation, getUserColourScheme(
+ jms, viewAnnColour.getColourScheme()),
+ viewAnnColour.getAboveThreshold());
+ }
+ else
+ {
+ cs = new AnnotationColourGradient(matchedAnnotation,
+ ColourSchemeProperty.getColourScheme(al,
+ viewAnnColour.getColourScheme()),
+ viewAnnColour.getAboveThreshold());
+ }
- }
- }
+ boolean perSequenceOnly = viewAnnColour.isPerSequence();
+ boolean useOriginalColours = viewAnnColour.isPredefinedColours();
+ cs.setSeqAssociated(perSequenceOnly);
+ cs.setPredefinedColours(useOriginalColours);
- break;
+ if (propagateAnnColour && al.getGroups() != null)
+ {
+ // Also use these settings for all the groups
+ for (int g = 0; g < al.getGroups().size(); g++)
+ {
+ SequenceGroup sg = al.getGroups().get(g);
+ if (sg.getGroupColourScheme() == null)
+ {
+ continue;
}
+ AnnotationColourGradient groupScheme = new AnnotationColourGradient(
+ matchedAnnotation, sg.getColourScheme(),
+ viewAnnColour.getAboveThreshold());
+ sg.setColourScheme(groupScheme);
+ groupScheme.setSeqAssociated(perSequenceOnly);
+ groupScheme.setPredefinedColours(useOriginalColours);
}
}
return cs;
af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
view.getHeight());
- af.viewport.setStartRes(view.getStartRes());
- af.viewport.setStartSeq(view.getStartSeq());
+ af.viewport.getRanges().setStartRes(view.getStartRes());
+ // startSeq set in af.alignPanel.updateLayout below
af.viewport.setShowAnnotation(view.getShowAnnotation());
af.viewport.setAbovePIDThreshold(view.getPidSelected());
af.viewport.setColourText(view.getShowColourText());
Tree tree = jms.getTree(t);
- TreePanel tp = af.ShowNewickTree(
+ TreePanel tp = af.showNewickTree(
new jalview.io.NewickFile(tree.getNewick()),
tree.getTitle(), tree.getWidth(), tree.getHeight(),
tree.getXpos(), tree.getYpos());
import jalview.io.DataSourceType;
import jalview.structure.StructureSelectionManager;
+import javax.swing.SwingUtilities;
+
public class JalviewChimeraBindingModel extends JalviewChimeraBinding
{
private ChimeraViewFrame cvf;
- private FeatureRenderer fr = null;
-
-
public JalviewChimeraBindingModel(ChimeraViewFrame chimeraViewFrame,
StructureSelectionManager ssm, PDBEntry[] pdbentry,
SequenceI[][] sequenceIs, DataSourceType protocol)
: (AlignmentPanel) alignment;
if (ap.av.isShowSequenceFeatures())
{
- if (fr == null)
- {
- fr = (jalview.gui.FeatureRenderer) ap.cloneFeatureRenderer();
- }
- else
- {
- ap.updateFeatureRenderer(fr);
- }
+ return ap.getSeqPanel().seqCanvas.fr;
}
- return fr;
+ return null;
}
@Override
protected void sendAsynchronousCommand(final String command,
final String progressMsg)
{
- Thread thread = new Thread(new Runnable()
+ final long handle = progressMsg == null ? 0 : cvf
+ .startProgressBar(progressMsg);
+ SwingUtilities.invokeLater(new Runnable()
{
-
@Override
public void run()
{
- long stm = cvf.startProgressBar(progressMsg);
try
{
sendChimeraCommand(command, false);
} finally
{
- cvf.stopProgressBar(null, stm);
+ if (progressMsg != null)
+ {
+ cvf.stopProgressBar(null, handle);
+ }
}
}
});
- thread.start();
-
}
@Override
import jalview.util.MessageManager;
import java.awt.Container;
+import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
{
frame.setSize(width, height);
}
+ int minWidth = width - 100;
+ int minHeight = height - 100;
+ frame.setMinimumSize(new Dimension(minWidth, minHeight));
frame.setContentPane(content);
this.block = block;
--- /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.
+ */
+package jalview.gui;
+
+import jalview.api.AlignViewportI;
+import jalview.renderer.OverviewRenderer;
+import jalview.viewmodel.OverviewDimensions;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+
+import javax.swing.JComponent;
+
+public class OverviewCanvas extends JComponent
+{
+ private static final Color TRANS_GREY = new Color(100, 100, 100, 25);
+
+ // This is set true if the alignment view changes whilst
+ // the overview is being calculated
+ private volatile boolean restart = false;
+
+ private volatile boolean updaterunning = false;
+
+ private BufferedImage miniMe;
+
+ private BufferedImage lastMiniMe = null;
+
+ // Can set different properties in this seqCanvas than
+ // main visible SeqCanvas
+ private SequenceRenderer sr;
+
+ private jalview.renderer.seqfeatures.FeatureRenderer fr;
+
+ private OverviewDimensions od;
+
+ private AlignViewportI av;
+
+ public OverviewCanvas(OverviewDimensions overviewDims,
+ AlignViewportI alignvp)
+ {
+ od = overviewDims;
+ av = alignvp;
+
+ sr = new SequenceRenderer(av);
+ sr.renderGaps = false;
+ sr.forOverview = true;
+ fr = new jalview.renderer.seqfeatures.FeatureRenderer(av);
+ }
+
+ /**
+ * Update the overview dimensions object used by the canvas (e.g. if we change
+ * from showing hidden columns to hiding them or vice versa)
+ *
+ * @param overviewDims
+ */
+ public void resetOviewDims(OverviewDimensions overviewDims)
+ {
+ od = overviewDims;
+ }
+
+ /**
+ * Signals to drawing code that the associated alignment viewport has changed
+ * and a redraw will be required
+ */
+ public boolean restartDraw()
+ {
+ synchronized (this)
+ {
+ if (updaterunning)
+ {
+ restart = true;
+ }
+ else
+ {
+ updaterunning = true;
+ }
+ return restart;
+ }
+ }
+
+ /**
+ * Draw the overview sequences
+ *
+ * @param showSequenceFeatures
+ * true if sequence features are to be shown
+ * @param showAnnotation
+ * true if the annotation is to be shown
+ * @param transferRenderer
+ * the renderer to transfer feature colouring from
+ */
+ public void draw(boolean showSequenceFeatures, boolean showAnnotation,
+ FeatureRenderer transferRenderer)
+ {
+ miniMe = null;
+
+ if (showSequenceFeatures)
+ {
+ fr.transferSettings(transferRenderer);
+ }
+
+ setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
+
+ OverviewRenderer or = new OverviewRenderer(sr, fr, od);
+ miniMe = or.draw(od.getRows(av.getAlignment()),
+ od.getColumns(av.getAlignment()));
+
+ Graphics mg = miniMe.getGraphics();
+
+ if (showAnnotation)
+ {
+ mg.translate(0, od.getSequencesHeight());
+ or.drawGraph(mg, av.getAlignmentConservationAnnotation(),
+ av.getCharWidth(), od.getGraphHeight(),
+ od.getColumns(av.getAlignment()));
+ mg.translate(0, -od.getSequencesHeight());
+ }
+ System.gc();
+
+ if (restart)
+ {
+ restart = false;
+ draw(showSequenceFeatures, showAnnotation, transferRenderer);
+ }
+ else
+ {
+ updaterunning = false;
+ lastMiniMe = miniMe;
+ }
+ }
+
+ @Override
+ public void paintComponent(Graphics g)
+ {
+ if (restart)
+ {
+ if (lastMiniMe == null)
+ {
+ g.setColor(Color.white);
+ g.fillRect(0, 0, getWidth(), getHeight());
+ }
+ else
+ {
+ g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this);
+ }
+ g.setColor(TRANS_GREY);
+ g.fillRect(0, 0, getWidth(), getHeight());
+ }
+ else if (lastMiniMe != null)
+ {
+ g.drawImage(lastMiniMe, 0, 0, this);
+ if (lastMiniMe != miniMe)
+ {
+ g.setColor(TRANS_GREY);
+ g.fillRect(0, 0, getWidth(), getHeight());
+ }
+ }
+
+ g.setColor(Color.red);
+ od.drawBox(g);
+ }
+
+}
*/
package jalview.gui;
-import jalview.renderer.AnnotationRenderer;
-
-import java.awt.Color;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.viewmodel.OverviewDimensions;
+import jalview.viewmodel.OverviewDimensionsHideHidden;
+import jalview.viewmodel.OverviewDimensionsShowHidden;
+import jalview.viewmodel.ViewportListenerI;
+
+import java.awt.BorderLayout;
import java.awt.Dimension;
-import java.awt.Graphics;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
-import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeEvent;
+import javax.swing.JCheckBoxMenuItem;
import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
/**
- * DOCUMENT ME!
+ * Panel displaying an overview of the full alignment, with an interactive box
+ * representing the viewport onto the alignment.
*
* @author $author$
* @version $Revision$
*/
-public class OverviewPanel extends JPanel implements Runnable
+public class OverviewPanel extends JPanel implements Runnable,
+ ViewportListenerI
{
- BufferedImage miniMe;
-
- AlignViewport av;
-
- AlignmentPanel ap;
-
- final AnnotationRenderer renderer = new AnnotationRenderer();
-
- float scalew = 1f;
-
- float scaleh = 1f;
+ private OverviewDimensions od;
- int width;
+ private OverviewCanvas oviewCanvas;
- int sequencesHeight;
+ private AlignViewport av;
- int graphHeight = 20;
+ private AlignmentPanel ap;
- int boxX = -1;
+ private JCheckBoxMenuItem displayToggle;
- int boxY = -1;
-
- int boxWidth = -1;
-
- int boxHeight = -1;
-
- boolean resizing = false;
-
- // Can set different properties in this seqCanvas than
- // main visible SeqCanvas
- SequenceRenderer sr;
-
- jalview.renderer.seqfeatures.FeatureRenderer fr;
+ private boolean showHidden = true;
/**
* Creates a new OverviewPanel object.
*
- * @param ap
- * DOCUMENT ME!
+ * @param alPanel
+ * The alignment panel which is shown in the overview panel
*/
- public OverviewPanel(AlignmentPanel ap)
+ public OverviewPanel(AlignmentPanel alPanel)
{
- this.av = ap.av;
- this.ap = ap;
- setLayout(null);
+ this.av = alPanel.av;
+ this.ap = alPanel;
- sr = new SequenceRenderer(av);
- sr.renderGaps = false;
- sr.forOverview = true;
- fr = new FeatureRenderer(ap);
+ od = new OverviewDimensionsShowHidden(av.getRanges(),
+ (av.isShowAnnotation() && av
+ .getAlignmentConservationAnnotation() != null));
- // scale the initial size of overviewpanel to shape of alignment
- float initialScale = (float) av.getAlignment().getWidth()
- / (float) av.getAlignment().getHeight();
+ setSize(od.getWidth(), od.getHeight());
- if (av.getAlignmentConservationAnnotation() == null)
- {
- graphHeight = 0;
- }
+ oviewCanvas = new OverviewCanvas(od, av);
+ setLayout(new BorderLayout());
+ add(oviewCanvas, BorderLayout.CENTER);
- if (av.getAlignment().getWidth() > av.getAlignment().getHeight())
- {
- // wider
- width = 400;
- sequencesHeight = (int) (400f / initialScale);
- if (sequencesHeight < 40)
- {
- sequencesHeight = 40;
- }
- }
- else
- {
- // taller
- width = (int) (400f * initialScale);
- sequencesHeight = 300;
-
- if (width < 120)
- {
- width = 120;
- }
- }
+ av.getRanges().addPropertyChangeListener(this);
addComponentListener(new ComponentAdapter()
{
@Override
public void componentResized(ComponentEvent evt)
{
- if ((getWidth() != width)
- || (getHeight() != (sequencesHeight + graphHeight)))
+ if ((getWidth() != od.getWidth())
+ || (getHeight() != (od.getHeight())))
{
updateOverviewImage();
+ setBoxPosition();
}
}
});
@Override
public void mouseDragged(MouseEvent evt)
{
- if (!av.getWrapAlignment())
+ if (!SwingUtilities.isRightMouseButton(evt)
+ && !av.getWrapAlignment())
{
- // TODO: feature: jv2.5 detect shift drag and update selection from
- // it.
- boxX = evt.getX();
- boxY = evt.getY();
- checkValid();
+ od.updateViewportFromMouse(evt.getX(), evt.getY(), av
+ .getAlignment().getHiddenSequences(), av.getAlignment()
+ .getHiddenColumns());
+
}
}
});
@Override
public void mousePressed(MouseEvent evt)
{
- if (!av.getWrapAlignment())
+ if (SwingUtilities.isRightMouseButton(evt))
+ {
+ if (!Platform.isAMac())
+ {
+ showPopupMenu(evt);
+ }
+ }
+ else if (!av.getWrapAlignment())
+ {
+ od.updateViewportFromMouse(evt.getX(), evt.getY(), av
+ .getAlignment().getHiddenSequences(), av.getAlignment()
+ .getHiddenColumns());
+ }
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent evt)
+ {
+ if (SwingUtilities.isRightMouseButton(evt))
{
- boxX = evt.getX();
- boxY = evt.getY();
- checkValid();
+ showPopupMenu(evt);
}
}
});
+
updateOverviewImage();
}
- /**
- * DOCUMENT ME!
+ /*
+ * Displays the popup menu and acts on user input
*/
- void checkValid()
+ private void showPopupMenu(MouseEvent e)
{
- if (boxY < 0)
- {
- boxY = 0;
- }
-
- if (boxY > (sequencesHeight - boxHeight))
+ JPopupMenu popup = new JPopupMenu();
+ ActionListener menuListener = new ActionListener()
{
- boxY = sequencesHeight - boxHeight + 1;
- }
-
- if (boxX < 0)
- {
- boxX = 0;
- }
-
- if (boxX > (width - boxWidth))
- {
- if (av.hasHiddenColumns())
- {
- // Try smallest possible box
- boxWidth = (int) ((av.endRes - av.startRes + 1) * av.getCharWidth() * scalew);
- }
- boxX = width - boxWidth;
- }
-
- int col = (int) (boxX / scalew / av.getCharWidth());
- int row = (int) (boxY / scaleh / av.getCharHeight());
+ @Override
+ public void actionPerformed(ActionEvent event)
+ {
+ // switch on/off the hidden columns view
+ toggleHiddenColumns();
+ displayToggle.setSelected(showHidden);
+ }
+ };
+ displayToggle = new JCheckBoxMenuItem(
+ MessageManager.getString("label.togglehidden"));
+ displayToggle.setEnabled(true);
+ displayToggle.setSelected(showHidden);
+ popup.add(displayToggle);
+ displayToggle.addActionListener(menuListener);
+ popup.show(this, e.getX(), e.getY());
+ }
- if (av.hasHiddenColumns())
+ /*
+ * Toggle overview display between showing hidden columns and hiding hidden columns
+ */
+ private void toggleHiddenColumns()
+ {
+ if (showHidden)
{
- if (!av.getColumnSelection().isVisible(col))
- {
- return;
- }
-
- col = av.getColumnSelection().findColumnPosition(col);
+ showHidden = false;
+ od = new OverviewDimensionsHideHidden(av.getRanges(),
+ (av.isShowAnnotation() && av
+ .getAlignmentConservationAnnotation() != null));
}
-
- if (av.hasHiddenRows())
+ else
{
- row = av.getAlignment().getHiddenSequences()
- .findIndexWithoutHiddenSeqs(row);
+ showHidden = true;
+ od = new OverviewDimensionsShowHidden(av.getRanges(),
+ (av.isShowAnnotation() && av
+ .getAlignmentConservationAnnotation() != null));
}
-
- ap.setScrollValues(col, row);
-
+ oviewCanvas.resetOviewDims(od);
+ updateOverviewImage();
+ setBoxPosition();
}
/**
- * DOCUMENT ME!
+ * Updates the overview image when the related alignment panel is updated
*/
public void updateOverviewImage()
{
- if (resizing)
+ if ((getWidth() > 0) && (getHeight() > 0))
{
- resizeAgain = true;
- return;
+ od.setWidth(getWidth());
+ od.setHeight(getHeight());
}
+
+ setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
- resizing = true;
-
- if ((getWidth() > 0) && (getHeight() > 0))
+ if (oviewCanvas.restartDraw())
{
- width = getWidth();
- sequencesHeight = getHeight() - graphHeight;
+ return;
}
- setPreferredSize(new Dimension(width, sequencesHeight + graphHeight));
-
Thread thread = new Thread(this);
thread.start();
repaint();
- }
- // This is set true if the user resizes whilst
- // the overview is being calculated
- boolean resizeAgain = false;
+ }
- /**
- * DOCUMENT ME!
- */
@Override
public void run()
{
- miniMe = null;
-
- if (av.isShowSequenceFeatures())
- {
- fr.transferSettings(ap.getSeqPanel().seqCanvas.getFeatureRenderer());
- }
-
- int alwidth = av.getAlignment().getWidth();
- int alheight = av.getAlignment().getHeight()
- + av.getAlignment().getHiddenSequences().getSize();
-
- setPreferredSize(new Dimension(width, sequencesHeight + graphHeight));
-
- int fullsizeWidth = alwidth * av.getCharWidth();
- int fullsizeHeight = alheight * av.getCharHeight();
-
- scalew = (float) width / (float) fullsizeWidth;
- scaleh = (float) sequencesHeight / (float) fullsizeHeight;
-
- miniMe = new BufferedImage(width, sequencesHeight + graphHeight,
- BufferedImage.TYPE_INT_RGB);
-
- Graphics mg = miniMe.getGraphics();
- mg.setColor(Color.orange);
- mg.fillRect(0, 0, width, miniMe.getHeight());
-
- float sampleCol = (float) alwidth / (float) width;
- float sampleRow = (float) alheight / (float) sequencesHeight;
-
- int lastcol = -1, lastrow = -1;
- int color = Color.white.getRGB();
- int row, col;
- jalview.datamodel.SequenceI seq;
- final boolean hasHiddenRows = av.hasHiddenRows(), hasHiddenCols = av
- .hasHiddenColumns();
- boolean hiddenRow = false;
- // get hidden row and hidden column map once at beginning.
- // clone featureRenderer settings to avoid race conditions... if state is
- // updated just need to refresh again
- for (row = 0; row < sequencesHeight; row++)
- {
- if (resizeAgain)
- {
- break;
- }
- if ((int) (row * sampleRow) == lastrow)
- {
- // No need to recalculate the colours,
- // Just copy from the row above
- for (col = 0; col < width; col++)
- {
- if (resizeAgain)
- {
- break;
- }
- miniMe.setRGB(col, row, miniMe.getRGB(col, row - 1));
- }
- continue;
- }
-
- lastrow = (int) (row * sampleRow);
-
- hiddenRow = false;
- if (hasHiddenRows)
- {
- seq = av.getAlignment().getHiddenSequences()
- .getHiddenSequence(lastrow);
- if (seq == null)
- {
- int index = av.getAlignment().getHiddenSequences()
- .findIndexWithoutHiddenSeqs(lastrow);
-
- seq = av.getAlignment().getSequenceAt(index);
- }
- else
- {
- hiddenRow = true;
- }
- }
- else
- {
- seq = av.getAlignment().getSequenceAt(lastrow);
- }
-
- if (seq == null)
- {
- System.out.println(lastrow + " null");
- continue;
- }
-
- for (col = 0; col < width; col++)
- {
- if (resizeAgain)
- {
- break;
- }
- if ((int) (col * sampleCol) == lastcol
- && (int) (row * sampleRow) == lastrow)
- {
- miniMe.setRGB(col, row, color);
- continue;
- }
-
- lastcol = (int) (col * sampleCol);
-
- if (seq.getLength() > lastcol)
- {
- color = sr.getResidueBoxColour(seq, lastcol).getRGB();
-
- if (av.isShowSequenceFeatures())
- {
- color = fr.findFeatureColour(color, seq, lastcol);
- }
- }
- else
- {
- color = -1; // White
- }
-
- if (hiddenRow
- || (hasHiddenCols && !av.getColumnSelection().isVisible(
- lastcol)))
- {
- color = new Color(color).darker().darker().getRGB();
- }
-
- miniMe.setRGB(col, row, color);
-
- }
- }
-
- if (av.getAlignmentConservationAnnotation() != null)
- {
- renderer.updateFromAlignViewport(av);
- for (col = 0; col < width; col++)
- {
- if (resizeAgain)
- {
- break;
- }
- lastcol = (int) (col * sampleCol);
- {
- mg.translate(col, sequencesHeight);
- renderer.drawGraph(mg, av.getAlignmentConservationAnnotation(),
- av.getAlignmentConservationAnnotation().annotations,
- (int) (sampleCol) + 1, graphHeight,
- (int) (col * sampleCol), (int) (col * sampleCol) + 1);
- mg.translate(-col, -sequencesHeight);
- }
- }
- }
- System.gc();
-
- resizing = false;
-
- if (resizeAgain)
- {
- resizeAgain = false;
- updateOverviewImage();
- }
- else
- {
- lastMiniMe = miniMe;
- }
-
+ oviewCanvas.draw(av.isShowSequenceFeatures(),
+ (av.isShowAnnotation() && av
+ .getAlignmentConservationAnnotation() != null), ap
+ .getSeqPanel().seqCanvas.getFeatureRenderer());
setBoxPosition();
}
/**
- * DOCUMENT ME!
+ * Update the overview panel box when the associated alignment panel is
+ * changed
+ *
*/
- public void setBoxPosition()
+ private void setBoxPosition()
{
- int fullsizeWidth = av.getAlignment().getWidth() * av.getCharWidth();
- int fullsizeHeight = (av.getAlignment().getHeight() + av.getAlignment()
- .getHiddenSequences().getSize())
- * av.getCharHeight();
-
- int startRes = av.getStartRes();
- int endRes = av.getEndRes();
-
- if (av.hasHiddenColumns())
- {
- startRes = av.getColumnSelection().adjustForHiddenColumns(startRes);
- endRes = av.getColumnSelection().adjustForHiddenColumns(endRes);
- }
-
- int startSeq = av.startSeq;
- int endSeq = av.endSeq;
-
- if (av.hasHiddenRows())
- {
- startSeq = av.getAlignment().getHiddenSequences()
- .adjustForHiddenSeqs(startSeq);
-
- endSeq = av.getAlignment().getHiddenSequences()
- .adjustForHiddenSeqs(endSeq);
-
- }
-
- scalew = (float) width / (float) fullsizeWidth;
- scaleh = (float) sequencesHeight / (float) fullsizeHeight;
-
- boxX = (int) (startRes * av.getCharWidth() * scalew);
- boxY = (int) (startSeq * av.getCharHeight() * scaleh);
-
- if (av.hasHiddenColumns())
- {
- boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
- }
- else
- {
- boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
- }
-
- boxHeight = (int) ((endSeq - startSeq) * av.getCharHeight() * scaleh);
-
+ od.setBoxPosition(av.getAlignment().getHiddenSequences(), av
+ .getAlignment().getHiddenColumns());
repaint();
}
- private BufferedImage lastMiniMe = null;
-
- /**
- * DOCUMENT ME!
- *
- * @param g
- * DOCUMENT ME!
- */
@Override
- public void paintComponent(Graphics g)
+ public void propertyChange(PropertyChangeEvent evt)
{
- if (resizing || resizeAgain)
- {
- if (lastMiniMe == null)
- {
- g.setColor(Color.white);
- g.fillRect(0, 0, getWidth(), getHeight());
- }
- else
- {
- g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this);
- }
- g.setColor(new Color(100, 100, 100, 25));
- g.fillRect(0, 0, getWidth(), getHeight());
- }
- else if (lastMiniMe != null)
- {
- g.drawImage(lastMiniMe, 0, 0, this);
- if (lastMiniMe != miniMe)
- {
- g.setColor(new Color(100, 100, 100, 25));
- g.fillRect(0, 0, getWidth(), getHeight());
- }
- }
- // TODO: render selected regions
- g.setColor(Color.red);
- g.drawRect(boxX, boxY, boxWidth, boxHeight);
- g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);
+ setBoxPosition();
}
}
*/
package jalview.gui;
+import jalview.analysis.scoremodels.ScoreModels;
+import jalview.analysis.scoremodels.SimilarityParams;
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityParamsI;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentView;
-import jalview.datamodel.ColumnSelection;
-import jalview.datamodel.SeqCigar;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceI;
import jalview.jbgui.GPCAPanel;
-import jalview.schemes.ResidueProperties;
import jalview.util.MessageManager;
import jalview.viewmodel.AlignmentViewport;
import jalview.viewmodel.PCAModel;
import java.awt.BorderLayout;
import java.awt.Color;
+import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
PCAModel pcaModel;
+ private static final int MIN_WIDTH = 470;
+
+ private static final int MIN_HEIGHT = 250;
+
int top = 0;
/**
- * Creates a new PCAPanel object.
+ * Creates a new PCAPanel object using default score model and parameters
*
- * @param av
- * DOCUMENT ME!
- * @param s
- * DOCUMENT ME!
+ * @param alignPanel
*/
- public PCAPanel(AlignmentPanel ap)
+ public PCAPanel(AlignmentPanel alignPanel)
+ {
+ this(alignPanel, ScoreModels.getInstance()
+ .getDefaultModel(!alignPanel.av.getAlignment().isNucleotide())
+ .getName(), SimilarityParams.SeqSpace);
+ }
+
+ /**
+ * Constructor given sequence data, a similarity (or distance) score model
+ * name, and score calculation parameters
+ *
+ * @param alignPanel
+ * @param modelName
+ * @param params
+ */
+ public PCAPanel(AlignmentPanel alignPanel, String modelName,
+ SimilarityParamsI params)
{
super();
- this.av = ap.av;
- this.ap = ap;
+ this.av = alignPanel.av;
+ this.ap = alignPanel;
+ boolean nucleotide = av.getAlignment().isNucleotide();
progressBar = new ProgressBar(statusPanel, statusBar);
- boolean sameLength = true;
+ addInternalFrameListener(new InternalFrameAdapter()
+ {
+ @Override
+ public void internalFrameClosed(InternalFrameEvent e)
+ {
+ close_actionPerformed();
+ }
+ });
+
boolean selected = av.getSelectionGroup() != null
&& av.getSelectionGroup().getSize() > 0;
AlignmentView seqstrings = av.getAlignmentView(selected);
- boolean nucleotide = av.getAlignment().isNucleotide();
SequenceI[] seqs;
if (!selected)
{
{
seqs = av.getSelectionGroup().getSequencesInOrder(av.getAlignment());
}
- SeqCigar sq[] = seqstrings.getSequences();
- int length = sq[0].getWidth();
-
- for (int i = 0; i < seqs.length; i++)
- {
- if (sq[i].getWidth() != length)
- {
- sameLength = false;
- break;
- }
- }
- if (!sameLength)
- {
- JvOptionPane.showMessageDialog(Desktop.desktop,
- MessageManager.getString("label.pca_sequences_not_aligned"),
- MessageManager.getString("label.sequences_not_aligned"),
- JvOptionPane.WARNING_MESSAGE);
-
- return;
- }
-
- addInternalFrameListener(new InternalFrameAdapter()
- {
- @Override
- public void internalFrameClosed(InternalFrameEvent e)
- {
- close_actionPerformed();
- }
- });
-
- pcaModel = new PCAModel(seqstrings, seqs, nucleotide);
+ ScoreModelI scoreModel = ScoreModels.getInstance().getScoreModel(
+ modelName, ap);
+ pcaModel = new PCAModel(seqstrings, seqs, nucleotide, scoreModel,
+ params);
PaintRefresher.Register(this, av.getSequenceSetId());
- rc = new RotatableCanvas(ap);
+ rc = new RotatableCanvas(alignPanel);
this.getContentPane().add(rc, BorderLayout.CENTER);
Thread worker = new Thread(this);
worker.start();
pcaModel = null;
}
+ /**
+ * Repopulate the options and actions under the score model menu when it is
+ * selected. Options will depend on whether 'nucleotide' or 'peptide'
+ * modelling is selected (and also possibly on whether any additional score
+ * models have been added).
+ */
@Override
- protected void scoreMatrix_menuSelected()
+ protected void scoreModel_menuSelected()
{
- scoreMatrixMenu.removeAll();
- for (final String sm : ResidueProperties.scoreMatrices.keySet())
- {
- if (ResidueProperties.getScoreMatrix(sm) != null)
+ scoreModelMenu.removeAll();
+ for (final ScoreModelI sm : ScoreModels.getInstance().getModels())
+ {
+ final String name = sm.getName();
+ JCheckBoxMenuItem jm = new JCheckBoxMenuItem(name);
+
+ /*
+ * if the score model doesn't provide a description, try to look one
+ * up in the text bundle, falling back on its name
+ */
+ String tooltip = sm.getDescription();
+ if (tooltip == null)
{
- // create an entry for this score matrix for use in PCA
- JCheckBoxMenuItem jm = new JCheckBoxMenuItem();
- jm.setText(MessageManager.getStringOrReturn("label.score_model_",
- sm));
- jm.setSelected(pcaModel.getScore_matrix().equals(sm));
- if ((ResidueProperties.scoreMatrices.get(sm).isDNA() && ResidueProperties.scoreMatrices
- .get(sm).isProtein())
- || pcaModel.isNucleotide() == ResidueProperties.scoreMatrices
- .get(sm).isDNA())
+ tooltip = MessageManager.getStringOrReturn("label.score_model_",
+ name);
+ }
+ jm.setToolTipText(tooltip);
+ jm.setSelected(pcaModel.getScoreModelName().equals(name));
+ if ((pcaModel.isNucleotide() && sm.isDNA())
+ || (!pcaModel.isNucleotide() && sm.isProtein()))
+ {
+ jm.addActionListener(new ActionListener()
{
- final PCAPanel us = this;
- jm.addActionListener(new ActionListener()
+ @Override
+ public void actionPerformed(ActionEvent e)
{
- @Override
- public void actionPerformed(ActionEvent e)
+ if (!pcaModel.getScoreModelName().equals(name))
{
- if (!pcaModel.getScore_matrix().equals(sm))
- {
- pcaModel.setScore_matrix(sm);
- Thread worker = new Thread(us);
- worker.start();
- }
+ ScoreModelI sm2 = ScoreModels.getInstance().getScoreModel(
+ name, ap);
+ pcaModel.setScoreModel(sm2);
+ Thread worker = new Thread(PCAPanel.this);
+ worker.start();
}
- });
- scoreMatrixMenu.add(jm);
- }
+ }
+ });
+ scoreModelMenu.add(jm);
}
}
}
// rc.invalidate();
nuclSetting.setSelected(pcaModel.isNucleotide());
protSetting.setSelected(!pcaModel.isNucleotide());
- jvVersionSetting.setSelected(pcaModel.isJvCalcMode());
top = pcaModel.getTop();
} catch (OutOfMemoryError er)
addKeyListener(rc);
Desktop.addInternalFrame(this, MessageManager
.getString("label.principal_component_analysis"), 475, 450);
+ this.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
}
}
if (!pcaModel.isNucleotide())
{
pcaModel.setNucleotide(true);
- pcaModel.setScore_matrix("DNA");
+ pcaModel.setScoreModel(ScoreModels.getInstance().getDefaultModel(
+ false));
Thread worker = new Thread(this);
worker.start();
}
if (pcaModel.isNucleotide())
{
pcaModel.setNucleotide(false);
- pcaModel.setScore_matrix("BLOSUM62");
+ pcaModel.setScoreModel(ScoreModels.getInstance()
+ .getDefaultModel(true));
Thread worker = new Thread(this);
worker.start();
}
}
- @Override
- protected void jvVersionSetting_actionPerfomed(ActionEvent arg0)
- {
- pcaModel.setJvCalcMode(jvVersionSetting.isSelected());
- Thread worker = new Thread(this);
- worker.start();
- }
-
/**
* DOCUMENT ME!
*/
}
;
Object[] alAndColsel = pcaModel.getSeqtrings()
- .getAlignmentAndColumnSelection(gc);
+ .getAlignmentAndHiddenColumns(gc);
if (alAndColsel != null && alAndColsel[0] != null)
{
if (true)
{
// make a new frame!
- AlignFrame af = new AlignFrame(al,
- (ColumnSelection) alAndColsel[1], AlignFrame.DEFAULT_WIDTH,
+ AlignFrame af = new AlignFrame(al, (HiddenColumns) alAndColsel[1],
+ AlignFrame.DEFAULT_WIDTH,
AlignFrame.DEFAULT_HEIGHT);
// >>>This is a fix for the moment, until a better solution is
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.Annotation;
-import jalview.datamodel.ColumnSelection;
import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.io.FileFormats;
import jalview.io.FormatAdapter;
import jalview.io.SequenceAnnotationReport;
-import jalview.schemes.AnnotationColourGradient;
import jalview.schemes.Blosum62ColourScheme;
import jalview.schemes.ColourSchemeI;
import jalview.schemes.ColourSchemes;
import jalview.schemes.PIDColourScheme;
-import jalview.schemes.ResidueColourScheme;
import jalview.util.GroupUrlLink;
import jalview.util.GroupUrlLink.UrlStringTooLongException;
import jalview.util.MessageManager;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Hashtable;
hideInsertions_actionPerformed(e);
}
});
- /*
- * annotationMenuItem.setText("By Annotation");
- * annotationMenuItem.addActionListener(new ActionListener() { public void
- * actionPerformed(ActionEvent actionEvent) {
- * annotationMenuItem_actionPerformed(actionEvent); } });
- */
+
groupMenu.add(sequenceSelDetails);
add(groupMenu);
add(sequenceMenu);
protected void hideInsertions_actionPerformed(ActionEvent actionEvent)
{
- if (sequence != null)
+
+ HiddenColumns hidden = new HiddenColumns();
+ BitSet inserts = new BitSet(), mask = new BitSet();
+
+ // set mask to preserve existing hidden columns outside selected group
+ if (ap.av.hasHiddenColumns())
{
- ColumnSelection cs = ap.av.getColumnSelection();
- if (cs == null)
+ ap.av.getAlignment().getHiddenColumns().markHiddenRegions(mask);
+ }
+
+ boolean markedPopup = false;
+ // mark inserts in current selection
+ if (ap.av.getSelectionGroup() != null)
+ {
+ // mark just the columns in the selection group to be hidden
+ inserts.set(ap.av.getSelectionGroup().getStartRes(), ap.av
+ .getSelectionGroup().getEndRes() + 1);
+
+ // and clear that part of the mask
+ mask.andNot(inserts);
+
+ // now clear columns without gaps
+ for (SequenceI sq : ap.av.getSelectionGroup().getSequences())
{
- cs = new ColumnSelection();
+ if (sq == sequence)
+ {
+ markedPopup = true;
+ }
+ inserts.and(sq.getInsertionsAsBits());
}
- cs.hideInsertionsFor(sequence);
- ap.av.setColumnSelection(cs);
}
+ else
+ {
+ // initially, mark all columns to be hidden
+ inserts.set(0, ap.av.getAlignment().getWidth());
+
+ // and clear out old hidden regions completely
+ mask.clear();
+ }
+
+ // now mark for sequence under popup if we haven't already done it
+ if (!markedPopup && sequence != null)
+ {
+ inserts.and(sequence.getInsertionsAsBits());
+ }
+
+ // finally, preserve hidden regions outside selection
+ inserts.or(mask);
+
+ // and set hidden columns accordingly
+ hidden.hideMarkedBits(inserts);
+
+ ap.av.getAlignment().setHiddenColumns(hidden);
refresh();
}
refresh();
}
- public void annotationMenuItem_actionPerformed(ActionEvent actionEvent)
- {
- SequenceGroup sg = getGroup();
- if (sg == null)
- {
- return;
- }
-
- AnnotationColourGradient acg = new AnnotationColourGradient(
- sequence.getAnnotation()[0], null,
- AnnotationColourGradient.NO_THRESHOLD);
-
- acg.setPredefinedColours(true);
- sg.setColourScheme(acg);
-
- refresh();
- }
-
/**
* DOCUMENT ME!
*
return;
}
- int rsize = 0, gSize = sg.getSize();
- SequenceI[] rseqs, seqs = new SequenceI[gSize];
- SequenceFeature[] tfeatures, features = new SequenceFeature[gSize];
+ List<SequenceI> seqs = new ArrayList<SequenceI>();
+ List<SequenceFeature> features = new ArrayList<SequenceFeature>();
+ /*
+ * assemble dataset sequences, and template new sequence features,
+ * for the amend features dialog
+ */
+ int gSize = sg.getSize();
for (int i = 0; i < gSize; i++)
{
int start = sg.getSequenceAt(i).findPosition(sg.getStartRes());
int end = sg.findEndRes(sg.getSequenceAt(i));
if (start <= end)
{
- seqs[rsize] = sg.getSequenceAt(i).getDatasetSequence();
- features[rsize] = new SequenceFeature(null, null, null, start, end,
- "Jalview");
- rsize++;
+ seqs.add(sg.getSequenceAt(i).getDatasetSequence());
+ features.add(new SequenceFeature(null, null, null, start, end, null));
}
}
- rseqs = new SequenceI[rsize];
- tfeatures = new SequenceFeature[rsize];
- System.arraycopy(seqs, 0, rseqs, 0, rsize);
- System.arraycopy(features, 0, tfeatures, 0, rsize);
- features = tfeatures;
- seqs = rseqs;
+
if (ap.getSeqPanel().seqCanvas.getFeatureRenderer().amendFeatures(seqs,
features, true, ap))
{
public void changeColour_actionPerformed(String colourSchemeName)
{
SequenceGroup sg = getGroup();
- if (ResidueColourScheme.USER_DEFINED.equals(colourSchemeName))
- {
- /*
- * open a panel to load or configure a user-defined colour scheme
- */
- new UserDefinedColours(ap, sg);
- }
- else
+ /*
+ * switch to the chosen colour scheme (or null for None)
+ */
+ ColourSchemeI colourScheme = ColourSchemes.getInstance()
+ .getColourScheme(colourSchemeName, sg,
+ ap.av.getHiddenRepSequences());
+ sg.setColourScheme(colourScheme);
+ if (colourScheme instanceof Blosum62ColourScheme
+ || colourScheme instanceof PIDColourScheme)
{
- /*
- * switch to the chosen colour scheme (or null for None)
- */
- ColourSchemeI colourScheme = ColourSchemes.getInstance().getColourScheme(
- colourSchemeName, sg, ap.av.getHiddenRepSequences());
- sg.setColourScheme(colourScheme);
- if (colourScheme instanceof Blosum62ColourScheme
- || colourScheme instanceof PIDColourScheme)
- {
- sg.cs.setConsensus(AAFrequency.calculate(
- sg.getSequences(ap.av.getHiddenRepSequences()),
- sg.getStartRes(), sg.getEndRes() + 1));
- }
+ sg.cs.setConsensus(AAFrequency.calculate(
+ sg.getSequences(ap.av.getHiddenRepSequences()),
+ sg.getStartRes(), sg.getEndRes() + 1));
}
refresh();
public static final String SHOW_AUTOCALC_ABOVE = "SHOW_AUTOCALC_ABOVE";
+ public static final String SHOW_OCCUPANCY = "SHOW_OCCUPANCY";
+
private static final int MIN_FONT_SIZE = 1;
private static final int MAX_FONT_SIZE = 30;
openoverv.setSelected(Cache.getDefault("SHOW_OVERVIEW", false));
showUnconserved
.setSelected(Cache.getDefault("SHOW_UNCONSERVED", false));
+ showOccupancy.setSelected(Cache.getDefault(SHOW_OCCUPANCY, false));
showGroupConsensus.setSelected(Cache.getDefault("SHOW_GROUP_CONSENSUS",
false));
showGroupConservation.setSelected(Cache.getDefault(
Boolean.toString(idItalics.isSelected()));
Cache.applicationProperties.setProperty("SHOW_UNCONSERVED",
Boolean.toString(showUnconserved.isSelected()));
+ Cache.applicationProperties.setProperty(SHOW_OCCUPANCY,
+ Boolean.toString(showOccupancy.isSelected()));
Cache.applicationProperties.setProperty("SHOW_GROUP_CONSENSUS",
Boolean.toString(showGroupConsensus.isSelected()));
Cache.applicationProperties.setProperty("SHOW_GROUP_CONSERVATION",
conservation.setEnabled(annotations.isSelected());
quality.setEnabled(annotations.isSelected());
identity.setEnabled(annotations.isSelected());
+ showOccupancy.setEnabled(annotations.isSelected());
showGroupConsensus.setEnabled(annotations.isSelected());
showGroupConservation.setEnabled(annotations.isSelected());
showConsensHistogram.setEnabled(annotations.isSelected()
package jalview.gui;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.renderer.ScaleRenderer;
import jalview.renderer.ScaleRenderer.ScaleMark;
import jalview.util.MessageManager;
import jalview.util.Platform;
+import jalview.viewmodel.ViewportListenerI;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
import java.util.List;
import javax.swing.JMenuItem;
* supports a range of mouse operations to select, hide or reveal columns.
*/
public class ScalePanel extends JPanel implements MouseMotionListener,
- MouseListener
+ MouseListener, ViewportListenerI
{
protected int offy = 4;
addMouseListener(this);
addMouseMotionListener(this);
+
+ av.getRanges().addPropertyChangeListener(this);
}
/**
@Override
public void mousePressed(MouseEvent evt)
{
- int x = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int x = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes();
final int res;
if (av.hasHiddenColumns())
{
- x = av.getColumnSelection().adjustForHiddenColumns(x);
+ x = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(x);
}
if (x >= av.getAlignment().getWidth())
});
pop.add(item);
- if (av.getColumnSelection().hasHiddenColumns())
+ if (av.getAlignment().getHiddenColumns().hasHiddenColumns())
{
item = new JMenuItem(MessageManager.getString("action.reveal_all"));
item.addActionListener(new ActionListener()
{
mouseDragging = false;
- int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int res = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
if (av.hasHiddenColumns())
{
- res = av.getColumnSelection().adjustForHiddenColumns(res);
+ res = av.getAlignment().getHiddenColumns()
+ .adjustForHiddenColumns(res);
}
if (res >= av.getAlignment().getWidth())
{
mouseDragging = true;
ColumnSelection cs = av.getColumnSelection();
+ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
- int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int res = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
res = Math.max(0, res);
- res = cs.adjustForHiddenColumns(res);
+ res = hidden.adjustForHiddenColumns(res);
res = Math.min(res, av.getAlignment().getWidth() - 1);
min = Math.min(res, min);
max = Math.max(res, max);
return;
}
- int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int res = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
- res = av.getColumnSelection().adjustForHiddenColumns(res);
+ res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res);
- if (av.getColumnSelection().getHiddenColumns() != null)
+ if (av.getAlignment().getHiddenColumns().getHiddenRegions() != null)
{
- for (int[] region : av.getColumnSelection().getHiddenColumns())
+ for (int[] region : av.getAlignment().getHiddenColumns()
+ .getHiddenRegions())
{
if (res + 1 == region[0] || res - 1 == region[1])
{
@Override
public void paintComponent(Graphics g)
{
- drawScale(g, av.getStartRes(), av.getEndRes(), getWidth(), getHeight());
+ drawScale(g, av.getRanges().getStartRes(), av.getRanges().getEndRes(),
+ getWidth(), getHeight());
}
// scalewidth will normally be screenwidth,
// Fill the selected columns
ColumnSelection cs = av.getColumnSelection();
- int avCharWidth = av.getCharWidth(), avCharHeight = av.getCharHeight();
+ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+ int avCharWidth = av.getCharWidth();
+ int avCharHeight = av.getCharHeight();
if (cs != null)
{
if (av.hasHiddenColumns())
{
- if (cs.isVisible(sel))
+ if (hidden.isVisible(sel))
{
- sel = cs.findColumnPosition(sel);
+ sel = hidden.findColumnPosition(sel);
}
else
{
// draw any hidden column markers
gg.setColor(Color.blue);
int res;
- if (av.getShowHiddenMarkers()
- && av.getColumnSelection().getHiddenColumns() != null)
+
+ if (av.getShowHiddenMarkers() && hidden.getHiddenRegions() != null)
{
- for (int i = 0; i < av.getColumnSelection().getHiddenColumns()
+ for (int i = 0; i < hidden.getHiddenRegions()
.size(); i++)
{
- res = av.getColumnSelection().findHiddenRegionPosition(i)
+ res = hidden.findHiddenRegionPosition(i)
- startx;
if (res < 0 || res > widthx)
}
}
+ @Override
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ // Respond to viewport change events (e.g. alignment panel was scrolled)
+ repaint();
+ }
+
}
package jalview.gui;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.renderer.ScaleRenderer;
import jalview.renderer.ScaleRenderer.ScaleMark;
+import jalview.viewmodel.ViewportListenerI;
+import jalview.viewmodel.ViewportRanges;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeEvent;
import java.util.List;
import javax.swing.JComponent;
* @author $author$
* @version $Revision$
*/
-public class SeqCanvas extends JComponent
+public class SeqCanvas extends JComponent implements ViewportListenerI
{
final FeatureRenderer fr;
setLayout(new BorderLayout());
PaintRefresher.Register(this, av.getSequenceSetId());
setBackground(Color.white);
+
+ av.getRanges().addPropertyChangeListener(this);
}
public SequenceRenderer getSequenceRenderer()
if (av.hasHiddenColumns())
{
- startx = av.getColumnSelection().adjustForHiddenColumns(startx);
- endx = av.getColumnSelection().adjustForHiddenColumns(endx);
+ startx = av.getAlignment().getHiddenColumns()
+ .adjustForHiddenColumns(startx);
+ endx = av.getAlignment().getHiddenColumns()
+ .adjustForHiddenColumns(endx);
}
int maxwidth = av.getAlignment().getWidth();
if (av.hasHiddenColumns())
{
- maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+ maxwidth = av.getAlignment().getHiddenColumns()
+ .findColumnPosition(maxwidth) - 1;
}
// WEST SCALE
if (av.hasHiddenColumns())
{
- endx = av.getColumnSelection().adjustForHiddenColumns(endx);
+ endx = av.getAlignment().getHiddenColumns()
+ .adjustForHiddenColumns(endx);
}
SequenceI seq;
gg.copyArea(horizontal * charWidth, vertical * charHeight, imgWidth,
imgHeight, -horizontal * charWidth, -vertical * charHeight);
- int sr = av.startRes;
- int er = av.endRes;
- int ss = av.startSeq;
- int es = av.endSeq;
+ ViewportRanges ranges = av.getRanges();
+ int sr = ranges.getStartRes();
+ int er = ranges.getEndRes();
+ int ss = ranges.getStartSeq();
+ int es = ranges.getEndSeq();
int transX = 0;
int transY = 0;
if (horizontal > 0) // scrollbar pulled right, image to the left
{
- er++;
transX = (er - sr - horizontal) * charWidth;
sr = er - horizontal;
}
else if (horizontal < 0)
{
- er = sr - horizontal - 1;
+ er = sr - horizontal;
}
else if (vertical > 0) // scroll down
{
ss = es - vertical;
- if (ss < av.startSeq)
+ if (ss < ranges.getStartSeq())
{ // ie scrolling too fast, more than a page at a time
- ss = av.startSeq;
+ ss = ranges.getStartSeq();
}
else
{
- transY = imgHeight - (vertical * charHeight);
+ transY = imgHeight - ((vertical + 1) * charHeight);
}
}
else if (vertical < 0)
{
es = ss - vertical;
- if (es > av.endSeq)
+ if (es > ranges.getEndSeq())
{
- es = av.endSeq;
+ es = ranges.getEndSeq();
}
}
gg.setColor(Color.white);
gg.fillRect(0, 0, imgWidth, imgHeight);
+ ViewportRanges ranges = av.getRanges();
if (av.getWrapAlignment())
{
- drawWrappedPanel(gg, getWidth(), getHeight(), av.startRes);
+ drawWrappedPanel(gg, getWidth(), getHeight(), ranges.getStartRes());
}
else
{
- drawPanel(gg, av.startRes, av.endRes, av.startSeq, av.endSeq, 0);
+ drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(),
+ ranges.getStartSeq(), ranges.getEndSeq(), 0);
}
g.drawImage(lcimg, 0, 0, this);
av.setWrappedWidth(cWidth);
- av.endRes = av.startRes + cWidth;
+ av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth - 1);
int endx;
int ypos = hgap;
if (av.hasHiddenColumns())
{
- maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+ maxwidth = av.getAlignment().getHiddenColumns()
+ .findColumnPosition(maxwidth) - 1;
}
while ((ypos <= canvasHeight) && (startRes < maxwidth))
{
g.setColor(Color.blue);
int res;
- for (int i = 0; i < av.getColumnSelection().getHiddenColumns()
- .size(); i++)
+ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+ for (int i = 0; i < hidden.getHiddenRegions().size(); i++)
{
- res = av.getColumnSelection().findHiddenRegionPosition(i)
- - startRes;
+ res = hidden.findHiddenRegionPosition(i) - startRes;
if (res < 0 || res > endx - startRes)
{
(int) clip.getBounds().getHeight());
}
- drawPanel(g, startRes, endx, 0, al.getHeight(), ypos);
+ drawPanel(g, startRes, endx, 0, al.getHeight() - 1, ypos);
if (av.isShowAnnotation())
{
}
else
{
- List<int[]> regions = av.getColumnSelection().getHiddenColumns();
+ List<int[]> regions = av.getAlignment().getHiddenColumns()
+ .getHiddenRegions();
int screenY = 0;
int blockStart = startRes;
g1.drawLine((blockEnd - blockStart + 1) * charWidth - 1,
0 + offset, (blockEnd - blockStart + 1) * charWidth - 1,
- (endSeq - startSeq) * charHeight + offset);
+ (endSeq - startSeq + 1) * charHeight + offset);
}
g1.translate(-screenY * charWidth, 0);
// / First draw the sequences
// ///////////////////////////
- for (int i = startSeq; i < endSeq; i++)
+ for (int i = startSeq; i <= endSeq; i++)
{
nextSeq = av.getAlignment().getSequenceAt(i);
if (nextSeq == null)
if (av.isShowSequenceFeatures())
{
fr.drawSequence(g, nextSeq, startRes, endRes, offset
- + ((i - startSeq) * charHeight));
+ + ((i - startSeq) * charHeight), false);
}
// / Highlight search Results once all sequences have been drawn
int top = -1;
int bottom = -1;
- for (i = startSeq; i < endSeq; i++)
+ for (i = startSeq; i <= endSeq; i++)
{
sx = (group.getStartRes() - startRes) * charWidth;
sy = offset + ((i - startSeq) * charHeight);
repaint();
}
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ if (!av.getWrapAlignment())
+ {
+ if (evt.getPropertyName().equals("startres")
+ || evt.getPropertyName().equals("endres"))
+ {
+ // Make sure we're not trying to draw a panel
+ // larger than the visible window
+ ViewportRanges vpRanges = av.getRanges();
+ int scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
+ if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
+ {
+ scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
+ }
+ else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
+ {
+ scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
+ }
+ fastPaint(scrollX, 0);
+ }
+ else if (evt.getPropertyName().equals("startseq")
+ || evt.getPropertyName().equals("endseq"))
+ {
+ fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
+ }
+ }
+ }
}
--- /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.
+ */
+package jalview.gui;
+
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SearchResults;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+
+import java.awt.BasicStroke;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.image.BufferedImage;
+import java.util.List;
+
+import javax.swing.JComponent;
+
+/**
+ * DOCUMENT ME!
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class SeqCanvas extends JComponent
+{
+ final FeatureRenderer fr;
+
+ final SequenceRenderer sr;
+
+ BufferedImage img;
+
+ Graphics2D gg;
+
+ int imgWidth;
+
+ int imgHeight;
+
+ AlignViewport av;
+
+ SearchResults searchResults = null;
+
+ boolean fastPaint = false;
+
+ int LABEL_WEST;
+
+ int LABEL_EAST;
+
+ int cursorX = 0;
+
+ int cursorY = 0;
+
+ /**
+ * Creates a new SeqCanvas object.
+ *
+ * @param av
+ * DOCUMENT ME!
+ */
+ public SeqCanvas(AlignmentPanel ap)
+ {
+ this.av = ap.av;
+ updateViewport();
+ fr = new FeatureRenderer(ap);
+ sr = new SequenceRenderer(av);
+ setLayout(new BorderLayout());
+ PaintRefresher.Register(this, av.getSequenceSetId());
+ setBackground(Color.white);
+ }
+
+ public SequenceRenderer getSequenceRenderer()
+ {
+ return sr;
+ }
+
+ public FeatureRenderer getFeatureRenderer()
+ {
+ return fr;
+ }
+
+ int charHeight = 0, charWidth = 0;
+
+ private void updateViewport()
+ {
+ charHeight = av.getCharHeight();
+ charWidth = av.getCharWidth();
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param g
+ * DOCUMENT ME!
+ * @param startx
+ * DOCUMENT ME!
+ * @param endx
+ * DOCUMENT ME!
+ * @param ypos
+ * DOCUMENT ME!
+ */
+ private void drawNorthScale(Graphics g, int startx, int endx, int ypos)
+ {
+ updateViewport();
+ int scalestartx = startx - (startx % 10) + 10;
+
+ g.setColor(Color.black);
+ // NORTH SCALE
+ for (int i = scalestartx; i < endx; i += 10)
+ {
+ int value = i;
+ if (av.hasHiddenColumns())
+ {
+ value = av.getColumnSelection().adjustForHiddenColumns(value);
+ }
+
+ g.drawString(String.valueOf(value), (i - startx - 1) * charWidth,
+ ypos - (charHeight / 2));
+
+ g.drawLine(((i - startx - 1) * charWidth) + (charWidth / 2),
+ (ypos + 2) - (charHeight / 2), ((i - startx - 1) * charWidth)
+ + (charWidth / 2), ypos - 2);
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param g
+ * DOCUMENT ME!
+ * @param startx
+ * DOCUMENT ME!
+ * @param endx
+ * DOCUMENT ME!
+ * @param ypos
+ * DOCUMENT ME!
+ */
+ void drawWestScale(Graphics g, int startx, int endx, int ypos)
+ {
+ FontMetrics fm = getFontMetrics(av.getFont());
+ ypos += charHeight;
+
+ if (av.hasHiddenColumns())
+ {
+ startx = av.getColumnSelection().adjustForHiddenColumns(startx);
+ endx = av.getColumnSelection().adjustForHiddenColumns(endx);
+ }
+
+ int maxwidth = av.getAlignment().getWidth();
+ if (av.hasHiddenColumns())
+ {
+ maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+ }
+
+ // WEST SCALE
+ for (int i = 0; i < av.getAlignment().getHeight(); i++)
+ {
+ SequenceI seq = av.getAlignment().getSequenceAt(i);
+ int index = startx;
+ int value = -1;
+
+ while (index < endx)
+ {
+ if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
+ {
+ index++;
+
+ continue;
+ }
+
+ value = av.getAlignment().getSequenceAt(i).findPosition(index);
+
+ break;
+ }
+
+ if (value != -1)
+ {
+ int x = LABEL_WEST - fm.stringWidth(String.valueOf(value))
+ - charWidth / 2;
+ g.drawString(value + "", x, (ypos + (i * charHeight))
+ - (charHeight / 5));
+ }
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param g
+ * DOCUMENT ME!
+ * @param startx
+ * DOCUMENT ME!
+ * @param endx
+ * DOCUMENT ME!
+ * @param ypos
+ * DOCUMENT ME!
+ */
+ void drawEastScale(Graphics g, int startx, int endx, int ypos)
+ {
+ ypos += charHeight;
+
+ if (av.hasHiddenColumns())
+ {
+ endx = av.getColumnSelection().adjustForHiddenColumns(endx);
+ }
+
+ SequenceI seq;
+ // EAST SCALE
+ for (int i = 0; i < av.getAlignment().getHeight(); i++)
+ {
+ seq = av.getAlignment().getSequenceAt(i);
+ int index = endx;
+ int value = -1;
+
+ while (index > startx)
+ {
+ if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
+ {
+ index--;
+
+ continue;
+ }
+
+ value = seq.findPosition(index);
+
+ break;
+ }
+
+ if (value != -1)
+ {
+ g.drawString(String.valueOf(value), 0, (ypos + (i * charHeight))
+ - (charHeight / 5));
+ }
+ }
+ }
+
+ boolean fastpainting = false;
+
+ /**
+ * need to make this thread safe move alignment rendering in response to
+ * slider adjustment
+ *
+ * @param horizontal
+ * shift along
+ * @param vertical
+ * shift up or down in repaint
+ */
+ public void fastPaint(int horizontal, int vertical)
+ {
+ if (fastpainting || gg == null)
+ {
+ return;
+ }
+ fastpainting = true;
+ fastPaint = true;
+ updateViewport();
+ gg.copyArea(horizontal * charWidth, vertical * charHeight, imgWidth,
+ imgHeight, -horizontal * charWidth, -vertical * charHeight);
+
+ int sr = av.startRes;
+ int er = av.endRes;
+ int ss = av.startSeq;
+ int es = av.endSeq;
+ int transX = 0;
+ int transY = 0;
+
+ if (horizontal > 0) // scrollbar pulled right, image to the left
+ {
+ er++;
+ transX = (er - sr - horizontal) * charWidth;
+ sr = er - horizontal;
+ }
+ else if (horizontal < 0)
+ {
+ er = sr - horizontal - 1;
+ }
+ else if (vertical > 0) // scroll down
+ {
+ ss = es - vertical;
+
+ if (ss < av.startSeq)
+ { // ie scrolling too fast, more than a page at a time
+ ss = av.startSeq;
+ }
+ else
+ {
+ transY = imgHeight - (vertical * charHeight);
+ }
+ }
+ else if (vertical < 0)
+ {
+ es = ss - vertical;
+
+ if (es > av.endSeq)
+ {
+ es = av.endSeq;
+ }
+ }
+
+ gg.translate(transX, transY);
+ drawPanel(gg, sr, er, ss, es, 0);
+ gg.translate(-transX, -transY);
+
+ repaint();
+ fastpainting = false;
+ }
+
+ /**
+ * Definitions of startx and endx (hopefully): SMJS This is what I'm working
+ * towards! startx is the first residue (starting at 0) to display. endx is
+ * the last residue to display (starting at 0). starty is the first sequence
+ * to display (starting at 0). endy is the last sequence to display (starting
+ * at 0). NOTE 1: The av limits are set in setFont in this class and in the
+ * adjustment listener in SeqPanel when the scrollbars move.
+ */
+
+ // Set this to false to force a full panel paint
+ @Override
+ public void paintComponent(Graphics g)
+ {
+ updateViewport();
+ BufferedImage lcimg = img; // take reference since other threads may null
+ // img and call later.
+ super.paintComponent(g);
+
+ if (lcimg != null
+ && (fastPaint
+ || (getVisibleRect().width != g.getClipBounds().width) || (getVisibleRect().height != g
+ .getClipBounds().height)))
+ {
+ g.drawImage(lcimg, 0, 0, this);
+ fastPaint = false;
+ return;
+ }
+
+ // this draws the whole of the alignment
+ imgWidth = getWidth();
+ imgHeight = getHeight();
+
+ imgWidth -= (imgWidth % charWidth);
+ imgHeight -= (imgHeight % charHeight);
+
+ if ((imgWidth < 1) || (imgHeight < 1))
+ {
+ return;
+ }
+
+ if (lcimg == null || imgWidth != lcimg.getWidth()
+ || imgHeight != lcimg.getHeight())
+ {
+ try
+ {
+ lcimg = img = new BufferedImage(imgWidth, imgHeight,
+ BufferedImage.TYPE_INT_RGB);
+ gg = (Graphics2D) img.getGraphics();
+ gg.setFont(av.getFont());
+ } catch (OutOfMemoryError er)
+ {
+ System.gc();
+ System.err.println("SeqCanvas OutOfMemory Redraw Error.\n" + er);
+ new OOMWarning("Creating alignment image for display", er);
+
+ return;
+ }
+ }
+
+ if (av.antiAlias)
+ {
+ gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ }
+
+ gg.setColor(Color.white);
+ gg.fillRect(0, 0, imgWidth, imgHeight);
+
+ if (av.getWrapAlignment())
+ {
+ drawWrappedPanel(gg, getWidth(), getHeight(), av.startRes);
+ }
+ else
+ {
+ drawPanel(gg, av.startRes, av.endRes, av.startSeq, av.endSeq, 0);
+ }
+
+ g.drawImage(lcimg, 0, 0, this);
+
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param cwidth
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public int getWrappedCanvasWidth(int cwidth)
+ {
+ FontMetrics fm = getFontMetrics(av.getFont());
+
+ LABEL_EAST = 0;
+ LABEL_WEST = 0;
+
+ if (av.getScaleRightWrapped())
+ {
+ LABEL_EAST = fm.stringWidth(getMask());
+ }
+
+ if (av.getScaleLeftWrapped())
+ {
+ LABEL_WEST = fm.stringWidth(getMask());
+ }
+
+ return (cwidth - LABEL_EAST - LABEL_WEST) / charWidth;
+ }
+
+ /**
+ * Generates a string of zeroes.
+ *
+ * @return String
+ */
+ String getMask()
+ {
+ String mask = "00";
+ int maxWidth = 0;
+ int tmp;
+ for (int i = 0; i < av.getAlignment().getHeight(); i++)
+ {
+ tmp = av.getAlignment().getSequenceAt(i).getEnd();
+ if (tmp > maxWidth)
+ {
+ maxWidth = tmp;
+ }
+ }
+
+ for (int i = maxWidth; i > 0; i /= 10)
+ {
+ mask += "0";
+ }
+ return mask;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param g
+ * DOCUMENT ME!
+ * @param canvasWidth
+ * DOCUMENT ME!
+ * @param canvasHeight
+ * DOCUMENT ME!
+ * @param startRes
+ * DOCUMENT ME!
+ */
+ public void drawWrappedPanel(Graphics g, int canvasWidth,
+ int canvasHeight, int startRes)
+ {
+ updateViewport();
+ AlignmentI al = av.getAlignment();
+
+ FontMetrics fm = getFontMetrics(av.getFont());
+
+ if (av.getScaleRightWrapped())
+ {
+ LABEL_EAST = fm.stringWidth(getMask());
+ }
+
+ if (av.getScaleLeftWrapped())
+ {
+ LABEL_WEST = fm.stringWidth(getMask());
+ }
+
+ int hgap = charHeight;
+ if (av.getScaleAboveWrapped())
+ {
+ hgap += charHeight;
+ }
+
+ int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / charWidth;
+ int cHeight = av.getAlignment().getHeight() * charHeight;
+
+ av.setWrappedWidth(cWidth);
+
+ av.endRes = av.startRes + cWidth;
+
+ int endx;
+ int ypos = hgap;
+ int maxwidth = av.getAlignment().getWidth() - 1;
+
+ if (av.hasHiddenColumns())
+ {
+ maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
+ }
+
+ while ((ypos <= canvasHeight) && (startRes < maxwidth))
+ {
+ endx = startRes + cWidth - 1;
+
+ if (endx > maxwidth)
+ {
+ endx = maxwidth;
+ }
+
+ g.setFont(av.getFont());
+ g.setColor(Color.black);
+
+ if (av.getScaleLeftWrapped())
+ {
+ drawWestScale(g, startRes, endx, ypos);
+ }
+
+ if (av.getScaleRightWrapped())
+ {
+ g.translate(canvasWidth - LABEL_EAST, 0);
+ drawEastScale(g, startRes, endx, ypos);
+ g.translate(-(canvasWidth - LABEL_EAST), 0);
+ }
+
+ g.translate(LABEL_WEST, 0);
+
+ if (av.getScaleAboveWrapped())
+ {
+ drawNorthScale(g, startRes, endx, ypos);
+ }
+
+ if (av.hasHiddenColumns() && av.getShowHiddenMarkers())
+ {
+ g.setColor(Color.blue);
+ int res;
+ for (int i = 0; i < av.getColumnSelection().getHiddenColumns()
+ .size(); i++)
+ {
+ res = av.getColumnSelection().findHiddenRegionPosition(i)
+ - startRes;
+
+ if (res < 0 || res > endx - startRes)
+ {
+ continue;
+ }
+
+ gg.fillPolygon(
+ new int[] { res * charWidth - charHeight / 4,
+ res * charWidth + charHeight / 4, res * charWidth },
+ new int[] { ypos - (charHeight / 2),
+ ypos - (charHeight / 2), ypos - (charHeight / 2) + 8 },
+ 3);
+
+ }
+ }
+
+ // When printing we have an extra clipped region,
+ // the Printable page which we need to account for here
+ Shape clip = g.getClip();
+
+ if (clip == null)
+ {
+ g.setClip(0, 0, cWidth * charWidth, canvasHeight);
+ }
+ else
+ {
+ g.setClip(0, (int) clip.getBounds().getY(), cWidth * charWidth,
+ (int) clip.getBounds().getHeight());
+ }
+
+ drawPanel(g, startRes, endx, 0, al.getHeight(), ypos);
+
+ if (av.isShowAnnotation())
+ {
+ g.translate(0, cHeight + ypos + 3);
+ if (annotations == null)
+ {
+ annotations = new AnnotationPanel(av);
+ }
+
+ annotations.renderer.drawComponent(annotations, av, g, -1,
+ startRes, endx + 1);
+ g.translate(0, -cHeight - ypos - 3);
+ }
+ g.setClip(clip);
+ g.translate(-LABEL_WEST, 0);
+
+ ypos += cHeight + getAnnotationHeight() + hgap;
+
+ startRes += cWidth;
+ }
+ }
+
+ AnnotationPanel annotations;
+
+ int getAnnotationHeight()
+ {
+ if (!av.isShowAnnotation())
+ {
+ return 0;
+ }
+
+ if (annotations == null)
+ {
+ annotations = new AnnotationPanel(av);
+ }
+
+ return annotations.adjustPanelHeight();
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param g1
+ * DOCUMENT ME!
+ * @param startRes
+ * DOCUMENT ME!
+ * @param endRes
+ * DOCUMENT ME!
+ * @param startSeq
+ * DOCUMENT ME!
+ * @param endSeq
+ * DOCUMENT ME!
+ * @param offset
+ * DOCUMENT ME!
+ */
+ public void drawPanel(Graphics g1, int startRes, int endRes,
+ int startSeq, int endSeq, int offset)
+ {
+ updateViewport();
+ if (!av.hasHiddenColumns())
+ {
+ draw(g1, startRes, endRes, startSeq, endSeq, offset);
+ }
+ else
+ {
+ List<int[]> regions = av.getColumnSelection().getHiddenColumns();
+
+ int screenY = 0;
+ int blockStart = startRes;
+ int blockEnd = endRes;
+ int newY = 0, clip;
+ for (int[] region : regions)
+ {
+ int hideStart = region[0];
+ int hideEnd = region[1];
+
+ if (hideStart < blockStart)
+ {
+ blockStart += (hideEnd - hideStart) + 1;
+ continue;
+ }
+ blockEnd = hideStart - 1;
+
+ g1.translate(screenY * charWidth, 0);
+
+ // find end of this visible block
+ newY += blockEnd - blockStart + 1;
+
+ clip = newY - (endRes - startRes);
+ if (clip > 0)
+ {
+ blockEnd = blockStart + (endRes - startRes) - screenY;
+ }
+ // TODO: JAL-1722 - does this block need clipping ?
+ draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
+ // TODO: JAL-1722 - is this hidden marker visible ?
+ if (clip < -1 && av.getShowHiddenMarkers())
+ {
+ g1.setColor(Color.blue);
+
+ g1.drawLine((blockEnd - blockStart + 1) * charWidth - 1,
+ 0 + offset, (blockEnd - blockStart + 1) * charWidth - 1,
+ (endSeq - startSeq) * charHeight + offset);
+ }
+
+ g1.translate(-screenY * charWidth, 0);
+
+ screenY = newY;
+ blockStart = hideEnd + 1;
+
+ if (clip > 0)
+ {
+ // already rendered last block
+ return;
+ }
+ }
+
+ if (screenY <= (endRes - startRes))
+ {
+ // remaining visible region to render
+ blockEnd = blockStart + (endRes - startRes) - screenY;
+ g1.translate(screenY * charWidth, 0);
+ draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
+
+ g1.translate(-screenY * charWidth, 0);
+ }
+ }
+ }
+
+ // int startRes, int endRes, int startSeq, int endSeq, int x, int y,
+ // int x1, int x2, int y1, int y2, int startx, int starty,
+ private void draw(Graphics g, int startRes, int endRes, int startSeq,
+ int endSeq, int offset)
+ {
+ g.setFont(av.getFont());
+ sr.prepare(g, av.isRenderGaps());
+
+ SequenceI nextSeq;
+
+ // / First draw the sequences
+ // ///////////////////////////
+ for (int i = startSeq; i < endSeq; i++)
+ {
+ nextSeq = av.getAlignment().getSequenceAt(i);
+ if (nextSeq == null)
+ {
+ // occasionally, a race condition occurs such that the alignment row is
+ // empty
+ continue;
+ }
+ sr.drawSequence(nextSeq, av.getAlignment().findAllGroups(nextSeq),
+ startRes, endRes, offset + ((i - startSeq) * charHeight));
+
+ if (av.isShowSequenceFeatures())
+ {
+ fr.drawSequence(g, nextSeq, startRes, endRes, offset
+ + ((i - startSeq) * charHeight));
+ }
+
+ // / Highlight search Results once all sequences have been drawn
+ // ////////////////////////////////////////////////////////
+ if (searchResults != null)
+ {
+ int[] visibleResults = searchResults.getResults(nextSeq, startRes,
+ endRes);
+ if (visibleResults != null)
+ {
+ for (int r = 0; r < visibleResults.length; r += 2)
+ {
+ sr.drawHighlightedText(nextSeq, visibleResults[r],
+ visibleResults[r + 1], (visibleResults[r] - startRes)
+ * charWidth, offset
+ + ((i - startSeq) * charHeight));
+ }
+ }
+ }
+
+ if (av.cursorMode && cursorY == i && cursorX >= startRes
+ && cursorX <= endRes)
+ {
+ sr.drawCursor(nextSeq, cursorX, (cursorX - startRes) * charWidth,
+ offset + ((i - startSeq) * charHeight));
+ }
+ }
+
+ if (av.getSelectionGroup() != null
+ || av.getAlignment().getGroups().size() > 0)
+ {
+ drawGroupsBoundaries(g, startRes, endRes, startSeq, endSeq, offset);
+ }
+
+ }
+
+ void drawGroupsBoundaries(Graphics g1, int startRes, int endRes,
+ int startSeq, int endSeq, int offset)
+ {
+ Graphics2D g = (Graphics2D) g1;
+ //
+ // ///////////////////////////////////
+ // Now outline any areas if necessary
+ // ///////////////////////////////////
+ SequenceGroup group = av.getSelectionGroup();
+
+ int sx = -1;
+ int sy = -1;
+ int ex = -1;
+ int groupIndex = -1;
+ int visWidth = (endRes - startRes + 1) * charWidth;
+
+ if ((group == null) && (av.getAlignment().getGroups().size() > 0))
+ {
+ group = av.getAlignment().getGroups().get(0);
+ groupIndex = 0;
+ }
+
+ if (group != null)
+ {
+ do
+ {
+ int oldY = -1;
+ int i = 0;
+ boolean inGroup = false;
+ int top = -1;
+ int bottom = -1;
+
+ for (i = startSeq; i < endSeq; i++)
+ {
+ sx = (group.getStartRes() - startRes) * charWidth;
+ sy = offset + ((i - startSeq) * charHeight);
+ ex = (((group.getEndRes() + 1) - group.getStartRes()) * charWidth) - 1;
+
+ if (sx + ex < 0 || sx > visWidth)
+ {
+ continue;
+ }
+
+ if ((sx <= (endRes - startRes) * charWidth)
+ && group.getSequences(null).contains(
+ av.getAlignment().getSequenceAt(i)))
+ {
+ if ((bottom == -1)
+ && !group.getSequences(null).contains(
+ av.getAlignment().getSequenceAt(i + 1)))
+ {
+ bottom = sy + charHeight;
+ }
+
+ if (!inGroup)
+ {
+ if (((top == -1) && (i == 0))
+ || !group.getSequences(null).contains(
+ av.getAlignment().getSequenceAt(i - 1)))
+ {
+ top = sy;
+ }
+
+ oldY = sy;
+ inGroup = true;
+
+ if (group == av.getSelectionGroup())
+ {
+ g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
+ BasicStroke.JOIN_ROUND, 3f, new float[] { 5f, 3f },
+ 0f));
+ g.setColor(Color.RED);
+ }
+ else
+ {
+ g.setStroke(new BasicStroke());
+ g.setColor(group.getOutlineColour());
+ }
+ }
+ }
+ else
+ {
+ if (inGroup)
+ {
+ if (sx >= 0 && sx < visWidth)
+ {
+ g.drawLine(sx, oldY, sx, sy);
+ }
+
+ if (sx + ex < visWidth)
+ {
+ g.drawLine(sx + ex, oldY, sx + ex, sy);
+ }
+
+ if (sx < 0)
+ {
+ ex += sx;
+ sx = 0;
+ }
+
+ if (sx + ex > visWidth)
+ {
+ ex = visWidth;
+ }
+
+ else if (sx + ex >= (endRes - startRes + 1) * charWidth)
+ {
+ ex = (endRes - startRes + 1) * charWidth;
+ }
+
+ if (top != -1)
+ {
+ g.drawLine(sx, top, sx + ex, top);
+ top = -1;
+ }
+
+ if (bottom != -1)
+ {
+ g.drawLine(sx, bottom, sx + ex, bottom);
+ bottom = -1;
+ }
+
+ inGroup = false;
+ }
+ }
+ }
+
+ if (inGroup)
+ {
+ sy = offset + ((i - startSeq) * charHeight);
+ if (sx >= 0 && sx < visWidth)
+ {
+ g.drawLine(sx, oldY, sx, sy);
+ }
+
+ if (sx + ex < visWidth)
+ {
+ g.drawLine(sx + ex, oldY, sx + ex, sy);
+ }
+
+ if (sx < 0)
+ {
+ ex += sx;
+ sx = 0;
+ }
+
+ if (sx + ex > visWidth)
+ {
+ ex = visWidth;
+ }
+ else if (sx + ex >= (endRes - startRes + 1) * charWidth)
+ {
+ ex = (endRes - startRes + 1) * charWidth;
+ }
+
+ if (top != -1)
+ {
+ g.drawLine(sx, top, sx + ex, top);
+ top = -1;
+ }
+
+ if (bottom != -1)
+ {
+ g.drawLine(sx, bottom - 1, sx + ex, bottom - 1);
+ bottom = -1;
+ }
+
+ inGroup = false;
+ }
+
+ groupIndex++;
+
+ g.setStroke(new BasicStroke());
+
+ if (groupIndex >= av.getAlignment().getGroups().size())
+ {
+ break;
+ }
+
+ group = av.getAlignment().getGroups().get(groupIndex);
+
+ } while (groupIndex < av.getAlignment().getGroups().size());
+
+ }
+
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param results
+ * DOCUMENT ME!
+ */
+ public void highlightSearchResults(SearchResults results)
+ {
+ img = null;
+
+ searchResults = results;
+
+ repaint();
+ }
+}
import jalview.commands.EditCommand.Edit;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SearchResultMatchI;
import jalview.datamodel.SearchResults;
import jalview.datamodel.SearchResultsI;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import java.util.ListIterator;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
* @param evt
* @return
*/
- int findRes(MouseEvent evt)
+ int findColumn(MouseEvent evt)
{
int res = 0;
int x = evt.getX();
}
wrappedBlock = y / cHeight;
- wrappedBlock += av.getStartRes() / cwidth;
+ wrappedBlock += av.getRanges().getStartRes() / cwidth;
res = wrappedBlock * cwidth + x / av.getCharWidth();
// right-hand gutter
x = seqCanvas.getX() + seqCanvas.getWidth();
}
- res = (x / av.getCharWidth()) + av.getStartRes();
- if (res > av.getEndRes())
+ res = (x / av.getCharWidth()) + av.getRanges().getStartRes();
+ if (res > av.getRanges().getEndRes())
{
// moused off right
- res = av.getEndRes();
+ res = av.getRanges().getEndRes();
}
}
if (av.hasHiddenColumns())
{
- res = av.getColumnSelection().adjustForHiddenColumns(res);
+ res = av.getAlignment().getHiddenColumns()
+ .adjustForHiddenColumns(res);
}
return res;
}
else
{
- seq = Math.min((y / av.getCharHeight()) + av.getStartSeq(), av
+ seq = Math.min((y / av.getCharHeight())
+ + av.getRanges().getStartSeq(),
+ av
.getAlignment().getHeight() - 1);
}
{
seqCanvas.cursorX += dx;
seqCanvas.cursorY += dy;
+
+ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+
if (av.hasHiddenColumns()
- && !av.getColumnSelection().isVisible(seqCanvas.cursorX))
+ && !hidden.isVisible(seqCanvas.cursorX))
{
int original = seqCanvas.cursorX - dx;
int maxWidth = av.getAlignment().getWidth();
- while (!av.getColumnSelection().isVisible(seqCanvas.cursorX)
+ while (!hidden.isVisible(seqCanvas.cursorX)
&& seqCanvas.cursorX < maxWidth && seqCanvas.cursorX > 0)
{
seqCanvas.cursorX += dx;
}
if (seqCanvas.cursorX >= maxWidth
- || !av.getColumnSelection().isVisible(seqCanvas.cursorX))
+ || !hidden.isVisible(seqCanvas.cursorX))
{
seqCanvas.cursorX = original;
}
endEditing();
if (av.getWrapAlignment())
{
- ap.scrollToWrappedVisible(seqCanvas.cursorX);
+ av.getRanges().scrollToWrappedVisible(seqCanvas.cursorX);
}
else
{
- while (seqCanvas.cursorY < av.startSeq)
- {
- ap.scrollUp(true);
- }
- while (seqCanvas.cursorY + 1 > av.endSeq)
- {
- ap.scrollUp(false);
- }
- if (!av.getWrapAlignment())
- {
- while (seqCanvas.cursorX < av.getColumnSelection()
- .adjustForHiddenColumns(av.startRes))
- {
- if (!ap.scrollRight(false))
- {
- break;
- }
- }
- while (seqCanvas.cursorX > av.getColumnSelection()
- .adjustForHiddenColumns(av.endRes))
- {
- if (!ap.scrollRight(true))
- {
- break;
- }
- }
- }
+ av.getRanges().scrollToVisible(seqCanvas.cursorX, seqCanvas.cursorY);
}
setStatusMessage(av.getAlignment().getSequenceAt(seqCanvas.cursorY),
seqCanvas.cursorX, seqCanvas.cursorY);
@Override
public void mouseReleased(MouseEvent evt)
{
+ boolean didDrag = mouseDragging; // did we come here after a drag
mouseDragging = false;
mouseWheelPressed = false;
if (!editingSeqs)
{
- doMouseReleasedDefineMode(evt);
+ doMouseReleasedDefineMode(evt, didDrag);
return;
}
}
int seq = findSeq(evt);
- int res = findRes(evt);
+ int res = findColumn(evt);
if (seq < 0 || res < 0)
{
if (av.isFollowHighlight())
{
- /*
- * if scrollToPosition requires a scroll adjustment, this flag prevents
- * another scroll event being propagated back to the originator
- *
- * @see AlignmentPanel#adjustmentValueChanged
- */
- ap.setDontScrollComplement(true);
+ // don't allow highlight of protein/cDNA to also scroll a complementary
+ // panel,as this sets up a feedback loop (scrolling panel 1 causes moused
+ // over residue to change abruptly, causing highlighted residue in panel 2
+ // to change, causing a scroll in panel 1 etc)
+ ap.setToScrollComplementPanel(false);
if (ap.scrollToPosition(results, false))
{
seqCanvas.revalidate();
}
+ ap.setToScrollComplementPanel(true);
}
setStatusMessage(results);
seqCanvas.highlightSearchResults(results);
mouseDragged(evt);
}
- int res = findRes(evt);
+ final int column = findColumn(evt);
int seq = findSeq(evt);
- int pos;
- if (res < 0 || seq < 0 || seq >= av.getAlignment().getHeight())
+ if (column < 0 || seq < 0 || seq >= av.getAlignment().getHeight())
{
return;
}
SequenceI sequence = av.getAlignment().getSequenceAt(seq);
- if (res >= sequence.getLength())
+ if (column >= sequence.getLength())
{
return;
}
- pos = setStatusMessage(sequence, res, seq);
- if (ssm != null && pos > -1)
+ /*
+ * set status bar message, returning residue position in sequence
+ */
+ boolean isGapped = Comparison.isGap(sequence.getCharAt(column));
+ final int pos = setStatusMessage(sequence, column, seq);
+ if (ssm != null && !isGapped)
{
- mouseOverSequence(sequence, res, pos);
+ mouseOverSequence(sequence, column, pos);
}
tooltipText.setLength(6); // Cuts the buffer back to <html>
{
for (int g = 0; g < groups.length; g++)
{
- if (groups[g].getStartRes() <= res && groups[g].getEndRes() >= res)
+ if (groups[g].getStartRes() <= column
+ && groups[g].getEndRes() >= column)
{
if (!groups[g].getName().startsWith("JTreeGroup")
&& !groups[g].getName().startsWith("JGroup"))
}
}
- // use aa to see if the mouse pointer is on a
+ /*
+ * add any features at the position to the tooltip; if over a gap, only
+ * add features that straddle the gap (pos may be the residue before or
+ * after the gap)
+ */
if (av.isShowSequenceFeatures())
{
- int rpos;
List<SequenceFeature> features = ap.getFeatureRenderer()
- .findFeaturesAtRes(sequence.getDatasetSequence(),
- rpos = sequence.findPosition(res));
- seqARep.appendFeatures(tooltipText, rpos, features,
+ .findFeaturesAtRes(sequence.getDatasetSequence(), pos);
+ if (isGapped)
+ {
+ removeAdjacentFeatures(features, column + 1, sequence);
+ }
+ seqARep.appendFeatures(tooltipText, pos, features,
this.ap.getSeqPanel().seqCanvas.fr.getMinMax());
}
if (tooltipText.length() == 6) // <html>
}
+ /**
+ * Removes from the list of features any that start after, or end before, the
+ * given column position. This allows us to retain only those features
+ * adjacent to a gapped position that straddle the position. Contact features
+ * that 'straddle' the position are also removed, since they are not 'at' the
+ * position.
+ *
+ * @param features
+ * @param column
+ * alignment column (1..)
+ * @param sequence
+ */
+ protected void removeAdjacentFeatures(List<SequenceFeature> features,
+ final int column, SequenceI sequence)
+ {
+ // TODO should this be an AlignViewController method (and reused by applet)?
+ ListIterator<SequenceFeature> it = features.listIterator();
+ while (it.hasNext())
+ {
+ SequenceFeature sf = it.next();
+ if (sf.isContactFeature()
+ || sequence.findIndex(sf.getBegin()) > column
+ || sequence.findIndex(sf.getEnd()) < column)
+ {
+ it.remove();
+ }
+ }
+ }
+
private Point lastp = null;
/*
// avcontroller or viewModel
/**
- * Set status message in alignment panel
+ * Sets the status message in alignment panel, showing the sequence number
+ * (index) and id, and residue and residue position if not at a gap, for the
+ * given sequence and column position. Returns the residue position returned
+ * by Sequence.findPosition. Note this may be for the nearest adjacent residue
+ * if at a gapped position.
*
* @param sequence
* aligned sequence object
- * @param res
+ * @param column
* alignment column
* @param seq
* index of sequence in alignment
- * @return position of res in sequence
+ * @return sequence position of residue at column, or adjacent residue if at a
+ * gap
*/
- int setStatusMessage(SequenceI sequence, int res, int seq)
+ int setStatusMessage(SequenceI sequence, final int column, int seq)
{
StringBuilder text = new StringBuilder(32);
.append(sequence.getName());
String residue = null;
+
/*
* Try to translate the display character to residue name (null for gap).
*/
- final String displayChar = String.valueOf(sequence.getCharAt(res));
- if (av.getAlignment().isNucleotide())
+ final String displayChar = String.valueOf(sequence.getCharAt(column));
+ boolean isGapped = Comparison.isGap(sequence.getCharAt(column));
+ int pos = sequence.findPosition(column);
+
+ if (!isGapped)
{
- residue = ResidueProperties.nucleotideName.get(displayChar);
- if (residue != null)
+ boolean nucleotide = av.getAlignment().isNucleotide();
+ if (nucleotide)
{
- text.append(" Nucleotide: ").append(residue);
+ residue = ResidueProperties.nucleotideName.get(displayChar);
}
- }
- else
- {
- residue = "X".equalsIgnoreCase(displayChar) ? "X" : ("*"
- .equals(displayChar) ? "STOP" : ResidueProperties.aa2Triplet
- .get(displayChar));
- if (residue != null)
+ else
{
- text.append(" Residue: ").append(residue);
+ residue = "X".equalsIgnoreCase(displayChar) ? "X" : ("*"
+ .equals(displayChar) ? "STOP"
+ : ResidueProperties.aa2Triplet.get(displayChar));
}
- }
+ text.append(" ").append(nucleotide ? "Nucleotide" : "Residue")
+ .append(": ").append(residue == null ? displayChar : residue);
- int pos = -1;
- if (residue != null)
- {
- pos = sequence.findPosition(res);
text.append(" (").append(Integer.toString(pos)).append(")");
}
ap.alignFrame.statusBar.setText(text.toString());
+
return pos;
}
}
/**
- * DOCUMENT ME!
- *
- * @param evt
- * DOCUMENT ME!
+ * {@inheritDoc}
*/
@Override
public void mouseDragged(MouseEvent evt)
{
if (mouseWheelPressed)
{
+ boolean inSplitFrame = ap.av.getCodingComplement() != null;
+ boolean copyChanges = inSplitFrame && av.isProteinFontAsCdna();
+
int oldWidth = av.getCharWidth();
// Which is bigger, left-right or up-down?
if (Math.abs(evt.getY() - lastMousePress.getY()) > Math.abs(evt
.getX() - lastMousePress.getX()))
{
+ /*
+ * on drag up or down, decrement or increment font size
+ */
int fontSize = av.font.getSize();
+ boolean fontChanged = false;
if (evt.getY() < lastMousePress.getY())
{
+ fontChanged = true;
fontSize--;
}
else if (evt.getY() > lastMousePress.getY())
{
+ fontChanged = true;
fontSize++;
}
fontSize = 1;
}
- av.setFont(
- new Font(av.font.getName(), av.font.getStyle(), fontSize),
- true);
- av.setCharWidth(oldWidth);
- ap.fontChanged();
+ if (fontChanged)
+ {
+ Font newFont = new Font(av.font.getName(), av.font.getStyle(),
+ fontSize);
+ av.setFont(newFont, true);
+ av.setCharWidth(oldWidth);
+ ap.fontChanged();
+ if (copyChanges)
+ {
+ ap.av.getCodingComplement().setFont(newFont, true);
+ SplitFrame splitFrame = (SplitFrame) ap.alignFrame
+ .getSplitViewContainer();
+ splitFrame.adjustLayout();
+ splitFrame.repaint();
+ }
+ }
}
else
{
+ /*
+ * on drag left or right, decrement or increment character width
+ */
+ int newWidth = 0;
if (evt.getX() < lastMousePress.getX() && av.getCharWidth() > 1)
{
- av.setCharWidth(av.getCharWidth() - 1);
+ newWidth = av.getCharWidth() - 1;
+ av.setCharWidth(newWidth);
}
else if (evt.getX() > lastMousePress.getX())
{
- av.setCharWidth(av.getCharWidth() + 1);
+ newWidth = av.getCharWidth() + 1;
+ av.setCharWidth(newWidth);
+ }
+ if (newWidth > 0)
+ {
+ ap.paintAlignment(false);
+ if (copyChanges)
+ {
+ /*
+ * need to ensure newWidth is set on cdna, regardless of which
+ * panel the mouse drag happened in; protein will compute its
+ * character width as 1:1 or 3:1
+ */
+ av.getCodingComplement().setCharWidth(newWidth);
+ SplitFrame splitFrame = (SplitFrame) ap.alignFrame
+ .getSplitViewContainer();
+ splitFrame.adjustLayout();
+ splitFrame.repaint();
+ }
}
-
- ap.paintAlignment(false);
}
FontMetrics fm = getFontMetrics(av.getFont());
return;
}
- int res = findRes(evt);
+ int res = findColumn(evt);
if (res < 0)
{
if (av.hasHiddenColumns())
{
fixedColumns = true;
- int y1 = av.getColumnSelection().getHiddenBoundaryLeft(startres);
- int y2 = av.getColumnSelection().getHiddenBoundaryRight(startres);
+ int y1 = av.getAlignment().getHiddenColumns()
+ .getHiddenBoundaryLeft(startres);
+ int y2 = av.getAlignment().getHiddenColumns()
+ .getHiddenBoundaryRight(startres);
if ((insertGap && startres > y1 && lastres < y1)
|| (!insertGap && startres < y2 && lastres > y2))
{
if (sg.getSize() == av.getAlignment().getHeight())
{
- if ((av.hasHiddenColumns() && startres < av
- .getColumnSelection().getHiddenBoundaryRight(startres)))
+ if ((av.hasHiddenColumns() && startres < av.getAlignment()
+ .getHiddenColumns().getHiddenBoundaryRight(startres)))
{
endEditing();
return;
}
}
+ /**
+ * Handler for double-click on a position with one or more sequence features.
+ * Opens the Amend Features dialog to allow feature details to be amended, or
+ * the feature deleted.
+ */
@Override
public void mouseClicked(MouseEvent evt)
{
av.setSelectionGroup(null);
}
+ int column = findColumn(evt);
+ boolean isGapped = Comparison.isGap(sequence.getCharAt(column));
+
+ /*
+ * find features at the position (if not gapped), or straddling
+ * the position (if at a gap)
+ */
List<SequenceFeature> features = seqCanvas.getFeatureRenderer()
.findFeaturesAtRes(sequence.getDatasetSequence(),
- sequence.findPosition(findRes(evt)));
+ sequence.findPosition(column));
+ if (isGapped)
+ {
+ removeAdjacentFeatures(features, column, sequence);
+ }
- if (features != null && features.size() > 0)
+ if (!features.isEmpty())
{
+ /*
+ * highlight the first feature at the position on the alignment
+ */
SearchResultsI highlight = new SearchResults();
highlight.addResult(sequence, features.get(0).getBegin(), features
.get(0).getEnd());
seqCanvas.highlightSearchResults(highlight);
- }
- if (features != null && features.size() > 0)
- {
- seqCanvas.getFeatureRenderer().amendFeatures(
- new SequenceI[] { sequence },
- features.toArray(new SequenceFeature[features.size()]),
- false, ap);
+ /*
+ * open the Amend Features dialog; clear highlighting afterwards,
+ * whether changes were made or not
+ */
+ List<SequenceI> seqs = Collections.singletonList(sequence);
+ seqCanvas.getFeatureRenderer().amendFeatures(seqs, features, false,
+ ap);
seqCanvas.highlightSearchResults(null);
}
}
{
if (e.isShiftDown())
{
- ap.scrollRight(true);
+ av.getRanges().scrollRight(true);
}
else
{
- ap.scrollUp(false);
+ av.getRanges().scrollUp(false);
}
}
else
{
if (e.isShiftDown())
{
- ap.scrollRight(false);
+ av.getRanges().scrollRight(false);
}
else
{
- ap.scrollUp(true);
+ av.getRanges().scrollUp(true);
}
}
// TODO Update tooltip for new position.
*/
public void doMousePressedDefineMode(MouseEvent evt)
{
- final int res = findRes(evt);
+ final int res = findColumn(evt);
final int seq = findSeq(evt);
oldSeq = seq;
needOverviewUpdate = false;
stretchGroup = av.getSelectionGroup();
- if (stretchGroup == null)
+ if (stretchGroup == null || !stretchGroup.contains(sequence, res))
{
stretchGroup = av.getAlignment().findGroup(sequence, res);
- av.setSelectionGroup(stretchGroup);
- }
- if (stretchGroup == null
- || !stretchGroup.getSequences(null).contains(sequence)
- || (stretchGroup.getStartRes() > res)
- || (stretchGroup.getEndRes() < res))
- {
- stretchGroup = null;
-
- SequenceGroup[] allGroups = av.getAlignment().findAllGroups(sequence);
-
- if (allGroups != null)
+ if (stretchGroup != null)
{
- for (int i = 0; i < allGroups.length; i++)
- {
- if ((allGroups[i].getStartRes() <= res)
- && (allGroups[i].getEndRes() >= res))
- {
- stretchGroup = allGroups[i];
- break;
- }
- }
+ // only update the current selection if the popup menu has a group to
+ // focus on
+ av.setSelectionGroup(stretchGroup);
}
-
- av.setSelectionGroup(stretchGroup);
}
if (evt.isPopupTrigger()) // Mac: mousePressed
if (av.cursorMode)
{
- seqCanvas.cursorX = findRes(evt);
+ seqCanvas.cursorX = findColumn(evt);
seqCanvas.cursorY = findSeq(evt);
seqCanvas.repaint();
return;
SliderPanel.setPIDSliderSource(ap, av.getResidueShading(),
ap.getViewName());
}
+ // TODO: stretchGroup will always be not null. Is this a merge error ?
if ((stretchGroup != null) && (stretchGroup.getEndRes() == res))
{
// Edit end res position of selected group
*
* @param evt
* @param res
- * @param sequence
+ * @param sequences
*/
void showPopupMenu(MouseEvent evt)
{
- final int res = findRes(evt);
+ final int res = findColumn(evt);
final int seq = findSeq(evt);
SequenceI sequence = av.getAlignment().getSequenceAt(seq);
List<SequenceFeature> allFeatures = ap.getFeatureRenderer()
.findFeaturesAtRes(sequence.getDatasetSequence(),
sequence.findPosition(res));
- List<String> links = new ArrayList<String>();
+ List<String> links = new ArrayList<>();
for (SequenceFeature sf : allFeatures)
{
if (sf.links != null)
}
/**
- * DOCUMENT ME!
+ * Update the display after mouse up on a selection or group
*
* @param evt
- * DOCUMENT ME!
+ * mouse released event details
+ * @param afterDrag
+ * true if this event is happening after a mouse drag (rather than a
+ * mouse down)
*/
- public void doMouseReleasedDefineMode(MouseEvent evt)
+ public void doMouseReleasedDefineMode(MouseEvent evt, boolean afterDrag)
{
if (stretchGroup == null)
{
// always do this - annotation has own state
// but defer colourscheme update until hidden sequences are passed in
boolean vischange = stretchGroup.recalcConservation(true);
- needOverviewUpdate |= vischange && av.isSelectionDefinedGroup();
+ needOverviewUpdate |= vischange && av.isSelectionDefinedGroup()
+ && afterDrag;
if (stretchGroup.cs != null)
{
stretchGroup.cs.alignmentChanged(stretchGroup,
*/
public void doMouseDraggedDefineMode(MouseEvent evt)
{
- int res = findRes(evt);
+ int res = findColumn(evt);
int y = findSeq(evt);
if (wrappedBlock != startWrapBlock)
changeStartRes = true;
}
- if (res < av.getStartRes())
+ if (res < av.getRanges().getStartRes())
{
- res = av.getStartRes();
+ res = av.getRanges().getStartRes();
}
if (changeEndRes)
{
if (evt != null)
{
- if (mouseDragging && (evt.getY() < 0) && (av.getStartSeq() > 0))
+ if (mouseDragging && (evt.getY() < 0)
+ && (av.getRanges().getStartSeq() > 0))
{
- running = ap.scrollUp(true);
+ running = av.getRanges().scrollUp(true);
}
if (mouseDragging && (evt.getY() >= getHeight())
- && (av.getAlignment().getHeight() > av.getEndSeq()))
+ && (av.getAlignment().getHeight() > av.getRanges()
+ .getEndSeq()))
{
- running = ap.scrollUp(false);
+ running = av.getRanges().scrollUp(false);
}
if (mouseDragging && (evt.getX() < 0))
{
- running = ap.scrollRight(false);
+ running = av.getRanges().scrollRight(false);
}
else if (mouseDragging && (evt.getX() >= getWidth()))
{
- running = ap.scrollRight(true);
+ running = av.getRanges().scrollRight(true);
}
}
*/
@Override
public void selection(SequenceGroup seqsel, ColumnSelection colsel,
- SelectionSource source)
+ HiddenColumns hidden, SelectionSource source)
{
// TODO: fix this hack - source of messages is align viewport, but SeqPanel
// handles selection messages...
// shared between viewports.
boolean iSentTheSelection = (av == source || (source instanceof AlignViewport && ((AlignmentViewport) source)
.getSequenceSetId().equals(av.getSequenceSetId())));
- if (iSentTheSelection || !av.followSelection)
+
+ if (iSentTheSelection)
+ {
+ // respond to our own event by updating dependent dialogs
+ if (ap.getCalculationDialog() != null)
+ {
+ ap.getCalculationDialog().validateCalcTypes();
+ }
+
+ return;
+ }
+
+ // process further ?
+ if (!av.followSelection)
{
return;
}
* Check for selection in a view of which this one is a dna/protein
* complement.
*/
- if (selectionFromTranslation(seqsel, colsel, source))
+ if (selectionFromTranslation(seqsel, colsel, hidden, source))
{
return;
}
}
else
{
- av.getColumnSelection().setElementsFrom(colsel);
+ av.getColumnSelection().setElementsFrom(colsel,
+ av.getAlignment().getHiddenColumns());
}
}
av.isColSelChanged(true);
if (copycolsel
&& av.hasHiddenColumns()
- && (av.getColumnSelection() == null || av.getColumnSelection()
- .getHiddenColumns() == null))
+ && (av.getAlignment().getHiddenColumns() == null || av
+ .getAlignment().getHiddenColumns().getHiddenRegions() == null))
{
System.err.println("Bad things");
}
PaintRefresher.Refresh(this, av.getSequenceSetId());
// ap.paintAlignment(false);
}
+
+ // lastly, update dependent dialogs
+ if (ap.getCalculationDialog() != null)
+ {
+ ap.getCalculationDialog().validateCalcTypes();
+ }
+
}
/**
* @param source
*/
protected boolean selectionFromTranslation(SequenceGroup seqsel,
- ColumnSelection colsel, SelectionSource source)
+ ColumnSelection colsel, HiddenColumns hidden,
+ SelectionSource source)
{
if (!(source instanceof AlignViewportI))
{
/*
* Map column selection
*/
- ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
- av);
+ // ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
+ // av);
+ ColumnSelection cs = new ColumnSelection();
+ HiddenColumns hs = new HiddenColumns();
+ MappingUtils.mapColumnSelection(colsel, hidden, sourceAv, av, cs, hs);
av.setColumnSelection(cs);
+ av.getAlignment().setHiddenColumns(hs);
+
+ // lastly, update any dependent dialogs
+ if (ap.getCalculationDialog() != null)
+ {
+ ap.getCalculationDialog().validateCalcTypes();
+ }
PaintRefresher.Refresh(this, av.getSequenceSetId());
import javax.swing.JCheckBox;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
-import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
*/
package jalview.gui;
-import jalview.api.FeatureRenderer;
+import jalview.api.AlignViewportI;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.renderer.ResidueShaderI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.util.Comparison;
import java.awt.Color;
{
final static int CHAR_TO_UPPER = 'A' - 'a';
- AlignViewport av;
+ AlignViewportI av;
FontMetrics fm;
boolean forOverview = false;
/**
- * Creates a new SequenceRenderer object.
+ * Creates a new SequenceRenderer object
*
- * @param av
- * DOCUMENT ME!
+ * @param viewport
*/
- public SequenceRenderer(AlignViewport av)
+ public SequenceRenderer(AlignViewportI viewport)
{
- this.av = av;
+ this.av = viewport;
}
/**
this.renderGaps = renderGaps;
}
- @Override
- public Color getResidueBoxColour(SequenceI seq, int i)
+ protected Color getResidueBoxColour(SequenceI seq, int i)
{
// rate limiting step when rendering overview for lots of groups
allGroups = av.getAlignment().findAllGroups(seq);
*
* @param seq
* @param position
- * @param fr
+ * @param finder
* @return
*/
@Override
public Color getResidueColour(final SequenceI seq, int position,
- FeatureRenderer fr)
+ FeatureColourFinder finder)
{
- // TODO replace 8 or so code duplications with calls to this method
- // (refactored as needed)
Color col = getResidueBoxColour(seq, position);
- if (fr != null)
+ if (finder != null)
{
- col = fr.findFeatureColour(col, seq, position);
+ col = finder.findFeatureColour(col, seq, position);
}
return col;
}
*/
void getBoxColour(ResidueShaderI shader, SequenceI seq, int i)
{
- if (shader != null)
+ if (shader.getColourScheme() != null)
{
resBoxColour = shader.findColour(seq.getCharAt(i),
i, seq);
drawBoxes(seq, start, end, y1);
- if (av.validCharWidth)
+ if (av.isValidCharWidth())
{
drawText(seq, start, end, y1);
}
package jalview.gui;
import jalview.api.SplitContainerI;
-import jalview.api.ViewStyleI;
import jalview.datamodel.AlignmentI;
import jalview.jbgui.GAlignFrame;
import jalview.jbgui.GSplitFrame;
: (!bottomAlignment.isNucleotide() ? bottomViewport : null);
if (protein != null && cdna != null)
{
- ViewStyleI vs = protein.getViewStyle();
- int scale = vs.isScaleProteinAsCdna() ? 3 : 1;
- vs.setCharWidth(scale * cdna.getViewStyle().getCharWidth());
- protein.setViewStyle(vs);
+ int scale = protein.isScaleProteinAsCdna() ? 3 : 1;
+ protein.setCharWidth(scale * cdna.getViewStyle().getCharWidth());
}
}
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
-import javax.swing.JOptionPane;
import javax.swing.table.AbstractTableModel;
/**
if (haveData)
{
cmb_filterOption.addItem(new FilterOption("Best Quality",
- "overall_quality", VIEWS_FILTER));
+ "overall_quality", VIEWS_FILTER, false));
cmb_filterOption.addItem(new FilterOption("Best Resolution",
- "resolution", VIEWS_FILTER));
+ "resolution", VIEWS_FILTER, false));
cmb_filterOption.addItem(new FilterOption("Most Protein Chain",
- "number_of_protein_chains", VIEWS_FILTER));
+ "number_of_protein_chains", VIEWS_FILTER, false));
cmb_filterOption.addItem(new FilterOption("Most Bound Molecules",
- "number_of_bound_molecules", VIEWS_FILTER));
+ "number_of_bound_molecules", VIEWS_FILTER, false));
cmb_filterOption.addItem(new FilterOption("Most Polymer Residues",
- "number_of_polymer_residues", VIEWS_FILTER));
+ "number_of_polymer_residues", VIEWS_FILTER, true));
}
cmb_filterOption.addItem(new FilterOption("Enter PDB Id", "-",
- VIEWS_ENTER_ID));
+ VIEWS_ENTER_ID, false));
cmb_filterOption.addItem(new FilterOption("From File", "-",
- VIEWS_FROM_FILE));
- FilterOption cachedOption = new FilterOption("Cached PDB Entries", "-",
- VIEWS_LOCAL_PDB);
- cmb_filterOption.addItem(cachedOption);
+ VIEWS_FROM_FILE, false));
- if (/*!haveData &&*/cachedPDBExists)
+ if (cachedPDBExists)
{
+ FilterOption cachedOption = new FilterOption("Cached PDB Entries",
+ "-", VIEWS_LOCAL_PDB, false);
+ cmb_filterOption.addItem(cachedOption);
cmb_filterOption.setSelectedItem(cachedOption);
}
--- /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.
+ */
+
+package jalview.gui;
+
+import jalview.bin.Jalview;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSData;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.fts.service.pdb.PDBFTSRestClient;
+import jalview.jbgui.GStructureChooser;
+import jalview.structure.StructureSelectionManager;
+import jalview.util.MessageManager;
+import jalview.ws.DBRefFetcher;
+import jalview.ws.sifts.SiftsSettings;
+
+import java.awt.event.ItemEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Vector;
+
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.table.AbstractTableModel;
+
+/**
+ * Provides the behaviors for the Structure chooser Panel
+ *
+ * @author tcnofoegbu
+ *
+ */
+@SuppressWarnings("serial")
+public class StructureChooser extends GStructureChooser implements
+ IProgressIndicator
+{
+ private boolean structuresDiscovered = false;
+
+ private SequenceI selectedSequence;
+
+ private SequenceI[] selectedSequences;
+
+ private IProgressIndicator progressIndicator;
+
+ private Collection<FTSData> discoveredStructuresSet;
+
+ private FTSRestRequest lastPdbRequest;
+
+ private FTSRestClientI pdbRestCleint;
+
+ private String selectedPdbFileName;
+
+ private boolean isValidPBDEntry;
+
+ public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
+ AlignmentPanel ap)
+ {
+ this.ap = ap;
+ this.selectedSequence = selectedSeq;
+ this.selectedSequences = selectedSeqs;
+ this.progressIndicator = (ap == null) ? null : ap.alignFrame;
+ init();
+ }
+
+ /**
+ * Initializes parameters used by the Structure Chooser Panel
+ */
+ public void init()
+ {
+ if (!Jalview.isHeadlessMode())
+ {
+ progressBar = new ProgressBar(this.statusPanel, this.statusBar);
+ }
+
+ Thread discoverPDBStructuresThread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ long startTime = System.currentTimeMillis();
+ updateProgressIndicator(MessageManager
+ .getString("status.loading_cached_pdb_entries"), startTime);
+ loadLocalCachedPDBEntries();
+ updateProgressIndicator(null, startTime);
+ updateProgressIndicator(MessageManager
+ .getString("status.searching_for_pdb_structures"),
+ startTime);
+ fetchStructuresMetaData();
+ populateFilterComboBox();
+ updateProgressIndicator(null, startTime);
+ mainFrame.setVisible(true);
+ updateCurrentView();
+ }
+ });
+ discoverPDBStructuresThread.start();
+ }
+
+ /**
+ * Updates the progress indicator with the specified message
+ *
+ * @param message
+ * displayed message for the operation
+ * @param id
+ * unique handle for this indicator
+ */
+ public void updateProgressIndicator(String message, long id)
+ {
+ if (progressIndicator != null)
+ {
+ progressIndicator.setProgressBar(message, id);
+ }
+ }
+
+ /**
+ * Retrieve meta-data for all the structure(s) for a given sequence(s) in a
+ * selection group
+ */
+ public void fetchStructuresMetaData()
+ {
+ long startTime = System.currentTimeMillis();
+ pdbRestCleint = PDBFTSRestClient.getInstance();
+ Collection<FTSDataColumnI> wantedFields = pdbDocFieldPrefs
+ .getStructureSummaryFields();
+
+ discoveredStructuresSet = new LinkedHashSet<FTSData>();
+ HashSet<String> errors = new HashSet<String>();
+ for (SequenceI seq : selectedSequences)
+ {
+ FTSRestRequest pdbRequest = new FTSRestRequest();
+ pdbRequest.setAllowEmptySeq(false);
+ pdbRequest.setResponseSize(500);
+ pdbRequest.setFieldToSearchBy("(");
+ pdbRequest.setWantedFields(wantedFields);
+ pdbRequest.setSearchTerm(buildQuery(seq) + ")");
+ pdbRequest.setAssociatedSequence(seq);
+ FTSRestResponse resultList;
+ try
+ {
+ resultList = pdbRestCleint.executeRequest(pdbRequest);
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ errors.add(e.getMessage());
+ continue;
+ }
+ lastPdbRequest = pdbRequest;
+ if (resultList.getSearchSummary() != null
+ && !resultList.getSearchSummary().isEmpty())
+ {
+ discoveredStructuresSet.addAll(resultList.getSearchSummary());
+ }
+ }
+
+ int noOfStructuresFound = 0;
+ String totalTime = (System.currentTimeMillis() - startTime)
+ + " milli secs";
+ if (discoveredStructuresSet != null
+ && !discoveredStructuresSet.isEmpty())
+ {
+ getResultTable().setModel(
+ FTSRestResponse.getTableModel(lastPdbRequest,
+ discoveredStructuresSet));
+ structuresDiscovered = true;
+ noOfStructuresFound = discoveredStructuresSet.size();
+ mainFrame.setTitle(MessageManager.formatMessage(
+ "label.structure_chooser_no_of_structures",
+ noOfStructuresFound, totalTime));
+ }
+ else
+ {
+ mainFrame.setTitle(MessageManager
+ .getString("label.structure_chooser_manual_association"));
+ if (errors.size() > 0)
+ {
+ StringBuilder errorMsg = new StringBuilder();
+ for (String error : errors)
+ {
+ errorMsg.append(error).append("\n");
+ }
+ JOptionPane.showMessageDialog(this, errorMsg.toString(),
+ MessageManager.getString("label.pdb_web-service_error"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+
+ public void loadLocalCachedPDBEntries()
+ {
+ ArrayList<CachedPDB> entries = new ArrayList<CachedPDB>();
+ for (SequenceI seq : selectedSequences)
+ {
+ if (seq.getDatasetSequence() != null
+ && seq.getDatasetSequence().getAllPDBEntries() != null)
+ {
+ for (PDBEntry pdbEntry : seq.getDatasetSequence()
+ .getAllPDBEntries())
+ {
+ if (pdbEntry.getFile() != null)
+ {
+ entries.add(new CachedPDB(seq, pdbEntry));
+ }
+ }
+ }
+ }
+
+ PDBEntryTableModel tableModelx = new PDBEntryTableModel(entries);
+ tbl_local_pdb.setModel(tableModelx);
+ }
+
+ /**
+ * Builds a query string for a given sequences using its DBRef entries
+ *
+ * @param seq
+ * the sequences to build a query for
+ * @return the built query string
+ */
+
+ public static String buildQuery(SequenceI seq)
+ {
+ boolean isPDBRefsFound = false;
+ boolean isUniProtRefsFound = false;
+ StringBuilder queryBuilder = new StringBuilder();
+ HashSet<String> seqRefs = new LinkedHashSet<String>();
+
+ if (seq.getAllPDBEntries() != null)
+ {
+ for (PDBEntry entry : seq.getAllPDBEntries())
+ {
+ if (isValidSeqName(entry.getId()))
+ {
+ queryBuilder.append("pdb_id")
+ .append(":")
+.append(entry.getId().toLowerCase())
+ .append(" OR ");
+ isPDBRefsFound = true;
+ // seqRefs.add(entry.getId());
+ }
+ }
+ }
+
+ if (seq.getDBRefs() != null && seq.getDBRefs().length != 0)
+ {
+ for (DBRefEntry dbRef : seq.getDBRefs())
+ {
+ if (isValidSeqName(getDBRefId(dbRef)))
+ {
+ if (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT))
+ {
+ queryBuilder
+.append("uniprot_accession").append(":")
+ .append(getDBRefId(dbRef))
+ .append(" OR ");
+ queryBuilder
+.append("uniprot_id")
+ .append(":")
+ .append(getDBRefId(dbRef)).append(" OR ");
+ isUniProtRefsFound = true;
+ }
+ else if (dbRef.getSource().equalsIgnoreCase(DBRefSource.PDB))
+ {
+
+ queryBuilder.append("pdb_id")
+ .append(":").append(getDBRefId(dbRef).toLowerCase())
+ .append(" OR ");
+ isPDBRefsFound = true;
+ }
+ else
+ {
+ seqRefs.add(getDBRefId(dbRef));
+ }
+ }
+ }
+ }
+
+ if (!isPDBRefsFound && !isUniProtRefsFound)
+ {
+ String seqName = seq.getName();
+ seqName = sanitizeSeqName(seqName);
+ String[] names = seqName.toLowerCase().split("\\|");
+ for (String name : names)
+ {
+ // System.out.println("Found name : " + name);
+ name.trim();
+ if (isValidSeqName(name))
+ {
+ seqRefs.add(name);
+ }
+ }
+
+ for (String seqRef : seqRefs)
+ {
+ queryBuilder.append("text:").append(seqRef).append(" OR ");
+ }
+ }
+
+ int endIndex = queryBuilder.lastIndexOf(" OR ");
+ if (queryBuilder.toString().length() < 6)
+ {
+ return null;
+ }
+ String query = queryBuilder.toString().substring(0, endIndex);
+ return query;
+ }
+
+ /**
+ * Remove the following special characters from input string +, -, &, !, (, ),
+ * {, }, [, ], ^, ", ~, *, ?, :, \
+ *
+ * @param seqName
+ * @return
+ */
+ static String sanitizeSeqName(String seqName)
+ {
+ Objects.requireNonNull(seqName);
+ return seqName.replaceAll("\\[\\d*\\]", "")
+ .replaceAll("[^\\dA-Za-z|_]", "").replaceAll("\\s+", "+");
+ }
+
+
+ /**
+ * Ensures sequence ref names are not less than 3 characters and does not
+ * contain a database name
+ *
+ * @param seqName
+ * @return
+ */
+ public static boolean isValidSeqName(String seqName)
+ {
+ // System.out.println("seqName : " + seqName);
+ String ignoreList = "pdb,uniprot,swiss-prot";
+ if (seqName.length() < 3)
+ {
+ return false;
+ }
+ if (seqName.contains(":"))
+ {
+ return false;
+ }
+ seqName = seqName.toLowerCase();
+ for (String ignoredEntry : ignoreList.split(","))
+ {
+ if (seqName.contains(ignoredEntry))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static String getDBRefId(DBRefEntry dbRef)
+ {
+ String ref = dbRef.getAccessionId().replaceAll("GO:", "");
+ return ref;
+ }
+
+ /**
+ * Filters a given list of discovered structures based on supplied argument
+ *
+ * @param fieldToFilterBy
+ * the field to filter by
+ */
+ public void filterResultSet(final String fieldToFilterBy)
+ {
+ Thread filterThread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ long startTime = System.currentTimeMillis();
+ pdbRestCleint = PDBFTSRestClient.getInstance();
+ lbl_loading.setVisible(true);
+ Collection<FTSDataColumnI> wantedFields = pdbDocFieldPrefs
+ .getStructureSummaryFields();
+ Collection<FTSData> filteredResponse = new HashSet<FTSData>();
+ HashSet<String> errors = new HashSet<String>();
+
+ for (SequenceI seq : selectedSequences)
+ {
+ FTSRestRequest pdbRequest = new FTSRestRequest();
+ if (fieldToFilterBy.equalsIgnoreCase("uniprot_coverage"))
+ {
+ pdbRequest.setAllowEmptySeq(false);
+ pdbRequest.setResponseSize(1);
+ pdbRequest.setFieldToSearchBy("(");
+ pdbRequest.setSearchTerm(buildQuery(seq) + ")");
+ pdbRequest.setWantedFields(wantedFields);
+ pdbRequest.setAssociatedSequence(seq);
+ pdbRequest.setFacet(true);
+ pdbRequest.setFacetPivot(fieldToFilterBy + ",entry_entity");
+ pdbRequest.setFacetPivotMinCount(1);
+ }
+ else
+ {
+ pdbRequest.setAllowEmptySeq(false);
+ pdbRequest.setResponseSize(1);
+ pdbRequest.setFieldToSearchBy("(");
+ pdbRequest.setFieldToSortBy(fieldToFilterBy,
+ !chk_invertFilter.isSelected());
+ pdbRequest.setSearchTerm(buildQuery(seq) + ")");
+ pdbRequest.setWantedFields(wantedFields);
+ pdbRequest.setAssociatedSequence(seq);
+ }
+ FTSRestResponse resultList;
+ try
+ {
+ resultList = pdbRestCleint.executeRequest(pdbRequest);
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ errors.add(e.getMessage());
+ continue;
+ }
+ lastPdbRequest = pdbRequest;
+ if (resultList.getSearchSummary() != null
+ && !resultList.getSearchSummary().isEmpty())
+ {
+ filteredResponse.addAll(resultList.getSearchSummary());
+ }
+ }
+
+ String totalTime = (System.currentTimeMillis() - startTime)
+ + " milli secs";
+ if (!filteredResponse.isEmpty())
+ {
+ final int filterResponseCount = filteredResponse.size();
+ Collection<FTSData> reorderedStructuresSet = new LinkedHashSet<FTSData>();
+ reorderedStructuresSet.addAll(filteredResponse);
+ reorderedStructuresSet.addAll(discoveredStructuresSet);
+ getResultTable().setModel(
+ FTSRestResponse.getTableModel(
+ lastPdbRequest, reorderedStructuresSet));
+
+ FTSRestResponse.configureTableColumn(getResultTable(),
+ wantedFields);
+ getResultTable().getColumn("Ref Sequence").setPreferredWidth(120);
+ getResultTable().getColumn("Ref Sequence").setMinWidth(100);
+ getResultTable().getColumn("Ref Sequence").setMaxWidth(200);
+ // Update table selection model here
+ getResultTable().addRowSelectionInterval(0,
+ filterResponseCount - 1);
+ mainFrame.setTitle(MessageManager.formatMessage(
+ "label.structure_chooser_filter_time", totalTime));
+ }
+ else
+ {
+ mainFrame.setTitle(MessageManager.formatMessage(
+ "label.structure_chooser_filter_time", totalTime));
+ if (errors.size() > 0)
+ {
+ StringBuilder errorMsg = new StringBuilder();
+ for (String error : errors)
+ {
+ errorMsg.append(error).append("\n");
+ }
+ JOptionPane.showMessageDialog(
+ null,
+ errorMsg.toString(),
+ MessageManager.getString("label.pdb_web-service_error"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+ lbl_loading.setVisible(false);
+
+ validateSelections();
+ }
+ });
+ filterThread.start();
+ }
+
+ /**
+ * Handles action event for btn_pdbFromFile
+ */
+ @Override
+ public void pdbFromFile_actionPerformed()
+ {
+ jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
+ jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
+ chooser.setFileView(new jalview.io.JalviewFileView());
+ chooser.setDialogTitle(MessageManager.formatMessage(
+ "label.select_pdb_file_for",
+ selectedSequence.getDisplayId(false)));
+ chooser.setToolTipText(MessageManager.formatMessage(
+ "label.load_pdb_file_associate_with_sequence",
+ selectedSequence.getDisplayId(false)));
+
+ int value = chooser.showOpenDialog(null);
+ if (value == jalview.io.JalviewFileChooser.APPROVE_OPTION)
+ {
+ selectedPdbFileName = chooser.getSelectedFile().getPath();
+ jalview.bin.Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
+ validateSelections();
+ }
+ }
+
+ /**
+ * Populates the filter combo-box options dynamically depending on discovered
+ * structures
+ */
+ @Override
+ protected void populateFilterComboBox()
+ {
+ if (isStructuresDiscovered())
+ {
+ cmb_filterOption.addItem(new FilterOption("Best Quality",
+ "overall_quality", VIEWS_FILTER));
+ cmb_filterOption.addItem(new FilterOption("Best Resolution",
+ "resolution", VIEWS_FILTER));
+ cmb_filterOption.addItem(new FilterOption("Most Protein Chain",
+ "number_of_protein_chains", VIEWS_FILTER));
+ cmb_filterOption.addItem(new FilterOption("Most Bound Molecules",
+ "number_of_bound_molecules", VIEWS_FILTER));
+ cmb_filterOption.addItem(new FilterOption("Most Polymer Residues",
+ "number_of_polymer_residues", VIEWS_FILTER));
+ }
+ cmb_filterOption.addItem(new FilterOption("Enter PDB Id", "-",
+ VIEWS_ENTER_ID));
+ cmb_filterOption.addItem(new FilterOption("From File", "-",
+ VIEWS_FROM_FILE));
+ cmb_filterOption.addItem(new FilterOption("Cached PDB Entries", "-",
+ VIEWS_LOCAL_PDB));
+ }
+
+ /**
+ * Updates the displayed view based on the selected filter option
+ */
+ @Override
+ protected void updateCurrentView()
+ {
+ FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
+ .getSelectedItem());
+ layout_switchableViews.show(pnl_switchableViews,
+ selectedFilterOpt.getView());
+ String filterTitle = mainFrame.getTitle();
+ mainFrame.setTitle(frameTitle);
+ chk_invertFilter.setVisible(false);
+ if (selectedFilterOpt.getView() == VIEWS_FILTER)
+ {
+ mainFrame.setTitle(filterTitle);
+ chk_invertFilter.setVisible(true);
+ filterResultSet(selectedFilterOpt.getValue());
+ }
+ else if (selectedFilterOpt.getView() == VIEWS_ENTER_ID
+ || selectedFilterOpt.getView() == VIEWS_FROM_FILE)
+ {
+ mainFrame.setTitle(MessageManager
+ .getString("label.structure_chooser_manual_association"));
+ idInputAssSeqPanel.loadCmbAssSeq();
+ fileChooserAssSeqPanel.loadCmbAssSeq();
+ }
+ validateSelections();
+ }
+
+ /**
+ * Validates user selection and activates the view button if all parameters
+ * are correct
+ */
+ @Override
+ public void validateSelections()
+ {
+ FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
+ .getSelectedItem());
+ btn_view.setEnabled(false);
+ String currentView = selectedFilterOpt.getView();
+ if (currentView == VIEWS_FILTER)
+ {
+ if (getResultTable().getSelectedRows().length > 0)
+ {
+ btn_view.setEnabled(true);
+ }
+ }
+ else if (currentView == VIEWS_LOCAL_PDB)
+ {
+ if (tbl_local_pdb.getSelectedRows().length > 0)
+ {
+ btn_view.setEnabled(true);
+ }
+ }
+ else if (currentView == VIEWS_ENTER_ID)
+ {
+ validateAssociationEnterPdb();
+ }
+ else if (currentView == VIEWS_FROM_FILE)
+ {
+ validateAssociationFromFile();
+ }
+ }
+
+ /**
+ * Validates inputs from the Manual PDB entry panel
+ */
+ public void validateAssociationEnterPdb()
+ {
+ AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) idInputAssSeqPanel
+ .getCmb_assSeq().getSelectedItem();
+ lbl_pdbManualFetchStatus.setIcon(errorImage);
+ lbl_pdbManualFetchStatus.setToolTipText("");
+ if (txt_search.getText().length() > 0)
+ {
+ lbl_pdbManualFetchStatus
+ .setToolTipText(JvSwingUtils.wrapTooltip(true, MessageManager
+ .formatMessage("info.no_pdb_entry_found_for",
+ txt_search.getText())));
+ }
+
+ if (errorWarning.length() > 0)
+ {
+ lbl_pdbManualFetchStatus.setIcon(warningImage);
+ lbl_pdbManualFetchStatus.setToolTipText(JvSwingUtils.wrapTooltip(
+ true, errorWarning.toString()));
+ }
+
+ if (selectedSequences.length == 1
+ || !assSeqOpt.getName().equalsIgnoreCase(
+ "-Select Associated Seq-"))
+ {
+ txt_search.setEnabled(true);
+ if (isValidPBDEntry)
+ {
+ btn_view.setEnabled(true);
+ lbl_pdbManualFetchStatus.setToolTipText("");
+ lbl_pdbManualFetchStatus.setIcon(goodImage);
+ }
+ }
+ else
+ {
+ txt_search.setEnabled(false);
+ lbl_pdbManualFetchStatus.setIcon(errorImage);
+ }
+ }
+
+ /**
+ * Validates inputs for the manual PDB file selection options
+ */
+ public void validateAssociationFromFile()
+ {
+ AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
+ .getCmb_assSeq().getSelectedItem();
+ lbl_fromFileStatus.setIcon(errorImage);
+ if (selectedSequences.length == 1
+ || (assSeqOpt != null && !assSeqOpt.getName().equalsIgnoreCase(
+ "-Select Associated Seq-")))
+ {
+ btn_pdbFromFile.setEnabled(true);
+ if (selectedPdbFileName != null && selectedPdbFileName.length() > 0)
+ {
+ btn_view.setEnabled(true);
+ lbl_fromFileStatus.setIcon(goodImage);
+ }
+ }
+ else
+ {
+ btn_pdbFromFile.setEnabled(false);
+ lbl_fromFileStatus.setIcon(errorImage);
+ }
+ }
+
+ @Override
+ public void cmbAssSeqStateChanged()
+ {
+ validateSelections();
+ }
+
+ /**
+ * Handles the state change event for the 'filter' combo-box and 'invert'
+ * check-box
+ */
+ @Override
+ protected void stateChanged(ItemEvent e)
+ {
+ if (e.getSource() instanceof JCheckBox)
+ {
+ updateCurrentView();
+ }
+ else
+ {
+ if (e.getStateChange() == ItemEvent.SELECTED)
+ {
+ updateCurrentView();
+ }
+ }
+
+ }
+
+ /**
+ * Handles action event for btn_ok
+ */
+ @Override
+ public void ok_ActionPerformed()
+ {
+ final StructureSelectionManager ssm = ap.getStructureSelectionManager();
+ new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
+ .getSelectedItem());
+ String currentView = selectedFilterOpt.getView();
+ if (currentView == VIEWS_FILTER)
+ {
+ int pdbIdColIndex = getResultTable().getColumn("PDB Id")
+ .getModelIndex();
+ int refSeqColIndex = getResultTable().getColumn("Ref Sequence")
+ .getModelIndex();
+ int[] selectedRows = getResultTable().getSelectedRows();
+ PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
+ int count = 0;
+ ArrayList<SequenceI> selectedSeqsToView = new ArrayList<SequenceI>();
+ for (int row : selectedRows)
+ {
+ String pdbIdStr = getResultTable().getValueAt(row,
+ pdbIdColIndex)
+ .toString();
+ SequenceI selectedSeq = (SequenceI) getResultTable()
+ .getValueAt(row,
+ refSeqColIndex);
+ selectedSeqsToView.add(selectedSeq);
+ PDBEntry pdbEntry = selectedSeq.getPDBEntry(pdbIdStr);
+ if (pdbEntry == null)
+ {
+ pdbEntry = getFindEntry(pdbIdStr,
+ selectedSeq.getAllPDBEntries());
+ }
+ if (pdbEntry == null)
+ {
+ pdbEntry = new PDBEntry();
+ pdbEntry.setId(pdbIdStr);
+ pdbEntry.setType(PDBEntry.Type.PDB);
+ selectedSeq.getDatasetSequence().addPDBId(pdbEntry);
+ }
+ pdbEntriesToView[count++] = pdbEntry;
+ }
+ SequenceI[] selectedSeqs = selectedSeqsToView
+ .toArray(new SequenceI[selectedSeqsToView.size()]);
+ launchStructureViewer(ssm, pdbEntriesToView, ap,
+ selectedSeqs);
+ }
+ else if (currentView == VIEWS_LOCAL_PDB)
+ {
+ int[] selectedRows = tbl_local_pdb.getSelectedRows();
+ PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
+ int count = 0;
+ int pdbIdColIndex = tbl_local_pdb.getColumn("PDB Id")
+ .getModelIndex();
+ int refSeqColIndex = tbl_local_pdb.getColumn("Ref Sequence")
+ .getModelIndex();
+ ArrayList<SequenceI> selectedSeqsToView = new ArrayList<SequenceI>();
+ for (int row : selectedRows)
+ {
+ PDBEntry pdbEntry = (PDBEntry) tbl_local_pdb.getValueAt(row,
+ pdbIdColIndex);
+ pdbEntriesToView[count++] = pdbEntry;
+ SequenceI selectedSeq = (SequenceI) tbl_local_pdb.getValueAt(row,
+ refSeqColIndex);
+ selectedSeqsToView.add(selectedSeq);
+ }
+ SequenceI[] selectedSeqs = selectedSeqsToView
+ .toArray(new SequenceI[selectedSeqsToView.size()]);
+ launchStructureViewer(ssm, pdbEntriesToView, ap,
+ selectedSeqs);
+ }
+ else if (currentView == VIEWS_ENTER_ID)
+ {
+ SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel
+ .getCmb_assSeq().getSelectedItem()).getSequence();
+ if (userSelectedSeq != null)
+ {
+ selectedSequence = userSelectedSeq;
+ }
+
+ String pdbIdStr = txt_search.getText();
+ PDBEntry pdbEntry = selectedSequence.getPDBEntry(pdbIdStr);
+ if (pdbEntry == null)
+ {
+ pdbEntry = new PDBEntry();
+ if (pdbIdStr.split(":").length > 1)
+ {
+ pdbEntry.setChainCode(pdbIdStr.split(":")[1]);
+ }
+ pdbEntry.setId(pdbIdStr);
+ pdbEntry.setType(PDBEntry.Type.PDB);
+ selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
+ }
+
+ PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry };
+ launchStructureViewer(ssm, pdbEntriesToView, ap,
+ new SequenceI[] { selectedSequence });
+ }
+ else if (currentView == VIEWS_FROM_FILE)
+ {
+ SequenceI userSelectedSeq = ((AssociateSeqOptions) fileChooserAssSeqPanel
+ .getCmb_assSeq().getSelectedItem()).getSequence();
+ if (userSelectedSeq != null)
+ {
+ selectedSequence = userSelectedSeq;
+ }
+ PDBEntry fileEntry = new AssociatePdbFileWithSeq()
+ .associatePdbWithSeq(selectedPdbFileName,
+ jalview.io.AppletFormatAdapter.FILE,
+ selectedSequence, true, Desktop.instance);
+
+ launchStructureViewer(ssm,
+ new PDBEntry[] { fileEntry }, ap,
+ new SequenceI[] { selectedSequence });
+ }
+ mainFrame.dispose();
+ }
+ }).start();
+ }
+
+ private PDBEntry getFindEntry(String id, Vector<PDBEntry> pdbEntries)
+ {
+ Objects.requireNonNull(id);
+ Objects.requireNonNull(pdbEntries);
+ PDBEntry foundEntry = null;
+ for (PDBEntry entry : pdbEntries)
+ {
+ if (entry.getId().equalsIgnoreCase(id))
+ {
+ return entry;
+ }
+ }
+ return foundEntry;
+ }
+
+ private void launchStructureViewer(StructureSelectionManager ssm,
+ final PDBEntry[] pdbEntriesToView,
+ final AlignmentPanel alignPanel, SequenceI[] sequences)
+ {
+ long progressId = sequences.hashCode();
+ setProgressBar(MessageManager
+ .getString("status.launching_3d_structure_viewer"), progressId);
+ final StructureViewer sViewer = new StructureViewer(ssm);
+ setProgressBar(null, progressId);
+
+ if (SiftsSettings.isMapWithSifts())
+ {
+ // TODO: prompt user if there are lots of sequences without dbrefs.
+ // It can take a long time if we need to fetch all dbrefs for all
+ // sequences!
+ ArrayList<SequenceI> seqsWithoutSourceDBRef = new ArrayList<SequenceI>();
+ for (SequenceI seq : sequences)
+ {
+ if (seq.getSourceDBRef() == null && seq.getDBRefs() == null)
+ {
+ seqsWithoutSourceDBRef.add(seq);
+ continue;
+ }
+ }
+ if (!seqsWithoutSourceDBRef.isEmpty())
+ {
+ int y = seqsWithoutSourceDBRef.size();
+ setProgressBar(MessageManager.formatMessage(
+ "status.fetching_dbrefs_for_sequences_without_valid_refs",
+ y,
+ progressId);
+ SequenceI[] seqWithoutSrcDBRef = new SequenceI[y];
+ int x = 0;
+ for (SequenceI fSeq : seqsWithoutSourceDBRef)
+ {
+ seqWithoutSrcDBRef[x++] = fSeq;
+ }
+ new DBRefFetcher(seqWithoutSrcDBRef).fetchDBRefs(true);
+ setProgressBar("Fetch complete.", progressId); // todo i18n
+ }
+ }
+ if (pdbEntriesToView.length > 1)
+ {
+ ArrayList<SequenceI[]> seqsMap = new ArrayList<SequenceI[]>();
+ for (SequenceI seq : sequences)
+ {
+ seqsMap.add(new SequenceI[] { seq });
+ }
+ SequenceI[][] collatedSeqs = seqsMap.toArray(new SequenceI[0][0]);
+<<<<<<< Updated upstream
+ ssm.setProgressBar(null);
+ ssm.setProgressBar(MessageManager
+ .getString("status.fetching_3d_structures_for_selected_entries"));
+=======
+ setProgressBar("Fetching structure data", progressId);
+>>>>>>> Stashed changes
+ sViewer.viewStructures(pdbEntriesToView, collatedSeqs, alignPanel);
+ }
+ else
+ {
+<<<<<<< Updated upstream
+ ssm.setProgressBar(null);
+ ssm.setProgressBar(MessageManager.formatMessage(
+ "status.fetching_3d_structures_for",
+ pdbEntriesToView[0].getId()));
+=======
+ setProgressBar(
+ "Fetching structure for " + pdbEntriesToView[0].getId(),
+ progressId);
+>>>>>>> Stashed changes
+ sViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
+ }
+ setProgressBar(null, progressId);
+ }
+
+ /**
+ * Populates the combo-box used in associating manually fetched structures to
+ * a unique sequence when more than one sequence selection is made.
+ */
+ @Override
+ public void populateCmbAssociateSeqOptions(
+ JComboBox<AssociateSeqOptions> cmb_assSeq, JLabel lbl_associateSeq)
+ {
+ cmb_assSeq.removeAllItems();
+ cmb_assSeq.addItem(new AssociateSeqOptions("-Select Associated Seq-",
+ null));
+ lbl_associateSeq.setVisible(false);
+ if (selectedSequences.length > 1)
+ {
+ for (SequenceI seq : selectedSequences)
+ {
+ cmb_assSeq.addItem(new AssociateSeqOptions(seq));
+ }
+ }
+ else
+ {
+ String seqName = selectedSequence.getDisplayId(false);
+ seqName = seqName.length() <= 40 ? seqName : seqName.substring(0, 39);
+ lbl_associateSeq.setText(seqName);
+ lbl_associateSeq.setVisible(true);
+ cmb_assSeq.setVisible(false);
+ }
+ }
+
+ public boolean isStructuresDiscovered()
+ {
+ return structuresDiscovered;
+ }
+
+ public void setStructuresDiscovered(boolean structuresDiscovered)
+ {
+ this.structuresDiscovered = structuresDiscovered;
+ }
+
+ public Collection<FTSData> getDiscoveredStructuresSet()
+ {
+ return discoveredStructuresSet;
+ }
+
+ @Override
+ protected void txt_search_ActionPerformed()
+ {
+ new Thread()
+ {
+ @Override
+ public void run()
+ {
+ errorWarning.setLength(0);
+ isValidPBDEntry = false;
+ if (txt_search.getText().length() > 0)
+ {
+ String searchTerm = txt_search.getText().toLowerCase();
+ searchTerm = searchTerm.split(":")[0];
+ // System.out.println(">>>>> search term : " + searchTerm);
+ List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+ FTSRestRequest pdbRequest = new FTSRestRequest();
+ pdbRequest.setAllowEmptySeq(false);
+ pdbRequest.setResponseSize(1);
+ pdbRequest.setFieldToSearchBy("(pdb_id:");
+ pdbRequest.setWantedFields(wantedFields);
+ pdbRequest
+.setSearchTerm(searchTerm + ")");
+ pdbRequest.setAssociatedSequence(selectedSequence);
+ pdbRestCleint = PDBFTSRestClient.getInstance();
+ wantedFields.add(pdbRestCleint.getPrimaryKeyColumn());
+ FTSRestResponse resultList;
+ try
+ {
+ resultList = pdbRestCleint.executeRequest(pdbRequest);
+ } catch (Exception e)
+ {
+ errorWarning.append(e.getMessage());
+ return;
+ } finally
+ {
+ validateSelections();
+ }
+ if (resultList.getSearchSummary() != null
+ && resultList.getSearchSummary().size() > 0)
+ {
+ isValidPBDEntry = true;
+ }
+ }
+ validateSelections();
+ }
+ }.start();
+ }
+
+ @Override
+ public void tabRefresh()
+ {
+ if (selectedSequences != null)
+ {
+ Thread refreshThread = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ fetchStructuresMetaData();
+ filterResultSet(((FilterOption) cmb_filterOption
+ .getSelectedItem()).getValue());
+ }
+ });
+ refreshThread.start();
+ }
+ }
+
+ public class PDBEntryTableModel extends AbstractTableModel
+ {
+ String[] columns = { "Ref Sequence", "PDB Id", "Chain", "Type", "File" };
+
+ private List<CachedPDB> pdbEntries;
+
+ public PDBEntryTableModel(List<CachedPDB> pdbEntries)
+ {
+ this.pdbEntries = new ArrayList<CachedPDB>(pdbEntries);
+ }
+
+ @Override
+ public String getColumnName(int columnIndex)
+ {
+ return columns[columnIndex];
+ }
+
+ @Override
+ public int getRowCount()
+ {
+ return pdbEntries.size();
+ }
+
+ @Override
+ public int getColumnCount()
+ {
+ return columns.length;
+ }
+
+ @Override
+ public boolean isCellEditable(int row, int column)
+ {
+ return false;
+ }
+
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex)
+ {
+ Object value = "??";
+ CachedPDB entry = pdbEntries.get(rowIndex);
+ switch (columnIndex)
+ {
+ case 0:
+ value = entry.getSequence();
+ break;
+ case 1:
+ value = entry.getPdbEntry();
+ break;
+ case 2:
+ value = entry.getPdbEntry().getChainCode() == null ? "_" : entry
+ .getPdbEntry().getChainCode();
+ break;
+ case 3:
+ value = entry.getPdbEntry().getType();
+ break;
+ case 4:
+ value = entry.getPdbEntry().getFile();
+ break;
+ }
+ return value;
+ }
+
+ @Override
+ public Class<?> getColumnClass(int columnIndex)
+ {
+ return columnIndex == 0 ? SequenceI.class : PDBEntry.class;
+ }
+
+ public CachedPDB getPDBEntryAt(int row)
+ {
+ return pdbEntries.get(row);
+ }
+
+ }
+
+ private class CachedPDB
+ {
+ private SequenceI sequence;
+
+ private PDBEntry pdbEntry;
+
+ public CachedPDB(SequenceI sequence, PDBEntry pdbEntry)
+ {
+ this.sequence = sequence;
+ this.pdbEntry = pdbEntry;
+ }
+
+ public SequenceI getSequence()
+ {
+ return sequence;
+ }
+
+ public PDBEntry getPdbEntry()
+ {
+ return pdbEntry;
+ }
+
+ }
+
+ private IProgressIndicator progressBar;
+
+ @Override
+ public void setProgressBar(String message, long id)
+ {
+ progressBar.setProgressBar(message, id);
+ }
+
+ @Override
+ public void registerHandler(long id, IProgressIndicatorHandler handler)
+ {
+ progressBar.registerHandler(id, handler);
+ }
+
+ @Override
+ public boolean operationInProgress()
+ {
+ return progressBar.operationInProgress();
+ }
+}
import jalview.bin.Cache;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
import jalview.gui.StructureViewer.ViewerType;
protected boolean allChainsSelected = false;
+ protected JMenu viewSelectionMenu;
+
/**
* Default constructor
*/
@Override
public void itemStateChanged(ItemEvent e)
{
- alignStructs.setEnabled(_alignwith.size() > 0);
+ alignStructs.setEnabled(!_alignwith.isEmpty());
alignStructs.setToolTipText(MessageManager.formatMessage(
"label.align_structures_using_linked_alignment_views",
- new String[] { String.valueOf(_alignwith.size()) }));
+ _alignwith.size()));
}
};
- JMenu alpanels = new ViewSelectionMenu(
+ viewSelectionMenu = new ViewSelectionMenu(
MessageManager.getString("label.superpose_with"), this,
_alignwith, handler);
handler.itemStateChanged(null);
- viewerActionMenu.add(alpanels);
+ viewerActionMenu.add(viewSelectionMenu, 0);
viewerActionMenu.addMenuListener(new MenuListener()
{
@Override
public void setJalviewColourScheme(ColourSchemeI cs) {
getBinding().setJalviewColourScheme(cs);
}
+
+ /**
+ * Sends commands to the structure viewer to superimpose structures based on
+ * currently associated alignments. May optionally return an error message for
+ * the operation.
+ */
@Override
- protected void alignStructs_actionPerformed(ActionEvent actionEvent)
+ protected String alignStructs_actionPerformed(
+ ActionEvent actionEvent)
{
- alignStructs_withAllAlignPanels();
+ return alignStructs_withAllAlignPanels();
}
- protected void alignStructs_withAllAlignPanels()
+
+ protected String alignStructs_withAllAlignPanels()
{
if (getAlignmentPanel() == null)
{
- return;
+ return null;
}
if (_alignwith.size() == 0)
_alignwith.add(getAlignmentPanel());
}
+ String reply = null;
try
{
AlignmentI[] als = new Alignment[_alignwith.size()];
- ColumnSelection[] alc = new ColumnSelection[_alignwith.size()];
+ HiddenColumns[] alc = new HiddenColumns[_alignwith.size()];
int[] alm = new int[_alignwith.size()];
int a = 0;
{
als[a] = ap.av.getAlignment();
alm[a] = -1;
- alc[a++] = ap.av.getColumnSelection();
+ alc[a++] = ap.av.getAlignment().getHiddenColumns();
+ }
+ reply = getBinding().superposeStructures(als, alm, alc);
+ if (reply != null)
+ {
+ String text = MessageManager.formatMessage(
+ "error.superposition_failed", reply);
+ statusBar.setText(text);
}
- getBinding().superposeStructures(als, alm, alc);
} catch (Exception e)
{
StringBuffer sp = new StringBuffer();
Cache.log.info("Couldn't align structures with the " + sp.toString()
+ "associated alignment panels.", e);
}
+ return reply;
}
+
@Override
public void background_actionPerformed(ActionEvent actionEvent)
{
{
// TODO: cope with multiple PDB files in view
in = new BufferedReader(
- new FileReader(getBinding().getPdbFile()[0]));
+ new FileReader(getBinding().getStructureFiles()[0]));
File outFile = chooser.getSelectedFile();
PrintWriter out = new PrintWriter(new FileOutputStream(outFile));
}
protected abstract String getViewerName();
+
+ /**
+ * Configures the title and menu items of the viewer panel.
+ */
public void updateTitleAndMenus()
{
AAStructureBindingModel binding = getBinding();
setChainMenuItems(binding.getChainNames());
this.setTitle(binding.getViewerTitle(getViewerName(), true));
- if (binding.getPdbFile().length > 1 && binding.getSequence().length > 1)
+
+ /*
+ * enable 'Superpose with' if more than one mapped structure
+ */
+ viewSelectionMenu.setEnabled(false);
+ if (getBinding().getStructureFiles().length > 1
+ && getBinding().getSequence().length > 1)
{
- viewerActionMenu.setVisible(true);
+ viewSelectionMenu.setEnabled(true);
}
+
+ /*
+ * Show action menu if it has any enabled items
+ */
+ viewerActionMenu.setVisible(false);
+ for (int i = 0; i < viewerActionMenu.getItemCount(); i++)
+ {
+ if (viewerActionMenu.getItem(i).isEnabled())
+ {
+ viewerActionMenu.setVisible(true);
+ break;
+ }
+ }
+
if (!binding.isLoadingFromArchive())
{
seqColour_actionPerformed(null);
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.util.HashMap;
+import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.JColorChooser;
import javax.swing.JLabel;
-import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
SequenceGroup sg;
- public void chooseColour(AlignmentPanel ap, SequenceGroup sg)
+ Color original1, original2;
+
+ int originalThreshold;
+
+ Map<SequenceGroup, Color> groupColour1;
+
+ Map<SequenceGroup, Color> groupColour2;
+
+ Map<SequenceGroup, Integer> groupThreshold;
+
+ /**
+ * Show a dialogue which allows the user to select two text colours and adjust
+ * a slider for the cross-over point
+ *
+ * @param alignPanel
+ * the AlignmentPanel context
+ * @param sequenceGroup
+ * the SequenceGroup context (only for group pop-menu option)
+ */
+ public void chooseColour(AlignmentPanel alignPanel, SequenceGroup sequenceGroup)
{
- this.ap = ap;
- this.sg = sg;
+ this.ap = alignPanel;
+ this.sg = sequenceGroup;
- int original1, original2, originalThreshold;
- if (sg == null)
- {
- original1 = ap.av.getTextColour().getRGB();
- original2 = ap.av.getTextColour2().getRGB();
- originalThreshold = ap.av.getThresholdTextColour();
- }
- else
- {
- original1 = sg.textColour.getRGB();
- original2 = sg.textColour2.getRGB();
- originalThreshold = sg.thresholdTextColour;
- }
+ saveInitialSettings();
final JSlider slider = new JSlider(0, 750, originalThreshold);
final JPanel col1 = new JPanel();
col1.setPreferredSize(new Dimension(40, 20));
col1.setBorder(BorderFactory.createEtchedBorder());
col1.setToolTipText(MessageManager.getString("label.dark_colour"));
- col1.setBackground(new Color(original1));
+ col1.setBackground(original1);
final JPanel col2 = new JPanel();
col2.setPreferredSize(new Dimension(40, 20));
col2.setBorder(BorderFactory.createEtchedBorder());
col2.setToolTipText(MessageManager.getString("label.light_colour"));
- col2.setBackground(new Color(original2));
+ col2.setBackground(original2);
final JPanel bigpanel = new JPanel(new BorderLayout());
JPanel panel = new JPanel();
bigpanel.add(panel, BorderLayout.CENTER);
int reply = JvOptionPane
.showInternalOptionDialog(
- ap,
+ alignPanel,
bigpanel,
MessageManager
.getString("label.adjunst_foreground_text_colour_threshold"),
if (reply == JvOptionPane.CANCEL_OPTION)
{
- if (sg == null)
- {
- ap.av.setTextColour(new Color(original1));
- ap.av.setTextColour2(new Color(original2));
- ap.av.setThresholdTextColour(originalThreshold);
- }
- else
+ restoreInitialSettings();
+ }
+ }
+
+ /**
+ * Restore initial settings on Cancel
+ */
+ protected void restoreInitialSettings()
+ {
+ if (sg == null)
+ {
+ ap.av.setTextColour(original1);
+ ap.av.setTextColour2(original2);
+ ap.av.setThresholdTextColour(originalThreshold);
+ }
+ else
+ {
+ sg.textColour = original1;
+ sg.textColour2 = original2;
+ sg.thresholdTextColour = originalThreshold;
+ }
+
+ /*
+ * if 'Apply To All Groups' was in force, there will be
+ * group-specific settings to restore as well
+ */
+ for (SequenceGroup group : this.groupColour1.keySet())
+ {
+ group.textColour = groupColour1.get(group);
+ group.textColour2 = groupColour2.get(group);
+ group.thresholdTextColour = groupThreshold.get(group);
+ }
+ }
+
+ /**
+ * Save settings on entry, for restore on Cancel
+ */
+ protected void saveInitialSettings()
+ {
+ groupColour1 = new HashMap<SequenceGroup, Color>();
+ groupColour2 = new HashMap<SequenceGroup, Color>();
+ groupThreshold = new HashMap<SequenceGroup, Integer>();
+
+ if (sg == null)
+ {
+ /*
+ * alignment scope
+ */
+ original1 = ap.av.getTextColour();
+ original2 = ap.av.getTextColour2();
+ originalThreshold = ap.av.getThresholdTextColour();
+ if (ap.av.getColourAppliesToAllGroups()
+ && ap.av.getAlignment().getGroups() != null)
{
- sg.textColour = new Color(original1);
- sg.textColour2 = new Color(original2);
- sg.thresholdTextColour = originalThreshold;
+ /*
+ * if applying changes to all groups, need to be able to
+ * restore group settings as well
+ */
+ for (SequenceGroup group : ap.av.getAlignment().getGroups())
+ {
+ groupColour1.put(group, group.textColour);
+ groupColour2.put(group, group.textColour2);
+ groupThreshold.put(group, group.thresholdTextColour);
+ }
}
}
+ else
+ {
+ /*
+ * Sequence group scope
+ */
+ original1 = sg.textColour;
+ original2 = sg.textColour2;
+ originalThreshold = sg.thresholdTextColour;
+ }
}
void colour1Changed(Color col)
return;
}
- for (SequenceGroup sg : ap.av.getAlignment().getGroups())
+ for (SequenceGroup group : ap.av.getAlignment().getGroups())
{
- sg.textColour = ap.av.getTextColour();
- sg.textColour2 = ap.av.getTextColour2();
- sg.thresholdTextColour = ap.av.getThresholdTextColour();
+ group.textColour = ap.av.getTextColour();
+ group.textColour2 = ap.av.getTextColour2();
+ group.thresholdTextColour = ap.av.getThresholdTextColour();
}
}
package jalview.gui;
import jalview.analysis.Conservation;
-import jalview.analysis.NJTree;
+import jalview.analysis.TreeModel;
import jalview.api.AlignViewportI;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceGroup;
import java.awt.print.PrinterJob;
import java.util.Enumeration;
import java.util.Hashtable;
+import java.util.List;
import java.util.Vector;
import javax.swing.JColorChooser;
/** DOCUMENT ME!! */
public static final String PLACEHOLDER = " * ";
- NJTree tree;
+ TreeModel tree;
JScrollPane scrollPane;
* @param tree
* DOCUMENT ME!
*/
- public void setTree(NJTree tree)
+ public void setTree(TreeModel tree)
{
this.tree = tree;
tree.findHeight(tree.getTopNode());
* DOCUMENT ME!
* @param chunk
* DOCUMENT ME!
- * @param scale
+ * @param wscale
* DOCUMENT ME!
* @param width
* DOCUMENT ME!
* DOCUMENT ME!
*/
public void drawNode(Graphics g, SequenceNode node, float chunk,
- float scale, int width, int offx, int offy)
+ double wscale, int width, int offx, int offy)
{
if (node == null)
{
if ((node.left() == null) && (node.right() == null))
{
// Drawing leaf node
- float height = node.height;
- float dist = node.dist;
+ double height = node.height;
+ double dist = node.dist;
- int xstart = (int) ((height - dist) * scale) + offx;
- int xend = (int) (height * scale) + offx;
+ int xstart = (int) ((height - dist) * wscale) + offx;
+ int xend = (int) (height * wscale) + offx;
int ypos = (int) (node.ycount * chunk) + offy;
}
else
{
- drawNode(g, (SequenceNode) node.left(), chunk, scale, width, offx,
+ drawNode(g, (SequenceNode) node.left(), chunk, wscale, width, offx,
offy);
- drawNode(g, (SequenceNode) node.right(), chunk, scale, width, offx,
+ drawNode(g, (SequenceNode) node.right(), chunk, wscale, width, offx,
offy);
- float height = node.height;
- float dist = node.dist;
+ double height = node.height;
+ double dist = node.dist;
- int xstart = (int) ((height - dist) * scale) + offx;
- int xend = (int) (height * scale) + offx;
+ int xstart = (int) ((height - dist) * wscale) + offx;
+ int xend = (int) (height * wscale) + offx;
int ypos = (int) (node.ycount * chunk) + offy;
g.setColor(node.color.darker());
g.fillRect(xend - 2, ypos - 2, 4, 4);
}
- int ystart = (int) (((SequenceNode) node.left()).ycount * chunk)
- + offy;
- int yend = (int) (((SequenceNode) node.right()).ycount * chunk)
+ int ystart = (node.left() == null ? 0 : (int) (((SequenceNode) node
+ .left()).ycount * chunk)) + offy;
+ int yend = (node.right() == null ? 0 : (int) (((SequenceNode) node
+ .right()).ycount * chunk))
+ offy;
Rectangle pos = new Rectangle(xend - 2, ypos - 2, 5, 5);
nodeHash.put(node, pos);
- g.drawLine((int) (height * scale) + offx, ystart,
- (int) (height * scale) + offx, yend);
+ g.drawLine((int) (height * wscale) + offx, ystart,
+ (int) (height * wscale) + offx, yend);
String nodeLabel = "";
SequenceNode top = tree.getTopNode();
- float wscale = (float) ((width * .8) - (offx * 2))
+ double wscale = ((width * .8) - (offx * 2))
/ tree.getMaxHeight();
if (top.count == 0)
* DOCUMENT ME!
* @param chunk
* DOCUMENT ME!
- * @param scale
+ * @param wscale
* DOCUMENT ME!
* @param width
* DOCUMENT ME!
* DOCUMENT ME!
*/
public void pickNode(Rectangle pickBox, SequenceNode node, float chunk,
- float scale, int width, int offx, int offy)
+ double wscale, int width, int offx, int offy)
{
if (node == null)
{
if ((node.left() == null) && (node.right() == null))
{
- float height = node.height;
- float dist = node.dist;
+ double height = node.height;
+ double dist = node.dist;
- int xstart = (int) ((height - dist) * scale) + offx;
- int xend = (int) (height * scale) + offx;
+ int xstart = (int) ((height - dist) * wscale) + offx;
+ int xend = (int) (height * wscale) + offx;
int ypos = (int) (node.ycount * chunk) + offy;
}
else
{
- pickNode(pickBox, (SequenceNode) node.left(), chunk, scale, width,
+ pickNode(pickBox, (SequenceNode) node.left(), chunk, wscale, width,
offx, offy);
- pickNode(pickBox, (SequenceNode) node.right(), chunk, scale, width,
+ pickNode(pickBox, (SequenceNode) node.right(), chunk, wscale, width,
offx, offy);
}
}
public void run()
{
PrinterJob printJob = PrinterJob.getPrinterJob();
- PageFormat pf = printJob.pageDialog(printJob.defaultPage());
+ PageFormat defaultPage = printJob.defaultPage();
+ PageFormat pf = printJob.pageDialog(defaultPage);
+
+ if (defaultPage == pf)
+ {
+ /*
+ * user cancelled
+ */
+ return;
+ }
printJob.setPrintable(this, pf);
labelLength = fm.stringWidth(longestName) + 20; // 20 allows for scrollbar
- float wscale = (width - labelLength - (offx * 2)) / tree.getMaxHeight();
+ double wscale = (width - labelLength - (offx * 2))
+ / tree.getMaxHeight();
SequenceNode top = tree.getTopNode();
threshold = (float) (x - offx)
/ (float) (getWidth() - labelLength - (2 * offx));
- tree.getGroups().removeAllElements();
- tree.groupNodes(tree.getTopNode(), threshold);
+ List<SequenceNode> groups = tree.groupNodes(threshold);
setColor(tree.getTopNode(), Color.black);
AlignmentPanel[] aps = getAssociatedPanels();
aps[a].av.getCodingComplement().clearSequenceColours();
}
}
- colourGroups();
+ colourGroups(groups);
}
PaintRefresher.Refresh(tp, ap.av.getSequenceSetId());
}
- void colourGroups()
+ void colourGroups(List<SequenceNode> groups)
{
AlignmentPanel[] aps = getAssociatedPanels();
- for (int i = 0; i < tree.getGroups().size(); i++)
+ for (int i = 0; i < groups.size(); i++)
{
Color col = new Color((int) (Math.random() * 255),
(int) (Math.random() * 255), (int) (Math.random() * 255));
- setColor(tree.getGroups().elementAt(i), col.brighter());
+ setColor(groups.get(i), col.brighter());
- Vector<SequenceNode> l = tree.findLeaves(tree.getGroups()
- .elementAt(i));
+ Vector<SequenceNode> l = tree.findLeaves(groups.get(i));
Vector<SequenceI> sequences = new Vector<SequenceI>();
--- /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.
+ */
+package jalview.gui;
+
+import jalview.analysis.Conservation;
+import jalview.analysis.NJTree;
+import jalview.api.AlignViewportI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.SequenceNode;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemeProperty;
+import jalview.schemes.ResidueProperties;
+import jalview.schemes.UserColourScheme;
+import jalview.structure.SelectionSource;
+import jalview.util.Format;
+import jalview.util.MappingUtils;
+import jalview.util.MessageManager;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.awt.print.PrinterJob;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.swing.JColorChooser;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+import javax.swing.ToolTipManager;
+
+/**
+ * DOCUMENT ME!
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class TreeCanvas extends JPanel implements MouseListener, Runnable,
+ Printable, MouseMotionListener, SelectionSource
+{
+ /** DOCUMENT ME!! */
+ public static final String PLACEHOLDER = " * ";
+
+ NJTree tree;
+
+ JScrollPane scrollPane;
+
+ TreePanel tp;
+
+ AlignViewport av;
+
+ AlignmentPanel ap;
+
+ Font font;
+
+ FontMetrics fm;
+
+ boolean fitToWindow = true;
+
+ boolean showDistances = false;
+
+ boolean showBootstrap = false;
+
+ boolean markPlaceholders = false;
+
+ int offx = 20;
+
+ int offy;
+
+ float threshold;
+
+ String longestName;
+
+ int labelLength = -1;
+
+ Hashtable nameHash = new Hashtable();
+
+ Hashtable nodeHash = new Hashtable();
+
+ SequenceNode highlightNode;
+
+ boolean applyToAllViews = false;
+
+ /**
+ * Creates a new TreeCanvas object.
+ *
+ * @param av
+ * DOCUMENT ME!
+ * @param tree
+ * DOCUMENT ME!
+ * @param scroller
+ * DOCUMENT ME!
+ * @param label
+ * DOCUMENT ME!
+ */
+ public TreeCanvas(TreePanel tp, AlignmentPanel ap, JScrollPane scroller)
+ {
+ this.tp = tp;
+ this.av = ap.av;
+ this.ap = ap;
+ font = av.getFont();
+ scrollPane = scroller;
+ addMouseListener(this);
+ addMouseMotionListener(this);
+ ToolTipManager.sharedInstance().registerComponent(this);
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param sequence
+ * DOCUMENT ME!
+ */
+ public void treeSelectionChanged(SequenceI sequence)
+ {
+ AlignmentPanel[] aps = getAssociatedPanels();
+
+ for (int a = 0; a < aps.length; a++)
+ {
+ SequenceGroup selected = aps[a].av.getSelectionGroup();
+
+ if (selected == null)
+ {
+ selected = new SequenceGroup();
+ aps[a].av.setSelectionGroup(selected);
+ }
+
+ selected.setEndRes(aps[a].av.getAlignment().getWidth() - 1);
+ selected.addOrRemove(sequence, true);
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param tree
+ * DOCUMENT ME!
+ */
+ public void setTree(NJTree tree)
+ {
+ this.tree = tree;
+ tree.findHeight(tree.getTopNode());
+
+ // Now have to calculate longest name based on the leaves
+ Vector leaves = tree.findLeaves(tree.getTopNode(), new Vector());
+ boolean has_placeholders = false;
+ longestName = "";
+
+ for (int i = 0; i < leaves.size(); i++)
+ {
+ SequenceNode lf = (SequenceNode) leaves.elementAt(i);
+
+ if (lf.isPlaceholder())
+ {
+ has_placeholders = true;
+ }
+
+ if (longestName.length() < ((Sequence) lf.element()).getName()
+ .length())
+ {
+ longestName = TreeCanvas.PLACEHOLDER
+ + ((Sequence) lf.element()).getName();
+ }
+ }
+
+ setMarkPlaceholders(has_placeholders);
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param g
+ * DOCUMENT ME!
+ * @param node
+ * DOCUMENT ME!
+ * @param chunk
+ * DOCUMENT ME!
+ * @param scale
+ * DOCUMENT ME!
+ * @param width
+ * DOCUMENT ME!
+ * @param offx
+ * DOCUMENT ME!
+ * @param offy
+ * DOCUMENT ME!
+ */
+ public void drawNode(Graphics g, SequenceNode node, float chunk,
+ float scale, int width, int offx, int offy)
+ {
+ if (node == null)
+ {
+ return;
+ }
+
+ if ((node.left() == null) && (node.right() == null))
+ {
+ // Drawing leaf node
+ float height = node.height;
+ float dist = node.dist;
+
+ int xstart = (int) ((height - dist) * scale) + offx;
+ int xend = (int) (height * scale) + offx;
+
+ int ypos = (int) (node.ycount * chunk) + offy;
+
+ if (node.element() instanceof SequenceI)
+ {
+ SequenceI seq = (SequenceI) node.element();
+
+ if (av.getSequenceColour(seq) == Color.white)
+ {
+ g.setColor(Color.black);
+ }
+ else
+ {
+ g.setColor(av.getSequenceColour(seq).darker());
+ }
+ }
+ else
+ {
+ g.setColor(Color.black);
+ }
+
+ // Draw horizontal line
+ g.drawLine(xstart, ypos, xend, ypos);
+
+ String nodeLabel = "";
+
+ if (showDistances && (node.dist > 0))
+ {
+ nodeLabel = new Format("%-.2f").form(node.dist);
+ }
+
+ if (showBootstrap && node.bootstrap > -1)
+ {
+ if (showDistances)
+ {
+ nodeLabel = nodeLabel + " : ";
+ }
+
+ nodeLabel = nodeLabel + String.valueOf(node.bootstrap);
+ }
+
+ if (!nodeLabel.equals(""))
+ {
+ g.drawString(nodeLabel, xstart + 2, ypos - 2);
+ }
+
+ String name = (markPlaceholders && node.isPlaceholder()) ? (PLACEHOLDER + node
+ .getName()) : node.getName();
+
+ int charWidth = fm.stringWidth(name) + 3;
+ int charHeight = font.getSize();
+
+ Rectangle rect = new Rectangle(xend + 10, ypos - charHeight / 2,
+ charWidth, charHeight);
+
+ nameHash.put(node.element(), rect);
+
+ // Colour selected leaves differently
+ SequenceGroup selected = av.getSelectionGroup();
+
+ if ((selected != null)
+ && selected.getSequences(null).contains(node.element()))
+ {
+ g.setColor(Color.gray);
+
+ g.fillRect(xend + 10, ypos - charHeight / 2, charWidth, charHeight);
+ g.setColor(Color.white);
+ }
+
+ g.drawString(name, xend + 10, ypos + fm.getDescent());
+ g.setColor(Color.black);
+ }
+ else
+ {
+ drawNode(g, (SequenceNode) node.left(), chunk, scale, width, offx,
+ offy);
+ drawNode(g, (SequenceNode) node.right(), chunk, scale, width, offx,
+ offy);
+
+ float height = node.height;
+ float dist = node.dist;
+
+ int xstart = (int) ((height - dist) * scale) + offx;
+ int xend = (int) (height * scale) + offx;
+ int ypos = (int) (node.ycount * chunk) + offy;
+
+ g.setColor(node.color.darker());
+
+ // Draw horizontal line
+ g.drawLine(xstart, ypos, xend, ypos);
+ if (node == highlightNode)
+ {
+ g.fillRect(xend - 3, ypos - 3, 6, 6);
+ }
+ else
+ {
+ g.fillRect(xend - 2, ypos - 2, 4, 4);
+ }
+
+ int ystart = (int) (((SequenceNode) node.left()).ycount * chunk)
+ + offy;
+ int yend = (int) (((SequenceNode) node.right()).ycount * chunk)
+ + offy;
+
+ Rectangle pos = new Rectangle(xend - 2, ypos - 2, 5, 5);
+ nodeHash.put(node, pos);
+
+ g.drawLine((int) (height * scale) + offx, ystart,
+ (int) (height * scale) + offx, yend);
+
+ String nodeLabel = "";
+
+ if (showDistances && (node.dist > 0))
+ {
+ nodeLabel = new Format("%-.2f").form(node.dist);
+ }
+
+ if (showBootstrap && node.bootstrap > -1)
+ {
+ if (showDistances)
+ {
+ nodeLabel = nodeLabel + " : ";
+ }
+
+ nodeLabel = nodeLabel + String.valueOf(node.bootstrap);
+ }
+
+ if (!nodeLabel.equals(""))
+ {
+ g.drawString(nodeLabel, xstart + 2, ypos - 2);
+ }
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param x
+ * DOCUMENT ME!
+ * @param y
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public Object findElement(int x, int y)
+ {
+ Enumeration keys = nameHash.keys();
+
+ while (keys.hasMoreElements())
+ {
+ Object ob = keys.nextElement();
+ Rectangle rect = (Rectangle) nameHash.get(ob);
+
+ if ((x >= rect.x) && (x <= (rect.x + rect.width)) && (y >= rect.y)
+ && (y <= (rect.y + rect.height)))
+ {
+ return ob;
+ }
+ }
+
+ keys = nodeHash.keys();
+
+ while (keys.hasMoreElements())
+ {
+ Object ob = keys.nextElement();
+ Rectangle rect = (Rectangle) nodeHash.get(ob);
+
+ if ((x >= rect.x) && (x <= (rect.x + rect.width)) && (y >= rect.y)
+ && (y <= (rect.y + rect.height)))
+ {
+ return ob;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param pickBox
+ * DOCUMENT ME!
+ */
+ public void pickNodes(Rectangle pickBox)
+ {
+ int width = getWidth();
+ int height = getHeight();
+
+ SequenceNode top = tree.getTopNode();
+
+ float wscale = (float) ((width * .8) - (offx * 2))
+ / tree.getMaxHeight();
+
+ if (top.count == 0)
+ {
+ top.count = ((SequenceNode) top.left()).count
+ + ((SequenceNode) top.right()).count;
+ }
+
+ float chunk = (float) (height - (offy)) / top.count;
+
+ pickNode(pickBox, top, chunk, wscale, width, offx, offy);
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param pickBox
+ * DOCUMENT ME!
+ * @param node
+ * DOCUMENT ME!
+ * @param chunk
+ * DOCUMENT ME!
+ * @param scale
+ * DOCUMENT ME!
+ * @param width
+ * DOCUMENT ME!
+ * @param offx
+ * DOCUMENT ME!
+ * @param offy
+ * DOCUMENT ME!
+ */
+ public void pickNode(Rectangle pickBox, SequenceNode node, float chunk,
+ float scale, int width, int offx, int offy)
+ {
+ if (node == null)
+ {
+ return;
+ }
+
+ if ((node.left() == null) && (node.right() == null))
+ {
+ float height = node.height;
+ float dist = node.dist;
+
+ int xstart = (int) ((height - dist) * scale) + offx;
+ int xend = (int) (height * scale) + offx;
+
+ int ypos = (int) (node.ycount * chunk) + offy;
+
+ if (pickBox.contains(new Point(xend, ypos)))
+ {
+ if (node.element() instanceof SequenceI)
+ {
+ SequenceI seq = (SequenceI) node.element();
+ SequenceGroup sg = av.getSelectionGroup();
+
+ if (sg != null)
+ {
+ sg.addOrRemove(seq, true);
+ }
+ }
+ }
+ }
+ else
+ {
+ pickNode(pickBox, (SequenceNode) node.left(), chunk, scale, width,
+ offx, offy);
+ pickNode(pickBox, (SequenceNode) node.right(), chunk, scale, width,
+ offx, offy);
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param node
+ * DOCUMENT ME!
+ * @param c
+ * DOCUMENT ME!
+ */
+ public void setColor(SequenceNode node, Color c)
+ {
+ if (node == null)
+ {
+ return;
+ }
+
+ if ((node.left() == null) && (node.right() == null)) // TODO: internal node
+ {
+ node.color = c;
+
+ if (node.element() instanceof SequenceI)
+ {
+ AlignmentPanel[] aps = getAssociatedPanels();
+ if (aps != null)
+ {
+ for (int a = 0; a < aps.length; a++)
+ {
+ final SequenceI seq = (SequenceI) node.element();
+ aps[a].av.setSequenceColour(seq, c);
+ }
+ }
+ }
+ }
+ else
+ {
+ node.color = c;
+ setColor((SequenceNode) node.left(), c);
+ setColor((SequenceNode) node.right(), c);
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ */
+ void startPrinting()
+ {
+ Thread thread = new Thread(this);
+ thread.start();
+ }
+
+ // put printing in a thread to avoid painting problems
+ @Override
+ public void run()
+ {
+ PrinterJob printJob = PrinterJob.getPrinterJob();
+ PageFormat pf = printJob.pageDialog(printJob.defaultPage());
+
+ printJob.setPrintable(this, pf);
+
+ if (printJob.printDialog())
+ {
+ try
+ {
+ printJob.print();
+ } catch (Exception PrintException)
+ {
+ PrintException.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param pg
+ * DOCUMENT ME!
+ * @param pf
+ * DOCUMENT ME!
+ * @param pi
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ *
+ * @throws PrinterException
+ * DOCUMENT ME!
+ */
+ @Override
+ public int print(Graphics pg, PageFormat pf, int pi)
+ throws PrinterException
+ {
+ pg.setFont(font);
+ pg.translate((int) pf.getImageableX(), (int) pf.getImageableY());
+
+ int pwidth = (int) pf.getImageableWidth();
+ int pheight = (int) pf.getImageableHeight();
+
+ int noPages = getHeight() / pheight;
+
+ if (pi > noPages)
+ {
+ return Printable.NO_SUCH_PAGE;
+ }
+
+ if (pwidth > getWidth())
+ {
+ pwidth = getWidth();
+ }
+
+ if (fitToWindow)
+ {
+ if (pheight > getHeight())
+ {
+ pheight = getHeight();
+ }
+
+ noPages = 0;
+ }
+ else
+ {
+ FontMetrics fm = pg.getFontMetrics(font);
+ int height = fm.getHeight() * nameHash.size();
+ pg.translate(0, -pi * pheight);
+ pg.setClip(0, pi * pheight, pwidth, (pi * pheight) + pheight);
+
+ // translate number of pages,
+ // height is screen size as this is the
+ // non overlapping text size
+ pheight = height;
+ }
+
+ draw(pg, pwidth, pheight);
+
+ return Printable.PAGE_EXISTS;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param g
+ * DOCUMENT ME!
+ */
+ @Override
+ public void paintComponent(Graphics g)
+ {
+ super.paintComponent(g);
+ g.setFont(font);
+
+ if (tree == null)
+ {
+ g.drawString(MessageManager.getString("label.calculating_tree")
+ + "....", 20, getHeight() / 2);
+ }
+ else
+ {
+ fm = g.getFontMetrics(font);
+
+ if (nameHash.size() == 0)
+ {
+ repaint();
+ }
+
+ if (fitToWindow
+ || (!fitToWindow && (scrollPane.getHeight() > ((fm
+ .getHeight() * nameHash.size()) + offy))))
+ {
+ draw(g, scrollPane.getWidth(), scrollPane.getHeight());
+ setPreferredSize(null);
+ }
+ else
+ {
+ setPreferredSize(new Dimension(scrollPane.getWidth(),
+ fm.getHeight() * nameHash.size()));
+ draw(g, scrollPane.getWidth(), fm.getHeight() * nameHash.size());
+ }
+
+ scrollPane.revalidate();
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param fontSize
+ * DOCUMENT ME!
+ */
+ @Override
+ public void setFont(Font font)
+ {
+ this.font = font;
+ repaint();
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param g1
+ * DOCUMENT ME!
+ * @param width
+ * DOCUMENT ME!
+ * @param height
+ * DOCUMENT ME!
+ */
+ public void draw(Graphics g1, int width, int height)
+ {
+ Graphics2D g2 = (Graphics2D) g1;
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setColor(Color.white);
+ g2.fillRect(0, 0, width, height);
+ g2.setFont(font);
+
+ if (longestName == null || tree == null)
+ {
+ g2.drawString("Calculating tree.", 20, 20);
+ }
+ offy = font.getSize() + 10;
+
+ fm = g2.getFontMetrics(font);
+
+ labelLength = fm.stringWidth(longestName) + 20; // 20 allows for scrollbar
+
+ float wscale = (width - labelLength - (offx * 2)) / tree.getMaxHeight();
+
+ SequenceNode top = tree.getTopNode();
+
+ if (top.count == 0)
+ {
+ top.count = ((SequenceNode) top.left()).count
+ + ((SequenceNode) top.right()).count;
+ }
+
+ float chunk = (float) (height - (offy)) / top.count;
+
+ drawNode(g2, tree.getTopNode(), chunk, wscale, width, offx, offy);
+
+ if (threshold != 0)
+ {
+ if (av.getCurrentTree() == tree)
+ {
+ g2.setColor(Color.red);
+ }
+ else
+ {
+ g2.setColor(Color.gray);
+ }
+
+ int x = (int) ((threshold * (getWidth() - labelLength - (2 * offx))) + offx);
+
+ g2.drawLine(x, 0, x, getHeight());
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param e
+ * DOCUMENT ME!
+ */
+ @Override
+ public void mouseReleased(MouseEvent e)
+ {
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param e
+ * DOCUMENT ME!
+ */
+ @Override
+ public void mouseEntered(MouseEvent e)
+ {
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param e
+ * DOCUMENT ME!
+ */
+ @Override
+ public void mouseExited(MouseEvent e)
+ {
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param e
+ * DOCUMENT ME!
+ */
+ @Override
+ public void mouseClicked(MouseEvent evt)
+ {
+ if (highlightNode != null)
+ {
+ if (SwingUtilities.isRightMouseButton(evt))
+ {
+ Color col = JColorChooser.showDialog(this,
+ MessageManager.getString("label.select_subtree_colour"),
+ highlightNode.color);
+ if (col != null)
+ {
+ setColor(highlightNode, col);
+ }
+ }
+ else if (evt.getClickCount() > 1)
+ {
+ tree.swapNodes(highlightNode);
+ tree.reCount(tree.getTopNode());
+ tree.findHeight(tree.getTopNode());
+ }
+ else
+ {
+ Vector leaves = new Vector();
+ tree.findLeaves(highlightNode, leaves);
+
+ for (int i = 0; i < leaves.size(); i++)
+ {
+ SequenceI seq = (SequenceI) ((SequenceNode) leaves.elementAt(i))
+ .element();
+ treeSelectionChanged(seq);
+ }
+ av.sendSelection();
+ }
+
+ PaintRefresher.Refresh(tp, av.getSequenceSetId());
+ repaint();
+ }
+ }
+
+ @Override
+ public void mouseMoved(MouseEvent evt)
+ {
+ av.setCurrentTree(tree);
+
+ Object ob = findElement(evt.getX(), evt.getY());
+
+ if (ob instanceof SequenceNode)
+ {
+ highlightNode = (SequenceNode) ob;
+ this.setToolTipText("<html>"
+ + MessageManager.getString("label.highlightnode"));
+ repaint();
+
+ }
+ else
+ {
+ if (highlightNode != null)
+ {
+ highlightNode = null;
+ setToolTipText(null);
+ repaint();
+ }
+ }
+ }
+
+ @Override
+ public void mouseDragged(MouseEvent ect)
+ {
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param e
+ * DOCUMENT ME!
+ */
+ @Override
+ public void mousePressed(MouseEvent e)
+ {
+ av.setCurrentTree(tree);
+
+ int x = e.getX();
+ int y = e.getY();
+
+ Object ob = findElement(x, y);
+
+ if (ob instanceof SequenceI)
+ {
+ treeSelectionChanged((Sequence) ob);
+ PaintRefresher.Refresh(tp, ap.av.getSequenceSetId());
+ repaint();
+ av.sendSelection();
+ return;
+ }
+ else if (!(ob instanceof SequenceNode))
+ {
+ // Find threshold
+ if (tree.getMaxHeight() != 0)
+ {
+ threshold = (float) (x - offx)
+ / (float) (getWidth() - labelLength - (2 * offx));
+
+ tree.getGroups().removeAllElements();
+ tree.groupNodes(tree.getTopNode(), threshold);
+ setColor(tree.getTopNode(), Color.black);
+
+ AlignmentPanel[] aps = getAssociatedPanels();
+
+ // TODO push calls below into a single AlignViewportI method?
+ // see also AlignViewController.deleteGroups
+ for (int a = 0; a < aps.length; a++)
+ {
+ aps[a].av.setSelectionGroup(null);
+ aps[a].av.getAlignment().deleteAllGroups();
+ aps[a].av.clearSequenceColours();
+ if (aps[a].av.getCodingComplement() != null)
+ {
+ aps[a].av.getCodingComplement().setSelectionGroup(null);
+ aps[a].av.getCodingComplement().getAlignment()
+ .deleteAllGroups();
+ aps[a].av.getCodingComplement().clearSequenceColours();
+ }
+ }
+ colourGroups();
+ }
+
+ PaintRefresher.Refresh(tp, ap.av.getSequenceSetId());
+ repaint();
+ }
+
+ }
+
+ void colourGroups()
+ {
+ AlignmentPanel[] aps = getAssociatedPanels();
+ for (int i = 0; i < tree.getGroups().size(); i++)
+ {
+ Color col = new Color((int) (Math.random() * 255),
+ (int) (Math.random() * 255), (int) (Math.random() * 255));
+ setColor((SequenceNode) tree.getGroups().elementAt(i), col.brighter());
+
+ Vector l = tree.findLeaves(
+ (SequenceNode) tree.getGroups().elementAt(i), new Vector());
+
+ Vector sequences = new Vector();
+
+ for (int j = 0; j < l.size(); j++)
+ {
+ SequenceI s1 = (SequenceI) ((SequenceNode) l.elementAt(j))
+ .element();
+
+ if (!sequences.contains(s1))
+ {
+ sequences.addElement(s1);
+ }
+ }
+
+ ColourSchemeI cs = null;
+ SequenceGroup sg = new SequenceGroup(sequences, null, cs, true, true,
+ false, 0, av.getAlignment().getWidth() - 1);
+
+ if (av.getGlobalColourScheme() != null)
+ {
+ if (av.getGlobalColourScheme() instanceof UserColourScheme)
+ {
+ cs = new UserColourScheme(
+ ((UserColourScheme) av.getGlobalColourScheme())
+ .getColours());
+
+ }
+ else
+ {
+ cs = ColourSchemeProperty.getColour(sg, ColourSchemeProperty
+ .getColourName(av.getGlobalColourScheme()));
+ }
+ // cs is null if shading is an annotationColourGradient
+ if (cs != null)
+ {
+ cs.setThreshold(av.getGlobalColourScheme().getThreshold(),
+ av.isIgnoreGapsConsensus());
+ }
+ }
+ sg.cs = cs;
+ // sg.recalcConservation();
+ sg.setName("JTreeGroup:" + sg.hashCode());
+ sg.setIdColour(col);
+
+ for (int a = 0; a < aps.length; a++)
+ {
+ if (aps[a].av.getGlobalColourScheme() != null
+ && aps[a].av.getGlobalColourScheme().conservationApplied())
+ {
+ Conservation c = new Conservation("Group",
+ ResidueProperties.propHash, 3, sg.getSequences(null),
+ sg.getStartRes(), sg.getEndRes());
+
+ c.calculate();
+ c.verdict(false, aps[a].av.getConsPercGaps());
+ sg.cs.setConservation(c);
+ }
+
+ aps[a].av.getAlignment().addGroup(new SequenceGroup(sg));
+ // TODO can we push all of the below into AlignViewportI?
+ final AlignViewportI codingComplement = aps[a].av
+ .getCodingComplement();
+ if (codingComplement != null)
+ {
+ if (codingComplement != null)
+ {
+ SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
+ av, codingComplement);
+ if (mappedGroup.getSequences().size() > 0)
+ {
+ codingComplement.getAlignment().addGroup(mappedGroup);
+ for (SequenceI seq : mappedGroup.getSequences())
+ {
+ codingComplement.setSequenceColour(seq, col.brighter());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // notify the panel(s) to redo any group specific stuff.
+ for (int a = 0; a < aps.length; a++)
+ {
+ aps[a].updateAnnotation();
+ // TODO: JAL-868 - need to ensure view colour change message is broadcast
+ // to any Jmols listening in
+ final AlignViewportI codingComplement = aps[a].av
+ .getCodingComplement();
+ if (codingComplement != null)
+ {
+ ((AlignViewport) codingComplement).getAlignPanel()
+ .updateAnnotation();
+
+ }
+
+ }
+
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param state
+ * DOCUMENT ME!
+ */
+ public void setShowDistances(boolean state)
+ {
+ this.showDistances = state;
+ repaint();
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param state
+ * DOCUMENT ME!
+ */
+ public void setShowBootstrap(boolean state)
+ {
+ this.showBootstrap = state;
+ repaint();
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param state
+ * DOCUMENT ME!
+ */
+ public void setMarkPlaceholders(boolean state)
+ {
+ this.markPlaceholders = state;
+ repaint();
+ }
+
+ AlignmentPanel[] getAssociatedPanels()
+ {
+ if (applyToAllViews)
+ {
+ return PaintRefresher.getAssociatedPanels(av.getSequenceSetId());
+ }
+ else
+ {
+ return new AlignmentPanel[] { ap };
+ }
+ }
+}
package jalview.gui;
import jalview.analysis.AlignmentSorter;
+import jalview.analysis.AverageDistanceTree;
import jalview.analysis.NJTree;
+import jalview.analysis.TreeBuilder;
+import jalview.analysis.TreeModel;
+import jalview.analysis.scoremodels.ScoreModels;
import jalview.api.analysis.ScoreModelI;
-import jalview.api.analysis.ViewBasedAnalysisI;
+import jalview.api.analysis.SimilarityParamsI;
import jalview.bin.Cache;
import jalview.commands.CommandI;
import jalview.commands.OrderCommand;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentView;
import jalview.datamodel.BinaryNode;
-import jalview.datamodel.ColumnSelection;
import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.NodeTransformI;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
import jalview.io.JalviewFileView;
import jalview.io.NewickFile;
import jalview.jbgui.GTreePanel;
-import jalview.schemes.ResidueProperties;
import jalview.util.ImageMaker;
import jalview.util.MessageManager;
import jalview.viewmodel.AlignmentViewport;
*/
public class TreePanel extends GTreePanel
{
- String type;
+ String treeType;
- String pwtype;
+ String scoreModelName; // if tree computed
+
+ String treeTitle; // if tree loaded
+
+ SimilarityParamsI similarityParams;
TreeCanvas treeCanvas;
- NJTree tree;
+ TreeModel tree;
AlignViewport av;
/**
* Creates a new TreePanel object.
*
- * @param av
- * DOCUMENT ME!
- * @param seqVector
- * DOCUMENT ME!
+ * @param ap
* @param type
- * DOCUMENT ME!
- * @param pwtype
- * DOCUMENT ME!
- * @param s
- * DOCUMENT ME!
- * @param e
- * DOCUMENT ME!
+ * @param modelName
+ * @param options
*/
- public TreePanel(AlignmentPanel ap, String type, String pwtype)
+ public TreePanel(AlignmentPanel ap, String type, String modelName,
+ SimilarityParamsI options)
{
super();
- initTreePanel(ap, type, pwtype, null, null);
+ this.similarityParams = options;
+ initTreePanel(ap, type, modelName, null, null);
// We know this tree has distances. JBPNote TODO: prolly should add this as
// a userdefined default
// showDistances(true);
}
- /**
- * Creates a new TreePanel object.
- *
- * @param av
- * DOCUMENT ME!
- * @param seqVector
- * DOCUMENT ME!
- * @param newtree
- * DOCUMENT ME!
- * @param type
- * DOCUMENT ME!
- * @param pwtype
- * DOCUMENT ME!
- */
- public TreePanel(AlignmentPanel ap, String type, String pwtype,
- NewickFile newtree)
- {
- super();
- initTreePanel(ap, type, pwtype, newtree, null);
- }
-
- public TreePanel(AlignmentPanel av, String type, String pwtype,
- NewickFile newtree, AlignmentView inputData)
+ public TreePanel(AlignmentPanel alignPanel, NewickFile newtree,
+ String theTitle, AlignmentView inputData)
{
super();
- initTreePanel(av, type, pwtype, newtree, inputData);
+ this.treeTitle = theTitle;
+ initTreePanel(alignPanel, null, null, newtree, inputData);
}
public AlignmentI getAlignment()
return treeCanvas.av;
}
- void initTreePanel(AlignmentPanel ap, String type, String pwtype,
+ void initTreePanel(AlignmentPanel ap, String type, String modelName,
NewickFile newTree, AlignmentView inputData)
{
av = ap.av;
- this.type = type;
- this.pwtype = pwtype;
+ this.treeType = type;
+ this.scoreModelName = modelName;
treeCanvas = new TreeCanvas(this, ap, scrollPane);
scrollPane.setViewportView(treeCanvas);
.println("new alignment sequences vector value is null");
}
- tree.UpdatePlaceHolders((List<SequenceI>) evt.getNewValue());
+ tree.updatePlaceHolders((List<SequenceI>) evt.getNewValue());
treeCanvas.nameHash.clear(); // reset the mapping between canvas
// rectangles and leafnodes
repaint();
}
});
- TreeLoader tl = new TreeLoader(newTree);
- if (inputData != null)
- {
- tl.odata = inputData;
- }
+ TreeLoader tl = new TreeLoader(newTree, inputData);
tl.start();
}
class TreeLoader extends Thread
{
- NewickFile newtree;
+ private NewickFile newtree;
- jalview.datamodel.AlignmentView odata = null;
+ private AlignmentView odata = null;
- public TreeLoader(NewickFile newtree)
+ public TreeLoader(NewickFile newickFile, AlignmentView inputData)
{
- this.newtree = newtree;
- if (newtree != null)
+ this.newtree = newickFile;
+ this.odata = inputData;
+
+ if (newickFile != null)
{
// Must be outside run(), as Jalview2XML tries to
// update distance/bootstrap visibility at the same time
- showBootstrap(newtree.HasBootstrap());
- showDistances(newtree.HasDistances());
+ showBootstrap(newickFile.HasBootstrap());
+ showDistances(newickFile.HasDistances());
}
}
if (newtree != null)
{
- if (odata == null)
- {
- tree = new NJTree(av.getAlignment().getSequencesArray(), newtree);
- }
- else
+ tree = new TreeModel(av.getAlignment().getSequencesArray(), odata,
+ newtree);
+ if (tree.getOriginalData() == null)
{
- tree = new NJTree(av.getAlignment().getSequencesArray(), odata,
- newtree);
- }
- if (!tree.hasOriginalSequenceData())
- {
- allowOriginalSeqData(false);
+ originalSeqData.setVisible(false);
}
}
else
{
- int start, end;
- SequenceI[] seqs;
- boolean selview = av.getSelectionGroup() != null
- && av.getSelectionGroup().getSize() > 1;
- AlignmentView seqStrings = av.getAlignmentView(selview);
- if (!selview)
- {
- start = 0;
- end = av.getAlignment().getWidth();
- seqs = av.getAlignment().getSequencesArray();
- }
- else
- {
- start = av.getSelectionGroup().getStartRes();
- end = av.getSelectionGroup().getEndRes() + 1;
- seqs = av.getSelectionGroup().getSequencesInOrder(
- av.getAlignment());
- }
- ScoreModelI sm = ResidueProperties.getScoreModel(pwtype);
- if (sm instanceof ViewBasedAnalysisI)
- {
- try
- {
- sm = sm.getClass().newInstance();
- ((ViewBasedAnalysisI) sm)
- .configureFromAlignmentView(treeCanvas.ap);
- } catch (Exception q)
- {
- Cache.log.error("Couldn't create a scoremodel instance for "
- + sm.getName());
- }
- tree = new NJTree(seqs, seqStrings, type, pwtype, sm, start, end);
- }
- else
- {
- tree = new NJTree(seqs, seqStrings, type, pwtype, null, start,
- end);
- }
+ ScoreModelI sm = ScoreModels.getInstance().getScoreModel(
+ scoreModelName, treeCanvas.ap);
+ TreeBuilder njtree = treeType.equals(TreeBuilder.NEIGHBOUR_JOINING) ? new NJTree(
+ av, sm, similarityParams) : new AverageDistanceTree(av, sm,
+ similarityParams);
+ tree = new TreeModel(njtree);
showDistances(true);
}
treeCanvas.setMarkPlaceholders(b);
}
- private void allowOriginalSeqData(boolean b)
- {
- originalSeqData.setVisible(b);
- }
-
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
- public NJTree getTree()
+ public TreeModel getTree()
{
return tree;
}
{
CutAndPasteTransfer cap = new CutAndPasteTransfer();
- StringBuffer buffer = new StringBuffer();
+ String newTitle = getPanelTitle();
- if (type.equals("AV"))
- {
- buffer.append("Average distance tree using ");
- }
- else
- {
- buffer.append("Neighbour joining tree using ");
- }
-
- if (pwtype.equals("BL"))
- {
- buffer.append("BLOSUM62");
- }
- else
- {
- buffer.append("PID");
- }
-
- jalview.io.NewickFile fout = new jalview.io.NewickFile(
- tree.getTopNode());
+ NewickFile fout = new NewickFile(tree.getTopNode());
try
{
- cap.setText(fout.print(tree.isHasBootstrap(), tree.isHasDistances(),
- tree.isHasRootDistance()));
- Desktop.addInternalFrame(cap, buffer.toString(), 500, 100);
+ cap.setText(fout.print(tree.hasBootstrap(), tree.hasDistances(),
+ tree.hasRootDistance()));
+ Desktop.addInternalFrame(cap, newTitle, 500, 100);
} catch (OutOfMemoryError oom)
{
new OOMWarning("generating newick tree file", oom);
{
jalview.io.NewickFile fout = new jalview.io.NewickFile(
tree.getTopNode());
- String output = fout.print(tree.isHasBootstrap(),
- tree.isHasDistances(), tree.isHasRootDistance());
+ String output = fout.print(tree.hasBootstrap(),
+ tree.hasDistances(), tree.hasRootDistance());
java.io.PrintWriter out = new java.io.PrintWriter(
new java.io.FileWriter(choice));
out.println(output);
@Override
public void originalSeqData_actionPerformed(ActionEvent e)
{
- if (!tree.hasOriginalSequenceData())
+ AlignmentView originalData = tree.getOriginalData();
+ if (originalData == null)
{
jalview.bin.Cache.log
.info("Unexpected call to originalSeqData_actionPerformed - should have hidden this menu action.");
} catch (Exception ex)
{
}
- ;
- Object[] alAndColsel = tree.seqData.getAlignmentAndColumnSelection(gc);
+
+ Object[] alAndColsel = originalData.getAlignmentAndHiddenColumns(gc);
if (alAndColsel != null && alAndColsel[0] != null)
{
if (true)
{
// make a new frame!
- AlignFrame af = new AlignFrame(al,
- (ColumnSelection) alAndColsel[1], AlignFrame.DEFAULT_WIDTH,
+ AlignFrame af = new AlignFrame(al, (HiddenColumns) alAndColsel[1],
+ AlignFrame.DEFAULT_WIDTH,
AlignFrame.DEFAULT_HEIGHT);
// >>>This is a fix for the moment, until a better solution is
public CommandI sortAlignmentIn(AlignmentPanel ap)
{
- AlignmentViewport av = ap.av;
- SequenceI[] oldOrder = av.getAlignment().getSequencesArray();
- AlignmentSorter.sortByTree(av.getAlignment(), tree);
+ AlignmentViewport viewport = ap.av;
+ SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+ AlignmentSorter.sortByTree(viewport.getAlignment(), tree);
CommandI undo;
- undo = new OrderCommand("Tree Sort", oldOrder, av.getAlignment());
+ undo = new OrderCommand("Tree Sort", oldOrder, viewport.getAlignment());
ap.paintAlignment(true);
return undo;
return treeCanvas.font;
}
- public void setTreeFont(Font font)
+ public void setTreeFont(Font f)
{
if (treeCanvas != null)
{
- treeCanvas.setFont(font);
+ treeCanvas.setFont(f);
}
}
}
if (newname != null)
{
- String oldname = ((SequenceNode) node).getName();
- // TODO : save in the undo object for this modification.
+ // String oldname = ((SequenceNode) node).getName();
+ // TODO : save oldname in the undo object for this modification.
((SequenceNode) node).setName(newname);
}
}
}
});
}
+
+ /**
+ * Formats a localised title for the tree panel, like
+ * <p>
+ * Neighbour Joining Using BLOSUM62
+ * <p>
+ * For a tree loaded from file, just uses the file name
+ * @return
+ */
+ public String getPanelTitle()
+ {
+ if (treeTitle != null)
+ {
+ return treeTitle;
+ }
+
+ /*
+ * i18n description of Neighbour Joining or Average Distance method
+ */
+ String treecalcnm = MessageManager.getString("label.tree_calc_"
+ + treeType.toLowerCase());
+
+ /*
+ * short score model name (long description can be too long)
+ */
+ String smn = scoreModelName;
+
+ /*
+ * put them together as <method> Using <model>
+ */
+ final String ttl = MessageManager.formatMessage("label.treecalc_title",
+ treecalcnm, smn);
+ return ttl;
+ }
}
*/
package jalview.gui;
-import jalview.api.structures.JalviewStructureDisplayI;
import jalview.bin.Cache;
-import jalview.datamodel.SequenceGroup;
import jalview.io.JalviewFileChooser;
import jalview.io.JalviewFileView;
import jalview.jbgui.GUserDefinedColours;
import jalview.schemabinding.version2.Colour;
import jalview.schemabinding.version2.JalviewUserColours;
import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemeLoader;
import jalview.schemes.ColourSchemes;
import jalview.schemes.ResidueProperties;
import jalview.schemes.UserColourScheme;
import java.awt.Color;
import java.awt.Font;
import java.awt.Insets;
-import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
private static final String LAST_DIRECTORY = "LAST_DIRECTORY";
- private static final int MY_FRAME_HEIGHT = 420;
+ private static final int MY_FRAME_HEIGHT = 440;
private static final int MY_FRAME_WIDTH = 810;
AlignmentPanel ap;
- SequenceGroup seqGroup;
-
- List<JButton> selectedButtons;
-
+ /*
+ * the colour scheme when the dialog was opened, or
+ * the scheme last saved to file
+ */
ColourSchemeI oldColourScheme;
- JInternalFrame frame;
+ /*
+ * flag is true if the colour scheme has been changed since the
+ * dialog was opened, or the changes last saved to file
+ */
+ boolean changed;
- JalviewStructureDisplayI structureViewer;
+ JInternalFrame frame;
List<JButton> upperCaseButtons;
List<JButton> lowerCaseButtons;
/**
- * Creates a new UserDefinedColours object.
+ * Creates and displays a new UserDefinedColours panel
*
- * @param ap
- * @param sg
+ * @param alignPanel
*/
- public UserDefinedColours(AlignmentPanel ap, SequenceGroup sg)
+ public UserDefinedColours(AlignmentPanel alignPanel)
{
this();
lcaseColour.setEnabled(false);
- this.ap = ap;
- seqGroup = sg;
+ this.ap = alignPanel;
- if (seqGroup != null)
- {
- oldColourScheme = seqGroup.getColourScheme();
- }
- else
- {
- oldColourScheme = ap.av.getGlobalColourScheme();
- }
+ oldColourScheme = alignPanel.av.getGlobalColourScheme();
if (oldColourScheme instanceof UserColourScheme)
{
showFrame();
}
- public UserDefinedColours(JalviewStructureDisplayI viewer,
- ColourSchemeI oldcs)
- {
- this();
- this.structureViewer = viewer;
-
- colorChooser.getSelectionModel().addChangeListener(this);
-
- oldColourScheme = oldcs;
-
- if (oldColourScheme instanceof UserColourScheme)
- {
- schemeName.setText(((UserColourScheme) oldColourScheme)
- .getSchemeName());
- }
-
- resetButtonPanel(false);
-
- showFrame();
-
- }
-
- public UserDefinedColours()
+ UserDefinedColours()
{
super();
selectedButtons = new ArrayList<JButton>();
Desktop.addInternalFrame(frame,
MessageManager.getString("label.user_defined_colours"),
MY_FRAME_WIDTH, MY_FRAME_HEIGHT, true);
-
- if (seqGroup != null)
- {
- frame.setTitle(frame.getTitle() + " (" + seqGroup.getName() + ")");
- }
}
/**
{
JButton button = null;
final Color newColour = colorChooser.getColor();
- for (int i = 0; i < selectedButtons.size(); i++)
- {
- button = selectedButtons.get(i);
- button.setBackground(newColour);
- button.setForeground(ColorUtils.brighterThan(newColour));
- }
if (lcaseColour.isSelected())
{
+ selectedButtons.clear();
for (int i = 0; i < lowerCaseButtons.size(); i++)
{
button = lowerCaseButtons.get(i);
button.setForeground(ColorUtils.brighterThan(button.getBackground()));
}
}
+ for (int i = 0; i < selectedButtons.size(); i++)
+ {
+ button = selectedButtons.get(i);
+ button.setBackground(newColour);
+ button.setForeground(ColorUtils.brighterThan(newColour));
+ }
+
+ changed = true;
}
/**
}
else
{
+ /*
+ * OK is treated as 'apply colours and close'
+ */
applyButton_actionPerformed();
+ /*
+ * If editing a named colour scheme, warn if changes
+ * have not been saved
+ */
+ warnIfUnsavedChanges();
+
try
{
frame.setClosed(true);
}
/**
+ * If we have made changes to an existing user defined colour scheme but not
+ * saved them, show a dialog with the option to save. If the user chooses to
+ * save, do so, else clear the colour scheme name to indicate a new colour
+ * scheme.
+ */
+ protected void warnIfUnsavedChanges()
+ {
+ if (!changed)
+ {
+ return;
+ }
+
+ String name = schemeName.getText().trim();
+ if (oldColourScheme != null && !"".equals(name)
+ && name.equals(oldColourScheme.getSchemeName()))
+ {
+ String message = MessageManager.formatMessage("label.scheme_changed",
+ name);
+ String title = MessageManager.getString("label.save_changes");
+ String[] options = new String[] { title,
+ MessageManager.getString("label.dont_save_changes"), };
+ final String question = JvSwingUtils.wrapTooltip(true, message);
+ int response = JvOptionPane.showOptionDialog(Desktop.desktop,
+ question, title, JvOptionPane.DEFAULT_OPTION,
+ JvOptionPane.PLAIN_MESSAGE, null, options, options[0]);
+
+ boolean saved = false;
+ if (response == 0)
+ {
+ /*
+ * prompt to save changes to file
+ */
+ saved = savebutton_actionPerformed();
+ }
+
+ /*
+ * if user chooses not to save (either in this dialog or in the
+ * save as dialogs), treat this as a new user defined colour scheme
+ */
+ if (!saved)
+ {
+ /*
+ * clear scheme name and re-apply as an anonymous scheme
+ */
+ schemeName.setText("");
+ applyButton_actionPerformed();
+ }
+ }
+ }
+
+ /**
* Returns true if the user has not made any colour selection (including if
* 'case-sensitive' selected and no lower-case colour chosen).
*
}
/**
- * Applies the current colour scheme to the alignment, sequence group or
- * structure view.
+ * Applies the current colour scheme to the alignment or sequence group
*/
@Override
protected void applyButton_actionPerformed()
}
UserColourScheme ucs = getSchemeFromButtons();
- if (seqGroup != null)
- {
- seqGroup.setColourScheme(ucs);
- ap.paintAlignment(true);
- }
- else if (ap != null)
- {
- ap.alignFrame.changeColour(ucs);
- }
- else if (structureViewer != null)
- {
- structureViewer.setJalviewColourScheme(ucs);
- }
+ ap.alignFrame.changeColour(ucs);
}
+ /**
+ * Constructs an instance of UserColourScheme with the residue colours
+ * currently set on the buttons on the panel
+ *
+ * @return
+ */
UserColourScheme getSchemeFromButtons()
{
ucs.setLowerCaseColours(newColours);
}
- // if (ap != null)
- // {
- // ucs.setThreshold(0, ap.av.isIgnoreGapsConsensus());
- // }
-
return ucs;
}
/**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
+ * Action on clicking Load scheme button.
+ * <ul>
+ * <li>Open a file chooser to browse for files with extension .jc</li>
+ * <li>Load in the colour scheme and transfer it to this panel's buttons</li>
+ * <li>Register the loaded colour scheme</li>
+ * </ul>
*/
@Override
- protected void loadbutton_actionPerformed(ActionEvent e)
+ protected void loadbutton_actionPerformed()
{
upperCaseButtons = new ArrayList<JButton>();
lowerCaseButtons = new ArrayList<JButton>();
File choice = chooser.getSelectedFile();
Cache.setProperty(LAST_DIRECTORY, choice.getParent());
- UserColourScheme ucs = ColourSchemes.loadColourScheme(choice
+ UserColourScheme ucs = ColourSchemeLoader.loadColourScheme(choice
.getAbsolutePath());
Color[] colors = ucs.getColours();
schemeName.setText(ucs.getSchemeName());
{
colours = colours.substring(0, colours.indexOf("|"));
}
- ret = ColourSchemes.loadColourScheme(colours);
+ ret = ColourSchemeLoader.loadColourScheme(colours);
}
if (ret == null)
}
/**
- * DOCUMENT ME!
+ * Action on pressing the Save button.
+ * <ul>
+ * <li>Check a name has been entered</li>
+ * <li>Warn if the name already exists, remove any existing scheme of the same
+ * name if overwriting</li>
+ * <li>Do the standard file chooser thing to write with extension .jc</li>
+ * <li>If saving changes (possibly not yet applied) to the currently selected
+ * colour scheme, then apply the changes, as it is too late to back out now</li>
+ * <li>Don't apply the changes if the currently selected scheme is different,
+ * to allow a new scheme to be configured and saved but not applied</li>
+ * </ul>
+ * Returns true if the scheme is saved to file, false if it is not
*
- * @param e
- * DOCUMENT ME!
+ * @return
*/
@Override
- protected void savebutton_actionPerformed(ActionEvent e)
+ protected boolean savebutton_actionPerformed()
{
String name = schemeName.getText().trim();
if (name.length() < 1)
.getString("label.user_colour_scheme_must_have_name"),
MessageManager.getString("label.no_name_colour_scheme"),
JvOptionPane.WARNING_MESSAGE);
- return;
+ return false;
}
if (ColourSchemes.getInstance().nameExists(name))
JvOptionPane.YES_NO_OPTION);
if (reply != JvOptionPane.YES_OPTION)
{
- return;
+ return false;
}
- ColourSchemes.getInstance().removeColourScheme(name);
}
JalviewFileChooser chooser = new JalviewFileChooser("jc",
"Jalview User Colours");
int value = chooser.showSaveDialog(this);
- if (value == JalviewFileChooser.APPROVE_OPTION)
+ if (value != JalviewFileChooser.APPROVE_OPTION)
+ {
+ return false;
+ }
+
+ File file = chooser.getSelectedFile();
+ UserColourScheme updatedScheme = addNewColourScheme(file.getPath());
+ saveToFile(file);
+ changed = false;
+
+ /*
+ * changes saved - apply to alignment if we are changing
+ * the currently selected colour scheme; also make the updated
+ * colours the 'backout' scheme on Cancel
+ */
+ if (oldColourScheme != null
+ && name.equals(oldColourScheme.getSchemeName()))
{
- File file = chooser.getSelectedFile();
- addNewColourScheme(file.getPath());
- saveToFile(file);
+ oldColourScheme = updatedScheme;
+ applyButton_actionPerformed();
}
+ return true;
}
/**
* the colour scheme.
*
* @param filePath
+ * @return
*/
- protected void addNewColourScheme(String filePath)
+ protected UserColourScheme addNewColourScheme(String filePath)
{
/*
* update the delimited list of user defined colour files in
{
ap.alignFrame.buildColourMenu();
}
+
+ return ucs;
}
/**
* marshal to file
*/
JalviewUserColours ucs = new JalviewUserColours();
- ucs.setSchemeName(schemeName.getText());
+ String name = schemeName.getText();
+ ucs.setSchemeName(name);
try
{
PrintWriter out = new PrintWriter(new OutputStreamWriter(
}
/**
- * On cancel, restores the colour scheme before the dialogue was opened
- *
- * @param e
+ * On cancel, restores the colour scheme that was selected before the dialogue
+ * was opened
*/
@Override
- protected void cancelButton_actionPerformed(ActionEvent e)
+ protected void cancelButton_actionPerformed()
{
- if (ap != null)
- {
- if (seqGroup != null)
- {
- seqGroup.setColourScheme(oldColourScheme);
- }
- else
- {
- ap.alignFrame.changeColour(oldColourScheme);
- }
- ap.paintAlignment(true);
- }
-
- if (structureViewer != null)
- {
- structureViewer.setJalviewColourScheme(oldColourScheme);
- }
+ ap.alignFrame.changeColour(oldColourScheme);
+ ap.paintAlignment(true);
try
{
}
}
+ /**
+ * Action on selecting or deselecting the Case Sensitive option. When
+ * selected, separate buttons are shown for lower case residues, and the panel
+ * is resized to accommodate them. Also, the checkbox for 'apply colour to all
+ * lower case' is enabled.
+ */
@Override
- public void caseSensitive_actionPerformed(ActionEvent e)
+ public void caseSensitive_actionPerformed()
{
boolean selected = caseSensitive.isSelected();
resetButtonPanel(selected);
import jalview.bin.Cache;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.io.VamsasAppDatastore;
import java.util.Iterator;
import javax.swing.JInternalFrame;
-import javax.swing.JOptionPane;
import uk.ac.vamsas.client.ClientHandle;
import uk.ac.vamsas.client.IClient;
{
// TODO: rationalise : can only clear a selection over a
// referred to object
- ssm.sendSelection(null, null, me);
+ ssm.sendSelection(null, null, null, me);
return;
}
Class type = null;
}
if (send)
{
- ssm.sendSelection(jselection, colsel, me);
+ ssm.sendSelection(jselection, colsel, null, me);
}
// discard message.
for (int c = 0; c < jvobjs.length; c++)
@Override
public void selection(SequenceGroup seqsel,
- ColumnSelection colsel, SelectionSource source)
+ ColumnSelection colsel, HiddenColumns hidden,
+ SelectionSource source)
{
if (vobj2jv == null)
{
}
else
{
- int[] intervals = colsel.getVisibleContigs(
+ // int[] intervals = colsel.getVisibleContigs(
+ // seqsel.getStartRes(), seqsel.getEndRes() + 1);
+ int[] intervals = hidden.getVisibleContigs(
seqsel.getStartRes(), seqsel.getEndRes() + 1);
for (int iv = 0; iv < intervals.length; iv += 2)
{
import jalview.datamodel.Annotation;
import jalview.datamodel.ColumnSelection;
import jalview.datamodel.GraphLine;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.HiddenSequences;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
*/
public class ViewDef
{
- public String viewname;
+ // TODO this class is not used - remove?
+ public final String viewname;
- public HiddenSequences hidseqs;
+ public final HiddenSequences hidseqs;
- public ColumnSelection hiddencols;
+ public final HiddenColumns hiddencols;
- public Vector visibleGroups;
+ public final Hashtable hiddenRepSeqs;
- public Hashtable hiddenRepSeqs;
-
- public ViewDef(String viewname, HiddenSequences hidseqs,
- ColumnSelection hiddencols, Hashtable hiddenRepSeqs)
+ public ViewDef(String vname, HiddenSequences hseqs,
+ HiddenColumns hcols, Hashtable hRepSeqs)
{
- this.viewname = viewname;
- this.hidseqs = hidseqs;
- this.hiddencols = hiddencols;
- this.hiddenRepSeqs = hiddenRepSeqs;
+ this.viewname = vname;
+ this.hidseqs = hseqs;
+ this.hiddencols = hcols;
+ this.hiddenRepSeqs = hRepSeqs;
}
}
*/
public String printAnnotations(AlignmentAnnotation[] annotations,
List<SequenceGroup> list, Hashtable properties,
- ColumnSelection cs, AlignmentI al, ViewDef view)
+ HiddenColumns cs,
+ AlignmentI al, ViewDef view)
{
if (view != null)
{
}
if (list == null)
{
- list = view.visibleGroups;
+ // list = view.visibleGroups;
}
if (cs == null)
{
if (cs != null && cs.hasHiddenColumns())
{
text.append("VIEW_HIDECOLS\t");
- List<int[]> hc = cs.getHiddenColumns();
+ List<int[]> hc = cs.getHiddenRegions();
boolean comma = false;
for (int[] r : hc)
{
return false;
}
- public void printGroups(List<SequenceGroup> list)
+ protected void printGroups(List<SequenceGroup> list)
{
SequenceI seqrep = null;
for (SequenceGroup sg : list)
if (sg.cs != null)
{
text.append("colour=");
- text.append(sg.cs.toString());
+ text.append(ColourSchemeProperty.getColourName(sg.cs
+ .getColourScheme()));
text.append("\t");
if (sg.cs.getThreshold() != 0)
{
String file, DataSourceType protocol)
{
ColumnSelection colSel = viewport.getColumnSelection();
+ HiddenColumns hidden = viewport.getAlignment().getHiddenColumns();
if (colSel == null)
{
colSel = new ColumnSelection();
}
- boolean rslt = readAnnotationFile(viewport.getAlignment(), colSel,
+ if (hidden == null)
+ {
+ hidden = new HiddenColumns();
+ }
+ boolean rslt = readAnnotationFile(viewport.getAlignment(), hidden,
file, protocol);
- if (rslt && (colSel.hasSelectedColumns() || colSel.hasHiddenColumns()))
+ if (rslt && (colSel.hasSelectedColumns() || hidden.hasHiddenColumns()))
{
viewport.setColumnSelection(colSel);
+ viewport.getAlignment().setHiddenColumns(hidden);
}
return rslt;
return readAnnotationFile(al, null, file, sourceType);
}
- public boolean readAnnotationFile(AlignmentI al, ColumnSelection colSel,
+ public boolean readAnnotationFile(AlignmentI al, HiddenColumns hidden,
String file, DataSourceType sourceType)
{
BufferedReader in = null;
}
if (in != null)
{
- return parseAnnotationFrom(al, colSel, in);
+ return parseAnnotationFrom(al, hidden, in);
}
} catch (Exception ex)
private static String GRAPHLINE = "GRAPHLINE", COMBINE = "COMBINE";
- public boolean parseAnnotationFrom(AlignmentI al, ColumnSelection colSel,
+ public boolean parseAnnotationFrom(AlignmentI al, HiddenColumns hidden,
BufferedReader in) throws Exception
{
nlinesread = 0;
{
if (st.hasMoreTokens())
{
- if (colSel == null)
+ if (hidden == null)
{
- colSel = new ColumnSelection();
+ hidden = new HiddenColumns();
}
- parseHideCols(colSel, st.nextToken());
+ parseHideCols(hidden, st.nextToken());
}
modified = true;
continue;
}
if (sr != null)
{
- if (colSel == null)
+ if (hidden == null)
{
System.err
.println("Cannot process HIDE_INSERTIONS without an alignment view: Ignoring line: "
else
{
// consider deferring this till after the file has been parsed ?
- colSel.hideInsertionsFor(sr);
+ hidden.hideInsertionsFor(sr);
}
}
modified = true;
return modified;
}
- private void parseHideCols(ColumnSelection colSel, String nextToken)
+ private void parseHideCols(HiddenColumns hidden, String nextToken)
{
StringTokenizer inval = new StringTokenizer(nextToken, ",");
while (inval.hasMoreTokens())
from = to = Integer.parseInt(range);
if (from >= 0)
{
- colSel.hideColumns(from, to);
+ hidden.hideColumns(from, to);
}
}
else
}
if (from > 0 && to >= from)
{
- colSel.hideColumns(from, to);
+ hidden.hideColumns(from, to);
}
}
}
return printAnnotations(viewport.isShowAnnotation() ? viewport
.getAlignment().getAlignmentAnnotation() : null, viewport
.getAlignment().getGroups(), viewport.getAlignment()
- .getProperties(), viewport.getColumnSelection(),
+ .getProperties(), viewport.getAlignment().getHiddenColumns(),
viewport.getAlignment(), null);
}
return null;
}
- public static DataSourceType checkProtocol(String file)
+ /**
+ * Determines the protocol (i.e DataSourceType.{FILE|PASTE|URL}) for the input
+ * data
+ *
+ * @param data
+ * @return the protocol for the input data
+ */
+ public static DataSourceType checkProtocol(String data)
{
- DataSourceType protocol = DataSourceType.FILE;
- String ft = file.toLowerCase().trim();
+ DataSourceType protocol = DataSourceType.PASTE;
+ String ft = data.toLowerCase().trim();
if (ft.indexOf("http:") == 0 || ft.indexOf("https:") == 0
|| ft.indexOf("file:") == 0)
{
protocol = DataSourceType.URL;
}
+ else if (new File(data).exists())
+ {
+ protocol = DataSourceType.FILE;
+ }
return protocol;
}
return new FeaturesFile();
}
},
+ ScoreMatrix("Substitution matrix", "", false, false)
+ {
+ @Override
+ public AlignmentFileReaderI getReader(FileParse source)
+ throws IOException
+ {
+ return new ScoreMatrixFile(source);
+ }
+
+ @Override
+ public AlignmentFileWriterI getWriter(AlignmentI al)
+ {
+ return null;
+ }
+ },
PDB("PDB", "pdb,ent", true, false)
{
@Override
import jalview.bin.Cache;
import jalview.bin.Jalview;
import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
import jalview.schemes.ColourSchemeI;
import jalview.structure.StructureSelectionManager;
import jalview.util.MessageManager;
+import jalview.ws.utils.UrlDownloadClient;
+import java.io.File;
+import java.io.IOException;
import java.util.StringTokenizer;
import java.util.Vector;
// refer to it as.
return;
}
+ if (file != null
+ && file.indexOf(System.getProperty("java.io.tmpdir")) > -1)
+ {
+ // ignore files loaded from the system's temporary directory
+ return;
+ }
String type = protocol == DataSourceType.FILE ? "RECENT_FILE"
: "RECENT_URL";
// open a new source and read from it
FormatAdapter fa = new FormatAdapter();
- al = fa.readFile(file, protocol, format);
- source = fa.getAlignFile(); // keep reference for later if
- // necessary.
+ boolean downloadStructureFile = format.isStructureFile()
+ && protocol.equals(DataSourceType.URL);
+ if (downloadStructureFile)
+ {
+ String structExt = format.getExtensions().split(",")[0];
+ String urlLeafName = file.substring(file.lastIndexOf(System
+ .getProperty("file.separator")), file
+ .lastIndexOf("."));
+ String tempStructureFileStr = createNamedJvTempFile(
+ urlLeafName, structExt);
+ UrlDownloadClient.download(file, tempStructureFileStr);
+ al = fa.readFile(tempStructureFileStr, DataSourceType.FILE,
+ format);
+ source = fa.getAlignFile();
+ }
+ else
+ {
+ al = fa.readFile(file, protocol, format);
+ source = fa.getAlignFile(); // keep reference for later if
+ // necessary.
+ }
}
} catch (java.io.IOException ex)
{
if (source instanceof ComplexAlignFile)
{
- ColumnSelection colSel = ((ComplexAlignFile) source)
- .getColumnSelection();
+ HiddenColumns colSel = ((ComplexAlignFile) source)
+ .getHiddenColumns();
SequenceI[] hiddenSeqs = ((ComplexAlignFile) source)
.getHiddenSequences();
String colourSchemeName = ((ComplexAlignFile) source)
}
+ /**
+ * This method creates the file -
+ * {tmpdir}/jalview/{current_timestamp}/fileName.exetnsion using the supplied
+ * file name and extension
+ *
+ * @param fileName
+ * the name of the temp file to be created
+ * @param extension
+ * the extension of the temp file to be created
+ * @return
+ */
+ private static String createNamedJvTempFile(String fileName,
+ String extension) throws IOException
+ {
+ String seprator = System.getProperty("file.separator");
+ String jvTempDir = System.getProperty("java.io.tmpdir") + "jalview"
+ + seprator + System.currentTimeMillis();
+ File tempStructFile = new File(jvTempDir + seprator + fileName + "."
+ + extension);
+ tempStructFile.mkdirs();
+ return tempStructFile.toString();
+ }
+
/*
* (non-Javadoc)
*
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
}
public String formatSequences(FileFormatI format, AlignmentI alignment,
- String[] omitHidden, int[] exportRange, ColumnSelection colSel)
+ String[] omitHidden, int[] exportRange, HiddenColumns hidden)
{
return formatSequences(format, alignment, omitHidden, exportRange,
- getCacheSuffixDefault(format), colSel, null);
+ getCacheSuffixDefault(format), hidden, null);
}
/**
- * hack function to replace seuqences with visible sequence strings before
+ * hack function to replace sequences with visible sequence strings before
* generating a string of the alignment in the given format.
*
* @param format
*/
public String formatSequences(FileFormatI format, AlignmentI alignment,
String[] omitHidden, int[] exportRange, boolean suffix,
- ColumnSelection colSel)
+ HiddenColumns hidden)
{
return formatSequences(format, alignment, omitHidden, exportRange,
- suffix, colSel, null);
+ suffix, hidden, null);
}
public String formatSequences(FileFormatI format, AlignmentI alignment,
String[] omitHidden, int[] exportRange, boolean suffix,
- ColumnSelection colSel, SequenceGroup selgp)
+ HiddenColumns hidden, SequenceGroup selgp)
{
if (omitHidden != null)
{
AlignmentAnnotation na = new AlignmentAnnotation(ala[i]);
if (selgp != null)
{
- colSel.makeVisibleAnnotation(selgp.getStartRes(),
+ hidden.makeVisibleAnnotation(selgp.getStartRes(),
selgp.getEndRes(), na);
}
else
{
- colSel.makeVisibleAnnotation(na);
+ hidden.makeVisibleAnnotation(na);
}
alv.addAnnotation(na);
}
String bioJSON = new FormatAdapter(ap, exportData.getSettings())
.formatSequences(FileFormat.Json, exportData.getAlignment(),
exportData.getOmitHidden(), exportData
- .getStartEndPostions(), ap.getAlignViewport()
- .getColumnSelection());
+.getStartEndPostions(), ap.getAlignViewport()
+ .getAlignment().getHiddenColumns());
return bioJSON;
}
import jalview.api.ComplexAlignFile;
import jalview.api.FeatureSettingsModelI;
import jalview.api.FeaturesDisplayedI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceI;
import java.io.IOException;
private boolean showSeqFeatures;
- private ColumnSelection columnSelection;
+ private HiddenColumns hiddenColumns;
private SequenceI[] hiddenSequences;
this.showSeqFeatures = jsonFile.isShowSeqFeatures();
this.globalColourScheme = jsonFile.getGlobalColourScheme();
this.hiddenSequences = jsonFile.getHiddenSequences();
- this.columnSelection = jsonFile.getColumnSelection();
+ this.hiddenColumns = jsonFile.getHiddenColumns();
this.displayedFeatures = jsonFile.getDisplayedFeatures();
} catch (Exception e)
{
}
@Override
- public ColumnSelection getColumnSelection()
+ public HiddenColumns getHiddenColumns()
{
- return columnSelection;
+ return hiddenColumns;
}
- public void setColumnSelection(ColumnSelection columnSelection)
+ public void setHiddenColumns(HiddenColumns hidden)
{
- this.columnSelection = columnSelection;
+ this.hiddenColumns = hidden;
}
@Override
boolean lineswereskipped = false;
boolean isBinary = false; // true if length is non-zero and non-printable
// characters are encountered
+
try
{
if (!closeSource)
{
source.mark();
}
+ boolean aaIndexHeaderRead = false;
+
while ((data = source.nextLine()) != null)
{
bytesRead += data.length();
}
data = data.toUpperCase();
+ if (data.startsWith(ScoreMatrixFile.SCOREMATRIX))
+ {
+ reply = FileFormat.ScoreMatrix;
+ break;
+ }
+ if (data.startsWith("H ") && !aaIndexHeaderRead)
+ {
+ aaIndexHeaderRead = true;
+ }
+ if (data.startsWith("D ") && aaIndexHeaderRead)
+ {
+ reply = FileFormat.ScoreMatrix;
+ break;
+ }
if (data.startsWith("##GFF-VERSION"))
{
// GFF - possibly embedded in a Jalview features file!
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.Annotation;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.HiddenSequences;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.json.binding.biojson.v1.SequenceFeaturesPojo;
import jalview.json.binding.biojson.v1.SequenceGrpPojo;
import jalview.json.binding.biojson.v1.SequencePojo;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
+import jalview.schemes.ColourSchemeProperty;
import jalview.schemes.JalviewColourScheme;
import jalview.schemes.ResidueColourScheme;
import jalview.util.ColorUtils;
private FeatureRenderer fr;
- private List<int[]> hiddenColumns;
-
- private ColumnSelection columnSelection;
+ private HiddenColumns hiddenColumns;
private List<String> hiddenSeqRefs;
{
SequenceGrpPojo seqGrpPojo = new SequenceGrpPojo();
seqGrpPojo.setGroupName(seqGrp.getName());
- seqGrpPojo.setColourScheme(seqGrp.getColourScheme()
- .getSchemeName());
+ seqGrpPojo.setColourScheme(ColourSchemeProperty
+ .getColourName(seqGrp.getColourScheme()));
seqGrpPojo.setColourText(seqGrp.getColourText());
seqGrpPojo.setDescription(seqGrp.getDescription());
seqGrpPojo.setDisplayBoxes(seqGrp.getDisplayBoxes());
// hidden column business
if (getViewport().hasHiddenColumns())
{
- List<int[]> hiddenCols = getViewport().getColumnSelection()
- .getHiddenColumns();
+ List<int[]> hiddenCols = getViewport().getAlignment()
+ .getHiddenColumns()
+ .getHiddenRegions();
StringBuilder hiddenColsBuilder = new StringBuilder();
for (int[] range : hiddenCols)
{
return sequenceFeaturesPojo;
}
+ FeatureColourFinder finder = new FeatureColourFinder(fr);
+
for (SequenceI seq : sqs)
{
SequenceI dataSetSequence = seq.getDatasetSequence();
String.valueOf(seq.hashCode()));
String featureColour = (fr == null) ? null : jalview.util.Format
- .getHexString(fr.findFeatureColour(Color.white, seq,
+ .getHexString(finder.findFeatureColour(Color.white, seq,
seq.findIndex(sf.getBegin())));
jsonFeature.setXstart(seq.findIndex(sf.getBegin()) - 1);
jsonFeature.setXend(seq.findIndex(sf.getEnd()));
String hiddenCols = (String) jvSettingsJson.get("hiddenCols");
if (hiddenCols != null && !hiddenCols.isEmpty())
{
- columnSelection = new ColumnSelection();
+ hiddenColumns = new HiddenColumns();
String[] rangeStrings = hiddenCols.split(";");
for (String rangeString : rangeStrings)
{
String[] range = rangeString.split("-");
- columnSelection.hideColumns(Integer.valueOf(range[0]),
+ hiddenColumns.hideColumns(Integer.valueOf(range[0]),
Integer.valueOf(range[1]));
}
}
}
}
}
- globalColourScheme = viewport.getGlobalColourScheme().getSchemeName();
+ globalColourScheme = ColourSchemeProperty.getColourName(viewport
+ .getGlobalColourScheme());
setDisplayedFeatures(viewport.getFeaturesDisplayed());
showSeqFeatures = viewport.isShowSequenceFeatures();
return annotations;
}
- public List<int[]> getHiddenColumns()
- {
- return hiddenColumns;
- }
-
@Override
- public ColumnSelection getColumnSelection()
+ public HiddenColumns getHiddenColumns()
{
- return columnSelection;
+ return hiddenColumns;
}
- public void setColumnSelection(ColumnSelection columnSelection)
+ public void setHiddenColumns(HiddenColumns hidden)
{
- this.columnSelection = columnSelection;
+ this.hiddenColumns = hidden;
}
@Override
import java.awt.Color;
+import MCview.PDBChain;
+
public class PDBFeatureSettings extends FeatureSettingsAdapter
{
// TODO find one central place to define feature names
private static final String FEATURE_INSERTION = "INSERTION";
- private static final String FEATURE_RES_NUM = "RESNUM";
+ private static final String FEATURE_RES_NUM = PDBChain.RESNUM_FEATURE;
@Override
public boolean isFeatureDisplayed(String type)
--- /dev/null
+package jalview.io;
+
+import jalview.analysis.scoremodels.ScoreMatrix;
+import jalview.analysis.scoremodels.ScoreModels;
+import jalview.datamodel.SequenceI;
+
+import java.io.IOException;
+import java.util.StringTokenizer;
+
+/**
+ * A class that can parse a file containing a substitution matrix and register
+ * it for use in Jalview
+ * <p>
+ * Accepts 'NCBI' format (e.g.
+ * https://www.ncbi.nlm.nih.gov/Class/FieldGuide/BLOSUM62.txt), with the
+ * addition of a header line to provide a matrix name, e.g.
+ *
+ * <pre>
+ * ScoreMatrix BLOSUM62
+ * </pre>
+ *
+ * Also accepts 'AAindex' format (as described at
+ * http://www.genome.jp/aaindex/aaindex_help.html) with the minimum data
+ * required being
+ *
+ * <pre>
+ * H accession number (used as score matrix identifier in Jalview)
+ * D description (used for tooltip in Jalview)
+ * M rows = symbolList
+ * and the substitution scores
+ * </pre>
+ */
+public class ScoreMatrixFile extends AlignFile implements
+ AlignmentFileReaderI
+{
+ // first non-comment line identifier - also checked in IdentifyFile
+ public static final String SCOREMATRIX = "SCOREMATRIX";
+
+ private static final String DELIMITERS = " ,\t";
+
+ private static final String COMMENT_CHAR = "#";
+
+ private String matrixName;
+
+ /*
+ * aaindex format has scores for diagonal and below only
+ */
+ boolean isLowerDiagonalOnly;
+
+ /*
+ * ncbi format has symbols as first column on score rows
+ */
+ boolean hasGuideColumn;
+
+ /**
+ * Constructor
+ *
+ * @param source
+ * @throws IOException
+ */
+ public ScoreMatrixFile(FileParse source) throws IOException
+ {
+ super(false, source);
+ }
+
+ @Override
+ public String print(SequenceI[] sqs, boolean jvsuffix)
+ {
+ return null;
+ }
+
+ /**
+ * Parses the score matrix file, and if successful registers the matrix so it
+ * will be shown in Jalview menus. This method is not thread-safe (a separate
+ * instance of this class should be used by each thread).
+ */
+ @Override
+ public void parse() throws IOException
+ {
+ ScoreMatrix sm = parseMatrix();
+
+ ScoreModels.getInstance().registerScoreModel(sm);
+ }
+
+ /**
+ * Parses the score matrix file and constructs a ScoreMatrix object. If an
+ * error is found in parsing, it is thrown as FileFormatException. Any
+ * warnings are written to syserr.
+ *
+ * @return
+ * @throws IOException
+ */
+ public ScoreMatrix parseMatrix() throws IOException
+ {
+ ScoreMatrix sm = null;
+ int lineNo = 0;
+ String name = null;
+ char[] alphabet = null;
+ float[][] scores = null;
+ int size = 0;
+ int row = 0;
+ String err = null;
+ String data;
+ isLowerDiagonalOnly = false;
+
+ while ((data = nextLine()) != null)
+ {
+ lineNo++;
+ data = data.trim();
+ if (data.startsWith(COMMENT_CHAR) || data.length() == 0)
+ {
+ continue;
+ }
+ if (data.toUpperCase().startsWith(SCOREMATRIX))
+ {
+ /*
+ * Parse name from ScoreMatrix <name>
+ * we allow any delimiter after ScoreMatrix then take the rest of the line
+ */
+ if (name != null)
+ {
+ throw new FileFormatException(
+ "Error: 'ScoreMatrix' repeated in file at line "
+ + lineNo);
+ }
+ StringTokenizer nameLine = new StringTokenizer(data, DELIMITERS);
+ if (nameLine.countTokens() < 2)
+ {
+ err = "Format error: expected 'ScoreMatrix <name>', found '"
+ + data + "' at line " + lineNo;
+ throw new FileFormatException(err);
+ }
+ nameLine.nextToken(); // 'ScoreMatrix'
+ name = nameLine.nextToken(); // next field
+ name = data.substring(1).substring(data.substring(1).indexOf(name));
+ continue;
+ }
+ else if (data.startsWith("H ") && name == null)
+ {
+ /*
+ * AAindex identifier
+ */
+ return parseAAIndexFormat(lineNo, data);
+ }
+ else if (name == null)
+ {
+ err = "Format error: 'ScoreMatrix <name>' should be the first non-comment line";
+ throw new FileFormatException(err);
+ }
+
+ /*
+ * next non-comment line after ScoreMatrix should be the
+ * column header line with the alphabet of scored symbols
+ */
+ if (alphabet == null)
+ {
+ StringTokenizer columnHeadings = new StringTokenizer(data,
+ DELIMITERS);
+ size = columnHeadings.countTokens();
+ alphabet = new char[size];
+ int col = 0;
+ while (columnHeadings.hasMoreTokens())
+ {
+ alphabet[col++] = columnHeadings.nextToken().charAt(0);
+ }
+ scores = new float[size][];
+ continue;
+ }
+
+ /*
+ * too much information
+ */
+ if (row >= size)
+ {
+ err = "Unexpected extra input line in score model file: '" + data
+ + "'";
+ throw new FileFormatException(err);
+ }
+
+ parseValues(data, lineNo, scores, row, alphabet);
+ row++;
+ }
+
+ /*
+ * out of data - check we found enough
+ */
+ if (row < size)
+ {
+ err = String
+ .format("Expected %d rows of score data in score matrix but only found %d",
+ size, row);
+ throw new FileFormatException(err);
+ }
+
+ /*
+ * If we get here, then name, alphabet and scores have been parsed successfully
+ */
+ sm = new ScoreMatrix(name, alphabet, scores);
+ matrixName = name;
+
+ return sm;
+ }
+
+ /**
+ * Parse input as AAIndex format, starting from the header line with the
+ * accession id
+ *
+ * @param lineNo
+ * @param data
+ * @return
+ * @throws IOException
+ */
+ protected ScoreMatrix parseAAIndexFormat(int lineNo, String data)
+ throws IOException
+ {
+ String name = data.substring(2).trim();
+ String description = null;
+
+ float[][] scores = null;
+ char[] alphabet = null;
+ int row = 0;
+ int size = 0;
+
+ while ((data = nextLine()) != null)
+ {
+ lineNo++;
+ data = data.trim();
+ if (skipAAindexLine(data))
+ {
+ continue;
+ }
+ if (data.startsWith("D "))
+ {
+ description = data.substring(2).trim();
+ }
+ else if (data.startsWith("M "))
+ {
+ alphabet = parseAAindexRowsColumns(lineNo, data);
+ size = alphabet.length;
+ scores = new float[size][size];
+ }
+ else if (scores == null)
+ {
+ throw new FileFormatException(
+ "No alphabet specified in matrix file");
+ }
+ else if (row >= size)
+ {
+ throw new FileFormatException("Too many data rows in matrix file");
+ }
+ else
+ {
+ parseValues(data, lineNo, scores, row, alphabet);
+ row++;
+ }
+ }
+
+ ScoreMatrix sm = new ScoreMatrix(name, description, alphabet, scores);
+ matrixName = name;
+
+ return sm;
+ }
+
+ /**
+ * Parse one row of score values, delimited by whitespace or commas. The line
+ * may optionally include the symbol from which the scores are defined. Values
+ * may be present for all columns, or only up to the diagonal (in which case
+ * upper diagonal values are set symmetrically).
+ *
+ * @param data
+ * the line to be parsed
+ * @param lineNo
+ * @param scores
+ * the score matrix to add data to
+ * @param row
+ * the row number / alphabet index position
+ * @param alphabet
+ * @return
+ * @throws exception
+ * if invalid, or too few, or too many values
+ */
+ protected void parseValues(String data, int lineNo, float[][] scores,
+ int row, char[] alphabet) throws FileFormatException
+ {
+ String err;
+ int size = alphabet.length;
+ StringTokenizer scoreLine = new StringTokenizer(data, DELIMITERS);
+
+ int tokenCount = scoreLine.countTokens();
+
+ /*
+ * inspect first row to see if it includes the symbol in the first column,
+ * and to see if it is lower diagonal values only (i.e. just one score)
+ */
+ if (row == 0)
+ {
+ if (data.startsWith(String.valueOf(alphabet[0])))
+ {
+ hasGuideColumn = true;
+ }
+ if (tokenCount == (hasGuideColumn ? 2 : 1))
+ {
+ isLowerDiagonalOnly = true;
+ }
+ }
+
+ if (hasGuideColumn)
+ {
+ /*
+ * check 'guide' symbol is the row'th letter of the alphabet
+ */
+ String symbol = scoreLine.nextToken();
+ if (symbol.length() > 1 || symbol.charAt(0) != alphabet[row])
+ {
+ err = String
+ .format("Error parsing score matrix at line %d, expected '%s' but found '%s'",
+ lineNo, alphabet[row], symbol);
+ throw new FileFormatException(err);
+ }
+ tokenCount = scoreLine.countTokens(); // excluding guide symbol
+ }
+
+ /*
+ * check the right number of values (lower diagonal or full format)
+ */
+ if (isLowerDiagonalOnly && tokenCount != row + 1)
+ {
+ err = String.format(
+ "Expected %d scores at line %d: '%s' but found %d", row + 1,
+ lineNo, data, tokenCount);
+ throw new FileFormatException(err);
+ }
+
+ if (!isLowerDiagonalOnly && tokenCount != size)
+ {
+ err = String.format(
+ "Expected %d scores at line %d: '%s' but found %d", size,
+ lineNo, data, scoreLine.countTokens());
+ throw new FileFormatException(err);
+ }
+
+ /*
+ * parse and set the values, setting the symmetrical value
+ * as well if lower diagonal format data
+ */
+ scores[row] = new float[size];
+ int col = 0;
+ String value = null;
+ while (scoreLine.hasMoreTokens())
+ {
+ try
+ {
+ value = scoreLine.nextToken();
+ scores[row][col] = Float.valueOf(value);
+ if (isLowerDiagonalOnly)
+ {
+ scores[col][row] = scores[row][col];
+ }
+ col++;
+ } catch (NumberFormatException e)
+ {
+ err = String.format(
+ "Invalid score value '%s' at line %d column %d", value,
+ lineNo, col);
+ throw new FileFormatException(err);
+ }
+ }
+ }
+
+ /**
+ * Parse the line in an aaindex file that looks like
+ *
+ * <pre>
+ * M rows = ARNDCQEGHILKMFPSTWYV, cols = ARNDCQEGHILKMFPSTWYV
+ * </pre>
+ *
+ * rejecting it if rows and cols do not match. Returns the string of
+ * characters in the row/cols alphabet.
+ *
+ * @param lineNo
+ * @param data
+ * @return
+ * @throws FileFormatException
+ */
+ protected char[] parseAAindexRowsColumns(int lineNo, String data)
+ throws FileFormatException
+ {
+ String err = "Unexpected aaIndex score matrix data at line " + lineNo
+ + ": " + data;
+
+ try
+ {
+ String[] toks = data.split(",");
+ String rowsAlphabet = toks[0].split("=")[1].trim();
+ String colsAlphabet = toks[1].split("=")[1].trim();
+ if (!rowsAlphabet.equals(colsAlphabet))
+ {
+ throw new FileFormatException("rows != cols");
+ }
+ return rowsAlphabet.toCharArray();
+ } catch (Throwable t)
+ {
+ throw new FileFormatException(err + " " + t.getMessage());
+ }
+ }
+
+ /**
+ * Answers true if line is one we are not interested in from AAindex format
+ * file
+ *
+ * @param data
+ * @return
+ */
+ protected boolean skipAAindexLine(String data)
+ {
+ if (data.startsWith(COMMENT_CHAR) || data.length() == 0)
+ {
+ return true;
+ }
+ if (data.startsWith("*") || data.startsWith("R ")
+ || data.startsWith("A ") || data.startsWith("T ")
+ || data.startsWith("J ") || data.startsWith("//"))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ public String getMatrixName()
+ {
+ return matrixName;
+ }
+}
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
import jalview.schemes.ResidueProperties;
+import jalview.util.Comparison;
import jalview.util.Format;
import jalview.util.MessageManager;
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);
}
{
String convert1, convert2 = null;
- convert1 = OPEN_PAREN.replaceAll(annots);
- convert2 = CLOSE_PAREN.replaceAll(convert1);
- annots = convert2;
+ // convert1 = OPEN_PAREN.replaceAll(annots);
+ // convert2 = CLOSE_PAREN.replaceAll(convert1);
+ // annots = convert2;
String type = label;
if (label.contains("_cons"))
type = (label.indexOf("_cons") == label.length() - 5) ? label
.substring(0, label.length() - 5) : label;
}
- boolean ss = false;
+ boolean ss = false, posterior = false;
type = id2type(type);
- if (type.equals("secondary structure"))
+ if (type.equalsIgnoreCase("secondary structure"))
{
ss = true;
}
+ if (type.equalsIgnoreCase("posterior probability"))
+ {
+ posterior = true;
+ }
// decide on secondary structure or not.
Annotation[] els = new Annotation[annots.length()];
for (int i = 0; i < annots.length(); i++)
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;
}
+ }
}
}
+ if (posterior && !ann.isWhitespace()
+ && !Comparison.isGap(pos.charAt(0)))
+ {
+ float val = 0;
+ // symbol encodes values - 0..*==0..10
+ if (pos.charAt(0) == '*')
+ {
+ val = 10;
+ }
+ else
+ {
+ val = pos.charAt(0) - '0';
+ if (val > 9)
+ {
+ val = 10;
+ }
+ }
+ ann.value = val;
+ }
els[i] = ann;
}
// 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();
+
+ if (isrna)
+ {
+ // hardwire to secondary structure if there is RNA secondary
+ // structure on the annotation
+ key = "SS";
+ }
+ if (key == null)
{
- if (ds.getSequenceFeatures() != null)
- {
- feature = ds.getSequenceFeatures()[0].type;
- }
- // ?bug - feature may still have previous loop value
- String key = type2id(feature);
- 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;
- boolean isrna = alAnot[j].isValidStruc();
- 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
{
if (typeIds == null)
{
typeIds = new Hashtable();
- typeIds.put("SS", "secondary structure");
- typeIds.put("SA", "surface accessibility");
+ typeIds.put("SS", "Secondary Structure");
+ typeIds.put("SA", "Surface Accessibility");
typeIds.put("TM", "transmembrane");
- typeIds.put("PP", "posterior probability");
+ typeIds.put("PP", "Posterior Probability");
typeIds.put("LI", "ligand binding");
typeIds.put("AS", "active site");
typeIds.put("IN", "intron");
typeIds.put("DE", "description");
typeIds.put("DR", "reference");
typeIds.put("LO", "look");
- typeIds.put("RF", "reference positions");
+ typeIds.put("RF", "Reference Positions");
}
}
while (e.hasMoreElements())
{
Object ll = e.nextElement();
- if (typeIds.get(ll).toString().equals(type))
+ if (typeIds.get(ll).toString().equalsIgnoreCase(type))
{
key = (String) ll;
break;
* make a friendly ID string.
*
* @param dataName
- * @return truncated dataName to after last '/'
+ * @return truncated dataName to after last '/' and pruned .extension if
+ * present
*/
protected String safeName(String dataName)
{
{
dataName = dataName.substring(p + 1);
}
+ if(dataName.indexOf(".") > -1){
+ dataName = dataName.substring(0, dataName.lastIndexOf("."));
+ }
return dataName;
}
TreePanel tp = null;
if (vstree.isValidTree())
{
- tp = alignFrame.ShowNewickTree(vstree.getNewickTree(),
+ tp = alignFrame.showNewickTree(vstree.getNewickTree(),
vstree.getTitle(), vstree.getInputData(), 600,
500, t * 20 + 50, t * 20 + 50);
--- /dev/null
+package jalview.io.cache;
+
+
+import jalview.bin.Cache;
+
+import java.util.Hashtable;
+import java.util.LinkedHashSet;
+
+/**
+ * A singleton class used for querying and persisting cache items.
+ *
+ * @author tcnofoegbu
+ *
+ */
+public class AppCache
+{
+ public static final String DEFAULT_LIMIT = "99";
+
+ public static final String CACHE_DELIMITER = ";";
+
+ private static AppCache instance = null;
+
+ private static final String DEFAULT_LIMIT_KEY = ".DEFAULT_LIMIT";
+
+
+
+ private Hashtable<String, LinkedHashSet<String>> cacheItems;
+
+ private AppCache()
+ {
+ cacheItems = new Hashtable<String, LinkedHashSet<String>>();
+ }
+
+ /**
+ * Method to obtain all the cache items for a given cache key
+ *
+ * @param cacheKey
+ * @return
+ */
+ public LinkedHashSet<String> getAllCachedItemsFor(String cacheKey)
+ {
+ LinkedHashSet<String> foundCache = cacheItems.get(cacheKey);
+ if (foundCache == null)
+ {
+ foundCache = new LinkedHashSet<String>();
+ cacheItems.put(cacheKey, foundCache);
+ }
+ return foundCache;
+ }
+
+
+ /**
+ * Returns a singleton instance of AppCache
+ *
+ * @return
+ */
+ public static AppCache getInstance()
+ {
+ if (instance == null)
+ {
+ instance = new AppCache();
+ }
+ return instance;
+ }
+
+
+
+ /**
+ * Method for persisting cache items for a given cache key
+ *
+ * @param cacheKey
+ */
+ public void persistCache(String cacheKey)
+ {
+ LinkedHashSet<String> foundCacheItems = getAllCachedItemsFor(cacheKey);
+ StringBuffer delimitedCacheBuf = new StringBuffer();
+ for (String cacheItem : foundCacheItems)
+ {
+ delimitedCacheBuf.append(CACHE_DELIMITER).append(cacheItem);
+ }
+ if (delimitedCacheBuf.length() > 0)
+ {
+ delimitedCacheBuf.deleteCharAt(0);
+ }
+ String delimitedCacheString = delimitedCacheBuf.toString();
+
+ Cache.setProperty(cacheKey, delimitedCacheString);
+ }
+
+ /**
+ * Method for deleting cached items for a given cache key
+ *
+ * @param cacheKey
+ * the cache key
+ */
+ public void deleteCacheItems(String cacheKey)
+ {
+ cacheItems.put(cacheKey, new LinkedHashSet<String>());
+ persistCache(cacheKey);
+ }
+
+ /**
+ * Method for obtaining the preset maximum cache limit for a given cache key
+ *
+ * @param cacheKey
+ * the cache key
+ * @return the max number of items that could be cached
+ */
+ public String getCacheLimit(String cacheKey)
+ {
+ String uniqueKey = cacheKey + DEFAULT_LIMIT_KEY;
+ return Cache.getDefault(uniqueKey, DEFAULT_LIMIT);
+ }
+
+ /**
+ * Method for updating the preset maximum cache limit for a given cache key
+ *
+ * @param cacheKey
+ * the cache key
+ * @param newLimit
+ * the max number of items that could be cached for the given cache
+ * key
+ * @return
+ */
+ public int updateCacheLimit(String cacheKey, int newUserLimit)
+ {
+ String newLimit = String.valueOf(newUserLimit);
+ String uniqueKey = cacheKey + DEFAULT_LIMIT_KEY;
+ String formerLimit = getCacheLimit(cacheKey);
+ if (newLimit != null && !newLimit.isEmpty()
+ && !formerLimit.equals(newLimit))
+ {
+ Cache.setProperty(uniqueKey, newLimit);
+ formerLimit = newLimit;
+ }
+ return Integer.valueOf(formerLimit);
+ }
+
+ /**
+ * Method for inserting cache items for given cache key into the cache data
+ * structure
+ *
+ * @param cacheKey
+ * the cache key
+ * @param cacheItems
+ * the items to add to the cache
+ */
+ public void putCache(String cacheKey, LinkedHashSet<String> newCacheItems)
+ {
+ cacheItems.put(cacheKey, newCacheItems);
+ }
+
+}
--- /dev/null
+package jalview.io.cache;
+
+import jalview.bin.Cache;
+import jalview.util.MessageManager;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.BorderFactory;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.PlainDocument;
+
+public class JvCacheableInputBox<E> extends JComboBox<String>
+{
+
+ private static final long serialVersionUID = 5774610435079326695L;
+
+ private static final int INPUT_LIMIT = 2;
+
+ private static final int LEFT_BOARDER_WIDTH = 16;
+
+ private String cacheKey;
+
+ private AppCache appCache;
+
+ private JPanel pnlDefaultCache = new JPanel();
+
+ private JLabel lblDefaultCacheSize = new JLabel();
+
+ private JTextField txtDefaultCacheSize = new JTextField();
+
+ private JPopupMenu popup = new JPopupMenu();
+
+ private JMenuItem menuItemClearCache = new JMenuItem();
+
+ public JvCacheableInputBox(String newCacheKey)
+ {
+ super();
+ this.cacheKey = newCacheKey;
+ setEditable(true);
+ setPrototypeDisplayValue("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+ appCache = AppCache.getInstance();
+ initCachePopupMenu();
+ initCache(newCacheKey);
+ updateCache();
+ }
+
+ /**
+ * Method for initialising cache items for a given cache key and populating
+ * the in-memory cache with persisted cache items
+ *
+ * @param cacheKey
+ */
+ private void initCache(String cacheKey)
+ {
+ // obtain persisted cache items from properties file as a delimited string
+ String delimitedCacheStr = Cache.getProperty(cacheKey);
+ if (delimitedCacheStr == null || delimitedCacheStr.isEmpty())
+ {
+ return;
+ }
+ // convert delimited cache items to a list of strings
+ List<String> persistedCacheItems = Arrays.asList(delimitedCacheStr
+ .split(AppCache.CACHE_DELIMITER));
+
+ LinkedHashSet<String> foundCacheItems = appCache
+ .getAllCachedItemsFor(cacheKey);
+ if (foundCacheItems == null)
+ {
+ foundCacheItems = new LinkedHashSet<String>();
+ }
+ // populate memory cache
+ for (String cacheItem : persistedCacheItems)
+ {
+ foundCacheItems.add(cacheItem);
+ }
+ appCache.putCache(cacheKey, foundCacheItems);
+ }
+
+ /**
+ * Initialise this cache's pop-up menu
+ */
+ private void initCachePopupMenu()
+ {
+ pnlDefaultCache.setBackground(Color.WHITE);
+ // pad panel so as to align with other menu items
+ pnlDefaultCache.setBorder(BorderFactory.createEmptyBorder(0,
+ LEFT_BOARDER_WIDTH, 0, 0));
+ txtDefaultCacheSize.setPreferredSize(new Dimension(45, 20));
+ txtDefaultCacheSize.setFont(new java.awt.Font("Verdana", 0, 12));
+ lblDefaultCacheSize.setText(MessageManager
+ .getString("label.default_cache_size"));
+ lblDefaultCacheSize.setFont(new java.awt.Font("Verdana", 0, 12));
+ // Force input to accept only Integer entries up to length - INPUT_LIMIT
+ txtDefaultCacheSize.setDocument(new PlainDocument()
+ {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void insertString(int offs, String str, AttributeSet a)
+ throws BadLocationException
+ {
+ if (getLength() + str.length() <= INPUT_LIMIT && isInteger(str))
+ {
+ super.insertString(offs, str, a);
+ }
+ }
+ });
+ txtDefaultCacheSize.addKeyListener(new java.awt.event.KeyAdapter()
+ {
+ @Override
+ public void keyPressed(KeyEvent e)
+ {
+ if (e.getKeyCode() == KeyEvent.VK_ENTER)
+ {
+ e.consume();
+ updateCache();
+ closePopup();
+ }
+ }
+ });
+
+ txtDefaultCacheSize.setText(appCache.getCacheLimit(cacheKey));
+ pnlDefaultCache.add(lblDefaultCacheSize);
+ menuItemClearCache.setFont(new java.awt.Font("Verdana", 0, 12));
+ pnlDefaultCache.add(txtDefaultCacheSize);
+ menuItemClearCache.setText(MessageManager
+ .getString("action.clear_cached_items"));
+ menuItemClearCache.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ // System.out.println(">>>>> Clear cache items");
+ setSelectedItem("");
+ appCache.deleteCacheItems(cacheKey);
+ updateCache();
+ }
+ });
+
+ popup.insert(pnlDefaultCache, 0);
+ popup.add(menuItemClearCache);
+ setComponentPopupMenu(popup);
+ add(popup);
+ }
+
+ private void closePopup()
+ {
+ popup.setVisible(false);
+ popup.transferFocus();
+ }
+
+ /**
+ * Answers true if input text is an integer
+ *
+ * @param text
+ * @return
+ */
+ static boolean isInteger(String text)
+ {
+ try
+ {
+ Integer.parseInt(text);
+ return true;
+ } catch (NumberFormatException e)
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Method called to update the cache with the last user input
+ */
+ public void updateCache()
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ int userLimit = txtDefaultCacheSize.getText().trim().isEmpty() ? Integer
+ .valueOf(AppCache.DEFAULT_LIMIT) : Integer
+ .valueOf(txtDefaultCacheSize.getText());
+ int cacheLimit = appCache.updateCacheLimit(cacheKey, userLimit);
+ String userInput = getUserInput();
+ if (userInput != null && !userInput.isEmpty())
+ {
+ LinkedHashSet<String> foundCache = appCache
+ .getAllCachedItemsFor(cacheKey);
+ // remove old cache item so as to place current input at the top of
+ // the result
+ foundCache.remove(userInput);
+ foundCache.add(userInput);
+ appCache.putCache(cacheKey, foundCache);
+ }
+
+ String lastSearch = userInput;
+ if (getItemCount() > 0)
+ {
+ removeAllItems();
+ }
+ Set<String> cacheItems = appCache.getAllCachedItemsFor(cacheKey);
+ List<String> reversedCacheItems = new ArrayList<String>();
+ reversedCacheItems.addAll(cacheItems);
+ cacheItems = null;
+ Collections.reverse(reversedCacheItems);
+ if (lastSearch.isEmpty())
+ {
+ addItem("");
+ }
+
+ if (reversedCacheItems != null && !reversedCacheItems.isEmpty())
+ {
+ LinkedHashSet<String> foundCache = appCache
+ .getAllCachedItemsFor(cacheKey);
+ boolean prune = reversedCacheItems.size() > cacheLimit;
+ int count = 1;
+ boolean limitExceeded = false;
+ for (String cacheItem : reversedCacheItems)
+ {
+ limitExceeded = (count++ > cacheLimit);
+ if (prune)
+ {
+ if (limitExceeded)
+ {
+ foundCache.remove(cacheItem);
+ }
+ else
+ {
+ addItem(cacheItem);
+ }
+ }
+ else
+ {
+ addItem(cacheItem);
+ }
+ }
+ appCache.putCache(cacheKey, foundCache);
+ }
+ setSelectedItem(lastSearch.isEmpty() ? "" : lastSearch);
+ }
+ });
+ }
+
+
+ /**
+ * This method should be called to persist the in-memory cache when this
+ * components parent frame is closed / exited
+ */
+ public void persistCache()
+ {
+ appCache.persistCache(cacheKey);
+ int userLimit = txtDefaultCacheSize.getText().trim().isEmpty() ? Integer
+ .valueOf(AppCache.DEFAULT_LIMIT) : Integer
+ .valueOf(txtDefaultCacheSize.getText());
+ appCache.updateCacheLimit(cacheKey, userLimit);
+ }
+
+ /**
+ * Method to obtain input text from the cache box
+ *
+ * @return
+ */
+ public String getUserInput()
+ {
+ return getEditor().getItem() == null ? "" : getEditor().getItem()
+ .toString().trim();
+ }
+
+}
*/
package jalview.io.packed;
+import jalview.analysis.TreeModel;
import jalview.api.FeatureColourI;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.SequenceI;
{
// the following works because all trees are already had node/SequenceI
// associations created.
- jalview.analysis.NJTree njt = new jalview.analysis.NJTree(
- al.getSequencesArray(), nf);
+ TreeModel njt = new TreeModel(al.getSequencesArray(), null, nf);
// this just updates the displayed leaf name on the tree according to
// the SequenceIs.
njt.renameAssociatedNodes();
*/
package jalview.io.vamsas;
-import jalview.analysis.NJTree;
+import jalview.analysis.TreeBuilder;
+import jalview.analysis.TreeModel;
import jalview.bin.Cache;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentView;
prov.getEntry(0).setUser(provEntry.getUser());
prov.getEntry(0).setApp(provEntry.getApp());
prov.getEntry(0).setDate(provEntry.getDate());
- if (tp.getTree().hasOriginalSequenceData())
+
+ AlignmentView originalData = tp.getTree().getOriginalData();
+ if (originalData != null)
{
Input vInput = new Input();
// LATER: check to see if tree input data is contained in this alignment -
// or just correctly resolve the tree's seqData to the correct alignment
// in
// the document.
- Vector alsqrefs = getjv2vObjs(findAlignmentSequences(jal,
- tp.getTree().seqData.getSequences()));
+ Vector alsqrefs = getjv2vObjs(findAlignmentSequences(jal, tp
+ .getTree().getOriginalData().getSequences()));
Object[] alsqs = new Object[alsqrefs.size()];
alsqrefs.copyInto(alsqs);
vInput.setObjRef(alsqs);
prov.getEntry(0).addParam(new Param());
prov.getEntry(0).getParam(0).setName("treeType");
prov.getEntry(0).getParam(0).setType("utf8");
- prov.getEntry(0).getParam(0).setContent("NJ"); // TODO: type of tree is a
- // general parameter
- int ranges[] = tp.getTree().seqData.getVisibleContigs();
+ prov.getEntry(0).getParam(0)
+ .setContent(TreeBuilder.NEIGHBOUR_JOINING);
+ // TODO: type of tree is a general parameter
+ int ranges[] = originalData.getVisibleContigs();
// VisibleContigs are with respect to alignment coordinates. Still need
// offsets
- int start = tp.getTree().seqData.getAlignmentOrigin();
+ int start = tp.getTree().getOriginalData().getAlignmentOrigin();
for (int r = 0; r < ranges.length; r += 2)
{
Seg visSeg = new Seg();
/**
* construct treenode mappings for mapped sequences
*
- * @param ntree
+ * @param treeModel
* @param newick
* @return
*/
- public Treenode[] makeTreeNodes(NJTree ntree, Newick newick)
+ public Treenode[] makeTreeNodes(TreeModel treeModel, Newick newick)
{
- Vector<SequenceNode> leaves = ntree.findLeaves(ntree.getTopNode());
+ Vector<SequenceNode> leaves = treeModel.findLeaves(treeModel
+ .getTopNode());
Vector tnv = new Vector();
Enumeration l = leaves.elements();
Hashtable nodespecs = new Hashtable();
bindjvvobj(tp, tree);
tree.setTitle(tp.getTitle());
Newick newick = new Newick();
- newick.setContent(tp.getTree().toString());
+ newick.setContent(tp.getTree().print());
newick.setTitle(tp.getTitle());
tree.addNewick(newick);
tree.setProvenance(makeTreeProvenance(jal, tp));
import jalview.appletgui.AlignFrame;
import jalview.bin.JalviewLite;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceGroup;
import jalview.structure.SelectionSource;
@Override
public void selection(SequenceGroup seqsel, ColumnSelection colsel,
- SelectionSource source)
+ HiddenColumns hidden, SelectionSource source)
{
// System.err.println("Testing selection event relay to jsfunction:"+_listener);
try
}
@Override
- public String[] getPdbFile()
+ public String[] getStructureFiles()
{
return modelSet;
}
ArrayList<String[]> ccomands = new ArrayList<String[]>();
ArrayList<String> pdbfn = new ArrayList<String>();
StructureMappingcommandSet[] colcommands = JmolCommands
- .getColourBySequenceCommand(ssm, modelSet, sequence, sr, fr,
- ((AlignmentViewPanel) source).getAlignment());
+ .getColourBySequenceCommand(ssm, modelSet, sequence, sr,
+ (AlignmentViewPanel) source);
if (colcommands == null)
{
return;
return _listenerfn;
}
+ @Override
public void finalize() throws Throwable
{
jvlite = null;
protected JMenu colourMenu = new JMenu();
- protected JRadioButtonMenuItem textColour;
+ protected JMenuItem textColour;
protected JCheckBoxMenuItem conservationMenuItem;
protected JMenu sort = new JMenu();
- protected JMenu calculateTree = new JMenu();
+ protected JMenuItem calculateTree = new JMenuItem();
protected JCheckBoxMenuItem padGapsMenuitem = new JCheckBoxMenuItem();
pairwiseAlignmentMenuItem_actionPerformed(e);
}
});
- JMenuItem PCAMenuItem = new JMenuItem(
- MessageManager.getString("label.principal_component_analysis"));
- PCAMenuItem.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- PCAMenuItem_actionPerformed(e);
- }
- });
- JMenuItem averageDistanceTreeMenuItem = new JMenuItem(
- MessageManager.getString("label.average_distance_identity"));
- averageDistanceTreeMenuItem.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- averageDistanceTreeMenuItem_actionPerformed(e);
- }
- });
- JMenuItem neighbourTreeMenuItem = new JMenuItem(
- MessageManager.getString("label.neighbour_joining_identity"));
- neighbourTreeMenuItem.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- neighbourTreeMenuItem_actionPerformed(e);
- }
- });
this.getContentPane().setLayout(new BorderLayout());
alignFrameMenuBar.setFont(new java.awt.Font("Verdana", 0, 11));
outputTextboxMenu.setText(MessageManager
.getString("label.out_to_textbox"));
-
- JMenuItem avDistanceTreeBlosumMenuItem = new JMenuItem(
- MessageManager.getString("label.average_distance_blosum62"));
- avDistanceTreeBlosumMenuItem.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- avTreeBlosumMenuItem_actionPerformed(e);
- }
- });
- JMenuItem njTreeBlosumMenuItem = new JMenuItem(
- MessageManager.getString("label.neighbour_blosum62"));
- njTreeBlosumMenuItem.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- njTreeBlosumMenuItem_actionPerformed(e);
- }
- });
annotationPanelMenuItem.setActionCommand("");
annotationPanelMenuItem.setText(MessageManager
.getString("label.show_annotations"));
});
JMenuItem createGroup = new JMenuItem(
- MessageManager.getString("action.create_groups"));
+ MessageManager.getString("action.create_group"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G, Toolkit
.getDefaultToolkit().getMenuShortcutKeyMask(), false);
al = new ActionListener()
@Override
public void menuSelected(MenuEvent e)
{
- buildTreeMenu();
+ buildTreeSortMenu();
}
@Override
});
sortByAnnotScore.setVisible(false);
- calculateTree
- .setText(MessageManager.getString("action.calculate_tree"));
+ calculateTree.setText(MessageManager
+ .getString("action.calculate_tree_pca"));
padGapsMenuitem.setText(MessageManager.getString("label.pad_gaps"));
padGapsMenuitem.setState(jalview.bin.Cache
formatMenu.setText(MessageManager.getString("action.format"));
JMenu selectMenu = new JMenu(MessageManager.getString("action.select"));
+
idRightAlign.setText(MessageManager
.getString("label.right_align_sequence_id"));
idRightAlign.addActionListener(new ActionListener()
calculateMenu.add(calculateTree);
calculateMenu.addSeparator();
calculateMenu.add(pairwiseAlignmentMenuItem);
- calculateMenu.add(PCAMenuItem);
calculateMenu.addSeparator();
calculateMenu.add(showTranslation);
calculateMenu.add(showReverse);
}
});
- textColour = new JRadioButtonMenuItem(
- MessageManager.getString("action.set_text_colour"));
+ textColour = new JMenuItem(
+ MessageManager.getString("label.text_colour"));
textColour.addActionListener(new ActionListener()
{
@Override
{
}
- protected void PCAMenuItem_actionPerformed(ActionEvent e)
- {
- }
-
- protected void averageDistanceTreeMenuItem_actionPerformed(ActionEvent e)
- {
- }
-
protected void neighbourTreeMenuItem_actionPerformed(ActionEvent e)
{
}
- protected void njTreeBlosumMenuItem_actionPerformed(ActionEvent e)
- {
- }
-
- protected void avTreeBlosumMenuItem_actionPerformed(ActionEvent e)
- {
- }
-
protected void conservationMenuItem_actionPerformed(boolean selected)
{
}
}
- public void buildTreeMenu()
+ public void buildTreeSortMenu()
{
}
import jalview.api.AlignmentViewPanel;
import jalview.io.FileFormatException;
import jalview.util.MessageManager;
+import jalview.util.Platform;
import java.awt.FlowLayout;
import java.awt.Toolkit;
JMenuItem garbageCollect = new JMenuItem();
+ protected JMenuItem groovyShell;
+
+ protected JCheckBoxMenuItem experimentalFeatures;
+
protected JCheckBoxMenuItem showConsole = new JCheckBoxMenuItem();
protected JCheckBoxMenuItem showNews = new JCheckBoxMenuItem();
e.printStackTrace();
}
- if (!new jalview.util.Platform().isAMac())
+ if (!Platform.isAMac())
{
FileMenu.setMnemonic('F');
inputLocalFileMenuItem.setMnemonic('L');
showNews_actionPerformed(e);
}
});
+ groovyShell = new JMenuItem();
+ groovyShell.setText(MessageManager.getString("label.groovy_console"));
+ groovyShell.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ groovyShell_actionPerformed();
+ }
+ });
+ experimentalFeatures = new JCheckBoxMenuItem();
+ experimentalFeatures.setText(MessageManager
+ .getString("label.show_experimental"));
+ experimentalFeatures.setToolTipText(MessageManager
+ .getString("label.show_experimental_tip"));
+ experimentalFeatures.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ showExperimental_actionPerformed(experimentalFeatures.isSelected());
+ }
+ });
+
snapShotWindow.setText(MessageManager.getString("label.take_snapshot"));
snapShotWindow.addActionListener(new ActionListener()
{
toolsMenu.add(showConsole);
toolsMenu.add(showNews);
toolsMenu.add(garbageCollect);
+ toolsMenu.add(groovyShell);
+ toolsMenu.add(experimentalFeatures);
// toolsMenu.add(snapShotWindow);
inputMenu.add(inputLocalFileMenuItem);
inputMenu.add(inputURLMenuItem);
// inputMenu.add(vamsasLoad);
}
+ protected void showExperimental_actionPerformed(boolean selected)
+ {
+ }
+
+ protected void groovyShell_actionPerformed()
+ {
+ }
+
protected void snapShotWindow_actionPerformed(ActionEvent e)
{
// TODO Auto-generated method stub
import jalview.io.DataSourceType;
import jalview.io.FileFormat;
import jalview.io.FormatAdapter;
+import jalview.io.cache.JvCacheableInputBox;
import jalview.util.MessageManager;
import java.awt.BorderLayout;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
+import javax.swing.text.JTextComponent;
public class GFinder extends JPanel
{
GridLayout gridLayout1 = new GridLayout();
- protected JButton createNewGroup = new JButton();
+ protected JButton createFeatures = new JButton();
- JScrollPane jScrollPane1 = new JScrollPane();
-
- protected JTextArea textfield = new JTextArea();
+ protected JvCacheableInputBox<String> searchBox = new JvCacheableInputBox<String>(getCacheKey());
BorderLayout mainBorderLayout = new BorderLayout();
GridLayout optionsGridLayout = new GridLayout();
+ private static final String FINDER_CACHE_KEY = "CACHE.FINDER";
+
public GFinder()
{
try
gridLayout1.setHgap(0);
gridLayout1.setRows(3);
gridLayout1.setVgap(2);
- createNewGroup.setEnabled(false);
- createNewGroup.setFont(new java.awt.Font("Verdana", 0, 12));
- createNewGroup.setMargin(new Insets(0, 0, 0, 0));
- createNewGroup.setText(MessageManager.getString("label.new_feature"));
- createNewGroup.addActionListener(new java.awt.event.ActionListener()
+ createFeatures.setEnabled(false);
+ createFeatures.setFont(new java.awt.Font("Verdana", 0, 12));
+ createFeatures.setMargin(new Insets(0, 0, 0, 0));
+ createFeatures.setText(MessageManager.getString("label.new_feature"));
+ createFeatures.addActionListener(new java.awt.event.ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
- createNewGroup_actionPerformed(e);
+ createFeatures_actionPerformed();
}
});
- textfield.setFont(new java.awt.Font("Verdana", Font.PLAIN, 12));
- textfield.setText("");
- textfield.setLineWrap(true);
- textfield.addCaretListener(new CaretListener()
+ searchBox.setFont(new java.awt.Font("Verdana", Font.PLAIN, 12));
+ ((JTextComponent) searchBox.getEditor().getEditorComponent())
+ .addCaretListener(new CaretListener()
{
@Override
public void caretUpdate(CaretEvent e)
textfield_caretUpdate(e);
}
});
- textfield.addKeyListener(new java.awt.event.KeyAdapter()
- {
- @Override
- public void keyPressed(KeyEvent e)
- {
- textfield_keyPressed(e);
- }
- });
-
+ searchBox.getEditor().getEditorComponent()
+ .addKeyListener(new java.awt.event.KeyAdapter()
+ {
+ @Override
+ public void keyPressed(KeyEvent e)
+ {
+ textfield_keyPressed(e);
+ }
+ });
mainBorderLayout.setHgap(5);
mainBorderLayout.setVgap(5);
jPanel4.setLayout(borderLayout2);
actionsPanel.add(findNext, null);
actionsPanel.add(findAll, null);
- actionsPanel.add(createNewGroup, null);
+ actionsPanel.add(createFeatures, null);
this.add(jLabelFind, java.awt.BorderLayout.WEST);
this.add(actionsPanel, java.awt.BorderLayout.EAST);
this.add(jPanel2, java.awt.BorderLayout.SOUTH);
this.add(jPanel3, java.awt.BorderLayout.NORTH);
this.add(jPanel4, java.awt.BorderLayout.CENTER);
- jPanel4.add(jScrollPane1, java.awt.BorderLayout.NORTH);
- jScrollPane1.getViewport().add(textfield);
+ jPanel4.add(searchBox, java.awt.BorderLayout.NORTH);
JPanel optionsPanel = new JPanel();
jPanel4.add(optionsPanel, java.awt.BorderLayout.WEST);
}
- protected void findNext_actionPerformed(ActionEvent e)
+ protected void textfield_keyPressed(KeyEvent e)
{
+ if (e.getKeyCode() == KeyEvent.VK_ENTER)
+ {
+ if (!searchBox.isPopupVisible())
+ {
+ e.consume();
+ findNext_actionPerformed(null);
+ }
+ }
}
- protected void findAll_actionPerformed(ActionEvent e)
+ protected void findNext_actionPerformed(ActionEvent e)
{
}
- protected void textfield_keyPressed(KeyEvent e)
+ protected void findAll_actionPerformed(ActionEvent e)
{
- if (e.getKeyCode() == KeyEvent.VK_ENTER)
- {
- e.consume();
- findNext_actionPerformed(null);
- }
}
- public void createNewGroup_actionPerformed(ActionEvent e)
+
+ public void createFeatures_actionPerformed()
{
}
public void textfield_caretUpdate(CaretEvent e)
{
- if (textfield.getText().indexOf(">") > -1)
+ if (searchBox.getUserInput().indexOf(">") > -1)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
- String str = textfield.getText();
+ String str = searchBox.getUserInput();
AlignmentI al = null;
try
{
jalview.util.Comparison.GapChars, al.getSequenceAt(0)
.getSequenceAsString());
- textfield.setText(str);
}
}
});
}
}
+
+
+
+
+
+ /**
+ * Returns unique key used for storing Finder cache items in the cache data
+ * structure
+ *
+ * @return
+ */
+ public String getCacheKey()
+ {
+ return FINDER_CACHE_KEY;
+ }
+
+
+
}
protected JCheckBox scaleAsCdna = new JCheckBox();
+ protected JCheckBox fontAsCdna = new JCheckBox();
+
/**
* Creates a new GFontChooser object.
*/
fontSize.setPreferredSize(new Dimension(50, 21));
fontSize.addActionListener(new java.awt.event.ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
- fontSize_actionPerformed(e);
+ fontSize_actionPerformed();
}
});
fontStyle.setPreferredSize(new Dimension(90, 21));
fontStyle.addActionListener(new java.awt.event.ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
- fontStyle_actionPerformed(e);
+ fontStyle_actionPerformed();
}
});
fontName.setPreferredSize(new Dimension(180, 21));
fontName.addActionListener(new java.awt.event.ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
- fontName_actionPerformed(e);
+ fontName_actionPerformed();
}
});
ok.setFont(VERDANA_11PT);
ok.addActionListener(new java.awt.event.ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
- ok_actionPerformed(e);
+ ok_actionPerformed();
}
});
cancel.setFont(VERDANA_11PT);
cancel.addActionListener(new java.awt.event.ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
- cancel_actionPerformed(e);
+ cancel_actionPerformed();
}
});
defaultButton.setText(MessageManager.getString("label.set_as_default"));
defaultButton.addActionListener(new ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
- defaultButton_actionPerformed(e);
+ defaultButton_actionPerformed();
}
});
smoothFont.setFont(JvSwingUtils.getLabelFont());
smoothFont.setOpaque(false);
smoothFont.setText(MessageManager.getString("label.anti_alias_fonts"));
- smoothFont.setBounds(new Rectangle(41, 65, 260, 23));
+ smoothFont.setBounds(new Rectangle(1, 65, 300, 23));
smoothFont.addActionListener(new ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
- smoothFont_actionPerformed(e);
+ smoothFont_actionPerformed();
}
});
/*
- * Scale protein as cDNA is only visible in SplitFrame protein alignment
+ * Scale protein as cDNA is only visible in SplitFrame
*/
scaleAsCdna.setVisible(false);
scaleAsCdna.setFont(JvSwingUtils.getLabelFont());
scaleAsCdna.setOpaque(false);
scaleAsCdna.setText(MessageManager.getString("label.scale_as_cdna"));
- scaleAsCdna.setBounds(new Rectangle(41, 85, 260, 23));
+ scaleAsCdna.setBounds(new Rectangle(1, 85, 300, 23));
scaleAsCdna.addActionListener(new ActionListener()
{
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ scaleAsCdna_actionPerformed();
+ }
+ });
+
+ /*
+ * Same font for cDNA/peptide is only visible in SplitFrame
+ */
+ fontAsCdna.setVisible(false);
+ fontAsCdna.setFont(JvSwingUtils.getLabelFont());
+ fontAsCdna.setOpaque(false);
+ fontAsCdna.setText(MessageManager.getString("label.font_as_cdna"));
+ fontAsCdna.setBounds(new Rectangle(1, 105, 350, 23));
+ fontAsCdna.addActionListener(new ActionListener()
+ {
+ @Override
public void actionPerformed(ActionEvent e)
{
- scaleAsCdna_actionPerformed(e);
+ mirrorFonts_actionPerformed();
}
});
*/
JPanel jPanel4 = new JPanel();
jPanel4.setOpaque(false);
- jPanel4.setBounds(new Rectangle(24, 112, 300, 35));
+ jPanel4.setBounds(new Rectangle(24, 132, 300, 35));
jPanel4.add(defaultButton);
jPanel4.add(ok);
jPanel4.add(cancel);
this.add(smoothFont);
this.add(scaleAsCdna);
+ this.add(fontAsCdna);
this.add(jPanel3, null);
this.add(jPanel2, null);
this.add(jPanel4);
this.add(jPanel1, null);
}
- protected void scaleAsCdna_actionPerformed(ActionEvent e)
+ protected void mirrorFonts_actionPerformed()
{
}
- /**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
- */
- protected void ok_actionPerformed(ActionEvent e)
+ protected void scaleAsCdna_actionPerformed()
{
}
- /**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
- */
- protected void cancel_actionPerformed(ActionEvent e)
+ protected void ok_actionPerformed()
{
}
- /**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
- */
- protected void fontName_actionPerformed(ActionEvent e)
+ protected void cancel_actionPerformed()
{
}
- /**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
- */
- protected void fontSize_actionPerformed(ActionEvent e)
+ protected void fontName_actionPerformed()
{
}
- /**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
- */
- protected void fontStyle_actionPerformed(ActionEvent e)
+ protected void fontSize_actionPerformed()
{
}
- /**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
- */
- public void defaultButton_actionPerformed(ActionEvent e)
+ protected void fontStyle_actionPerformed()
{
}
- public void smoothFont_actionPerformed(ActionEvent e)
+ public void defaultButton_actionPerformed()
{
+ }
+ protected void smoothFont_actionPerformed()
+ {
}
}
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
+import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class GPCAPanel extends JInternalFrame
{
- JPanel jPanel2 = new JPanel();
+ private static final Font VERDANA_12 = new Font("Verdana", 0, 12);
- JLabel jLabel1 = new JLabel();
+ protected JComboBox<String> xCombobox = new JComboBox<String>();
- JLabel jLabel2 = new JLabel();
+ protected JComboBox<String> yCombobox = new JComboBox<String>();
- JLabel jLabel3 = new JLabel();
+ protected JComboBox<String> zCombobox = new JComboBox<String>();
- protected JComboBox xCombobox = new JComboBox();
-
- protected JComboBox yCombobox = new JComboBox();
-
- protected JComboBox zCombobox = new JComboBox();
-
- protected JButton resetButton = new JButton();
-
- FlowLayout flowLayout1 = new FlowLayout();
-
- BorderLayout borderLayout1 = new BorderLayout();
-
- JMenuBar jMenuBar1 = new JMenuBar();
-
- JMenu fileMenu = new JMenu();
-
- JMenu saveMenu = new JMenu();
-
- protected JMenu scoreMatrixMenu = new JMenu();
-
- JMenuItem eps = new JMenuItem();
-
- JMenuItem png = new JMenuItem();
-
- JMenuItem print = new JMenuItem();
-
- JMenuItem outputValues = new JMenuItem();
-
- JMenuItem outputPoints = new JMenuItem();
-
- JMenuItem outputProjPoints = new JMenuItem();
+ protected JMenu scoreModelMenu = new JMenu();
protected JMenu viewMenu = new JMenu();
protected JCheckBoxMenuItem showLabels = new JCheckBoxMenuItem();
- JMenuItem bgcolour = new JMenuItem();
-
- JMenuItem originalSeqData = new JMenuItem();
-
protected JMenu associateViewsMenu = new JMenu();
protected JMenu calcSettings = new JMenu();
protected JCheckBoxMenuItem protSetting = new JCheckBoxMenuItem();
- protected JCheckBoxMenuItem jvVersionSetting = new JCheckBoxMenuItem();
-
protected JLabel statusBar = new JLabel();
- protected GridLayout statusPanelLayout = new GridLayout();
-
protected JPanel statusPanel = new JPanel();
public GPCAPanel()
yCombobox.addItem("dim " + i);
zCombobox.addItem("dim " + i);
}
-
- setJMenuBar(jMenuBar1);
}
private void jbInit() throws Exception
{
- this.getContentPane().setLayout(borderLayout1);
- jPanel2.setLayout(flowLayout1);
- jLabel1.setFont(new java.awt.Font("Verdana", 0, 12));
+ this.getContentPane().setLayout(new BorderLayout());
+ JPanel jPanel2 = new JPanel();
+ jPanel2.setLayout(new FlowLayout());
+ JLabel jLabel1 = new JLabel();
+ jLabel1.setFont(VERDANA_12);
jLabel1.setText("x=");
- jLabel2.setFont(new java.awt.Font("Verdana", 0, 12));
+ JLabel jLabel2 = new JLabel();
+ jLabel2.setFont(VERDANA_12);
jLabel2.setText("y=");
- jLabel3.setFont(new java.awt.Font("Verdana", 0, 12));
+ JLabel jLabel3 = new JLabel();
+ jLabel3.setFont(VERDANA_12);
jLabel3.setText("z=");
jPanel2.setBackground(Color.white);
jPanel2.setBorder(null);
- zCombobox.setFont(new java.awt.Font("Verdana", 0, 12));
- zCombobox.addActionListener(new java.awt.event.ActionListener()
+ zCombobox.setFont(VERDANA_12);
+ zCombobox.addActionListener(new ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
zCombobox_actionPerformed(e);
}
});
- yCombobox.setFont(new java.awt.Font("Verdana", 0, 12));
- yCombobox.addActionListener(new java.awt.event.ActionListener()
+ yCombobox.setFont(VERDANA_12);
+ yCombobox.addActionListener(new ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
yCombobox_actionPerformed(e);
}
});
- xCombobox.setFont(new java.awt.Font("Verdana", 0, 12));
- xCombobox.addActionListener(new java.awt.event.ActionListener()
+ xCombobox.setFont(VERDANA_12);
+ xCombobox.addActionListener(new ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
xCombobox_actionPerformed(e);
}
});
- resetButton.setFont(new java.awt.Font("Verdana", 0, 12));
+ JButton resetButton = new JButton();
+ resetButton.setFont(VERDANA_12);
resetButton.setText(MessageManager.getString("action.reset"));
- resetButton.addActionListener(new java.awt.event.ActionListener()
+ resetButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
resetButton_actionPerformed(e);
}
});
+ JMenu fileMenu = new JMenu();
fileMenu.setText(MessageManager.getString("action.file"));
+ JMenu saveMenu = new JMenu();
saveMenu.setText(MessageManager.getString("action.save_as"));
- eps.setText("EPS");
+ JMenuItem eps = new JMenuItem("EPS");
eps.addActionListener(new ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
eps_actionPerformed(e);
}
});
- png.setText("PNG");
+ JMenuItem png = new JMenuItem("PNG");
png.addActionListener(new ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
png_actionPerformed(e);
}
});
+ JMenuItem outputValues = new JMenuItem();
outputValues.setText(MessageManager.getString("label.output_values"));
outputValues.addActionListener(new ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
outputValues_actionPerformed(e);
}
});
+ JMenuItem outputPoints = new JMenuItem();
outputPoints.setText(MessageManager.getString("label.output_points"));
outputPoints.addActionListener(new ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
outputPoints_actionPerformed(e);
}
});
+ JMenuItem outputProjPoints = new JMenuItem();
outputProjPoints.setText(MessageManager
.getString("label.output_transformed_points"));
outputProjPoints.addActionListener(new ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
outputProjPoints_actionPerformed(e);
}
});
+ JMenuItem print = new JMenuItem();
+ print.setText(MessageManager.getString("action.print"));
print.addActionListener(new ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
print_actionPerformed(e);
viewMenu.setText(MessageManager.getString("action.view"));
viewMenu.addMenuListener(new MenuListener()
{
+ @Override
public void menuSelected(MenuEvent e)
{
viewMenu_menuSelected();
}
+ @Override
public void menuDeselected(MenuEvent e)
{
}
+ @Override
public void menuCanceled(MenuEvent e)
{
}
});
- scoreMatrixMenu.setText(MessageManager
+ scoreModelMenu.setText(MessageManager
.getString("label.select_score_model"));
- scoreMatrixMenu.addMenuListener(new MenuListener()
+ scoreModelMenu.addMenuListener(new MenuListener()
{
+ @Override
public void menuSelected(MenuEvent e)
{
- scoreMatrix_menuSelected();
+ scoreModel_menuSelected();
}
+ @Override
public void menuDeselected(MenuEvent e)
{
}
+ @Override
public void menuCanceled(MenuEvent e)
{
}
showLabels.setText(MessageManager.getString("label.show_labels"));
showLabels.addActionListener(new ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
showLabels_actionPerformed(e);
}
});
- print.setText(MessageManager.getString("action.print"));
+ JMenuItem bgcolour = new JMenuItem();
bgcolour.setText(MessageManager.getString("action.background_colour"));
bgcolour.addActionListener(new ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
bgcolour_actionPerformed(e);
}
});
+ JMenuItem originalSeqData = new JMenuItem();
originalSeqData.setText(MessageManager.getString("label.input_data"));
originalSeqData.addActionListener(new ActionListener()
{
+ @Override
public void actionPerformed(ActionEvent e)
{
originalSeqData_actionPerformed(e);
protSetting_actionPerfomed(arg0);
}
});
- jvVersionSetting.setText(MessageManager
- .getString("label.jalview_pca_calculation"));
- jvVersionSetting.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent arg0)
- {
- jvVersionSetting_actionPerfomed(arg0);
- }
- });
- calcSettings.add(jvVersionSetting);
+
calcSettings.add(nuclSetting);
calcSettings.add(protSetting);
- calcSettings.add(scoreMatrixMenu);
- statusPanel.setLayout(statusPanelLayout);
- statusBar.setFont(new java.awt.Font("Verdana", 0, 12));
+ calcSettings.add(scoreModelMenu);
+ statusPanel.setLayout(new GridLayout());
+ statusBar.setFont(VERDANA_12);
// statusPanel.setBackground(Color.lightGray);
// statusBar.setBackground(Color.lightGray);
// statusPanel.add(statusBar, null);
jPanel2.add(jLabel3, null);
jPanel2.add(zCombobox, null);
jPanel2.add(resetButton, null);
+
+ JMenuBar jMenuBar1 = new JMenuBar();
jMenuBar1.add(fileMenu);
jMenuBar1.add(viewMenu);
jMenuBar1.add(calcSettings);
+ setJMenuBar(jMenuBar1);
fileMenu.add(saveMenu);
fileMenu.add(outputValues);
fileMenu.add(print);
viewMenu.add(associateViewsMenu);
}
- protected void scoreMatrix_menuSelected()
+ protected void scoreModel_menuSelected()
{
// TODO Auto-generated method stub
{
}
-
- protected void jvVersionSetting_actionPerfomed(ActionEvent arg0)
- {
- // TODO Auto-generated method stub
-
- }
}
protected JComboBox<String> fontNameCB = new JComboBox<String>();
+ protected JCheckBox showOccupancy = new JCheckBox();
+
protected JCheckBox showUnconserved = new JCheckBox();
protected JCheckBox idItalics = new JCheckBox();
identity.setHorizontalTextPosition(SwingConstants.LEFT);
identity.setSelected(true);
identity.setText(MessageManager.getString("label.consensus"));
+ showOccupancy.setFont(LABEL_FONT);
+ showOccupancy.setEnabled(false);
+ showOccupancy.setHorizontalAlignment(SwingConstants.RIGHT);
+ showOccupancy.setHorizontalTextPosition(SwingConstants.LEFT);
+ showOccupancy.setSelected(true);
+ showOccupancy.setText(MessageManager.getString("label.occupancy"));
+
JLabel showGroupbits = new JLabel();
showGroupbits.setFont(LABEL_FONT);
showGroupbits.setHorizontalAlignment(SwingConstants.RIGHT);
.getString("label.database_references"));
annotations.setFont(LABEL_FONT);
annotations.setHorizontalAlignment(SwingConstants.RIGHT);
- annotations.setHorizontalTextPosition(SwingConstants.LEADING);
+ annotations.setHorizontalTextPosition(SwingConstants.LEFT);
annotations.setSelected(true);
annotations.setText(MessageManager.getString("label.show_annotations"));
- annotations.setBounds(new Rectangle(169, 12, 200, 23));
+ // annotations.setBounds(new Rectangle(169, 12, 200, 23));
annotations.addActionListener(new ActionListener()
{
@Override
sortAutocalc.setBounds(new Rectangle(290, 285, 165, 21));
JPanel annsettingsPanel = new JPanel();
- annsettingsPanel.setBounds(new Rectangle(173, 34, 320, 75));
+ annsettingsPanel.setBounds(new Rectangle(173, 13, 320, 96));
annsettingsPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
annsettingsPanel.setBorder(new EtchedBorder());
visualTab.add(annsettingsPanel);
Border jb = new EmptyBorder(1, 1, 4, 5);
+ annotations.setBorder(jb);
+ showOccupancy.setBorder(jb);
quality.setBorder(jb);
conservation.setBorder(jb);
identity.setBorder(jb);
showConsensLogo.setBorder(jb);
JPanel autoAnnotSettings = new JPanel();
- autoAnnotSettings.setLayout(new GridLayout(3, 3));
annsettingsPanel.add(autoAnnotSettings);
+ autoAnnotSettings.setLayout(new GridLayout(0, 2));
+ autoAnnotSettings.add(annotations);
autoAnnotSettings.add(quality);
+ // second row of autoannotation box
+ autoAnnotSettings = new JPanel();
+ annsettingsPanel.add(autoAnnotSettings);
+
+ autoAnnotSettings.setLayout(new GridLayout(0, 3));
autoAnnotSettings.add(conservation);
autoAnnotSettings.add(identity);
+ autoAnnotSettings.add(showOccupancy);
autoAnnotSettings.add(showGroupbits);
autoAnnotSettings.add(showGroupConservation);
autoAnnotSettings.add(showGroupConsensus);
autoAnnotSettings.add(showConsensbits);
autoAnnotSettings.add(showConsensHistogram);
autoAnnotSettings.add(showConsensLogo);
+
+
JPanel tooltipSettings = new JPanel();
tooltipSettings.setBorder(new TitledBorder(MessageManager
jPanel2.add(sortAnnLabel);
jPanel2.add(startupCheckbox);
visualTab.add(jPanel2);
- visualTab.add(annotations);
visualTab.add(startupFileTextfield);
visualTab.add(sortby);
visualTab.add(sortAnnBy);
import java.awt.BorderLayout;
import java.awt.CardLayout;
+import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
+import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
+import javax.swing.ListCellRenderer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
});
cmb_filterOption.addItemListener(this);
+
+ // add CustomComboSeparatorsRenderer to filter option combo-box
+ cmb_filterOption.setRenderer(new CustomComboSeparatorsRenderer(
+ (ListCellRenderer<Object>) cmb_filterOption.getRenderer())
+ {
+ @Override
+ protected boolean addSeparatorAfter(JList list, FilterOption value,
+ int index)
+ {
+ return value.isAddSeparatorAfter();
+ }
+ });
+
chk_invertFilter.addItemListener(this);
pnl_actions.add(chk_rememberSettings);
private String view;
- public FilterOption(String name, String value, String view)
+ private boolean addSeparatorAfter;
+
+ /**
+ * Model for structure filter option
+ *
+ * @param name
+ * - the name of the Option
+ * @param value
+ * - the value of the option
+ * @param view
+ * - the category of the filter option
+ * @param addSeparatorAfter
+ * - if true, a horizontal separator is rendered immediately after
+ * this filter option, otherwise
+ */
+ public FilterOption(String name, String value, String view,
+ boolean addSeparatorAfter)
{
this.name = name;
this.value = value;
this.view = view;
+ this.addSeparatorAfter = addSeparatorAfter;
}
public String getName()
{
return this.name;
}
+
+ public boolean isAddSeparatorAfter()
+ {
+ return addSeparatorAfter;
+ }
+
+ public void setAddSeparatorAfter(boolean addSeparatorAfter)
+ {
+ this.addSeparatorAfter = addSeparatorAfter;
+ }
}
/**
return cmb_filterOption;
}
+ /**
+ * Custom ListCellRenderer for adding a separator between different categories
+ * of structure chooser filter option drop-down.
+ *
+ * @author tcnofoegbu
+ *
+ */
+ public abstract class CustomComboSeparatorsRenderer implements
+ ListCellRenderer<Object>
+ {
+ private ListCellRenderer<Object> regent;
+
+ private JPanel separatorPanel = new JPanel(new BorderLayout());
+
+ private JSeparator jSeparator = new JSeparator();
+
+ public CustomComboSeparatorsRenderer(ListCellRenderer<Object> listCellRenderer)
+ {
+ this.regent = listCellRenderer;
+ }
+
+ @Override
+ public Component getListCellRendererComponent(JList list,
+ Object value,
+ int index, boolean isSelected, boolean cellHasFocus)
+ {
+
+ Component comp = regent.getListCellRendererComponent(list, value,
+ index, isSelected, cellHasFocus);
+ if (index != -1
+ && addSeparatorAfter(list, (FilterOption) value, index))
+ {
+ separatorPanel.removeAll();
+ separatorPanel.add(comp, BorderLayout.CENTER);
+ separatorPanel.add(jSeparator, BorderLayout.SOUTH);
+ return separatorPanel;
+ }
+ else
+ {
+ return comp;
+ }
+ }
+
+ protected abstract boolean addSeparatorAfter(JList list,
+ FilterOption value,
+ int index);
+ }
+
protected abstract void stateChanged(ItemEvent e);
protected abstract void ok_ActionPerformed();
public abstract void tabRefresh();
public abstract void validateSelections();
-}
+}
\ No newline at end of file
}
});
alignStructs = new JMenuItem();
- alignStructs
- .setText(MessageManager.getString("label.align_structures"));
+ alignStructs.setText(MessageManager
+ .getString("label.superpose_structures"));
alignStructs.addActionListener(new ActionListener()
{
@Override
}
});
- viewerActionMenu = new JMenu();
+ viewerActionMenu = new JMenu(); // text set in sub-classes
viewerActionMenu.setVisible(false);
viewerActionMenu.add(alignStructs);
colourMenu = new JMenu();
{
}
- protected void alignStructs_actionPerformed(ActionEvent actionEvent)
- {
- }
+ protected abstract String alignStructs_actionPerformed(
+ ActionEvent actionEvent);
public void pdbFile_actionPerformed(ActionEvent actionEvent)
{
gridLayout.setRows(5);
okButton.setFont(new java.awt.Font("Verdana", 0, 11));
okButton.setText(MessageManager.getString("action.ok"));
- okButton.addActionListener(new java.awt.event.ActionListener()
+ okButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
});
loadbutton.setFont(new java.awt.Font("Verdana", 0, 11));
loadbutton.setText(MessageManager.getString("action.load_scheme"));
- loadbutton.addActionListener(new java.awt.event.ActionListener()
+ loadbutton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
- loadbutton_actionPerformed(e);
+ loadbutton_actionPerformed();
}
});
savebutton.setFont(new java.awt.Font("Verdana", 0, 11));
savebutton.setText(MessageManager.getString("action.save_scheme"));
- savebutton.addActionListener(new java.awt.event.ActionListener()
+ savebutton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
- savebutton_actionPerformed(e);
+ savebutton_actionPerformed();
}
});
cancelButton.setFont(JvSwingUtils.getLabelFont());
cancelButton.setText(MessageManager.getString("action.cancel"));
- cancelButton.addActionListener(new java.awt.event.ActionListener()
+ cancelButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
- cancelButton_actionPerformed(e);
+ cancelButton_actionPerformed();
}
});
this.setBackground(new Color(212, 208, 223));
@Override
public void actionPerformed(ActionEvent e)
{
- caseSensitive_actionPerformed(e);
+ caseSensitive_actionPerformed();
}
});
lcaseColour
* @param e
* DOCUMENT ME!
*/
- protected void loadbutton_actionPerformed(ActionEvent e)
+ protected void loadbutton_actionPerformed()
{
}
- /**
- * DOCUMENT ME!
- *
- * @param e
- * DOCUMENT ME!
- */
- protected void savebutton_actionPerformed(ActionEvent e)
+ protected boolean savebutton_actionPerformed()
{
+ return false;
}
/**
* @param e
* DOCUMENT ME!
*/
- protected void cancelButton_actionPerformed(ActionEvent e)
+ protected void cancelButton_actionPerformed()
{
}
- public void caseSensitive_actionPerformed(ActionEvent e)
+ public void caseSensitive_actionPerformed()
{
}
- public void lcaseColour_actionPerformed(ActionEvent e)
+ public void lcaseColour_actionPerformed()
{
}
/**
* A class to model rectangular matrices of double values and operations on them
*/
-public class Matrix
+public class Matrix implements MatrixI
{
/*
* the cell values in row-major order
*/
- public double[][] value;
+ private double[][] value;
/*
* the number of rows
*/
- public int rows;
+ protected int rows;
/*
* the number of columns
*/
- public int cols;
+ protected int cols;
- /** DOCUMENT ME!! */
- public double[] d; // Diagonal
+ protected double[] d; // Diagonal
- /** DOCUMENT ME!! */
- public double[] e; // off diagonal
+ protected double[] e; // off diagonal
/**
* maximum number of iterations for tqli
*
*/
- int maxIter = 45; // fudge - add 15 iterations, just in case
+ private static final int maxIter = 45; // fudge - add 15 iterations, just in
+ // case
/**
- * Creates a new Matrix object. For example
+ * Default constructor
+ */
+ public Matrix()
+ {
+
+ }
+
+ /**
+ * Creates a new Matrix object containing a copy of the supplied array values.
+ * For example
*
* <pre>
* new Matrix(new double[][] {{2, 3, 4}, {5, 6, 7})
{
this.rows = values.length;
this.cols = this.rows == 0 ? 0 : values[0].length;
- this.value = values;
+
+ /*
+ * make a copy of the values array, for immutability
+ */
+ this.value = new double[rows][];
+ int i = 0;
+ for (double[] row : values)
+ {
+ if (row != null)
+ {
+ value[i] = new double[row.length];
+ System.arraycopy(row, 0, value[i], 0, row.length);
+ }
+ i++;
+ }
}
/**
- * Returns a new matrix which is the transposes of this one
+ * Returns a new matrix which is the transpose of this one
*
- * @return DOCUMENT ME!
+ * @return
*/
- public Matrix transpose()
+ @Override
+ public MatrixI transpose()
{
double[][] out = new double[cols][rows];
*
* @param ps
* DOCUMENT ME!
+ * @param format
*/
- public void print(PrintStream ps)
+ @Override
+ public void print(PrintStream ps, String format)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
- Format.print(ps, "%8.2f", value[i][j]);
+ Format.print(ps, format, getValue(i, j));
}
ps.println();
* if the number of columns in the pre-multiplier is not equal to
* the number of rows in the multiplicand (this)
*/
- public Matrix preMultiply(Matrix in)
+ @Override
+ public MatrixI preMultiply(MatrixI in)
{
- if (in.cols != this.rows)
+ if (in.width() != rows)
{
throw new IllegalArgumentException("Can't pre-multiply " + this.rows
- + " rows by " + in.cols + " columns");
+ + " rows by " + in.width() + " columns");
}
- double[][] tmp = new double[in.rows][this.cols];
+ double[][] tmp = new double[in.height()][this.cols];
- for (int i = 0; i < in.rows; i++)
+ for (int i = 0; i < in.height(); i++)
{
for (int j = 0; j < this.cols; j++)
{
- tmp[i][j] = 0.0;
-
- for (int k = 0; k < in.cols; k++)
+ /*
+ * result[i][j] is the vector product of
+ * in.row[i] and this.column[j]
+ */
+ for (int k = 0; k < in.width(); k++)
{
- tmp[i][j] += (in.value[i][k] * this.value[k][j]);
+ tmp[i][j] += (in.getValue(i, k) * this.value[k][j]);
}
}
}
* number of columns in the multiplicand (this)
* @see #preMultiply(Matrix)
*/
- public Matrix postMultiply(Matrix in)
+ @Override
+ public MatrixI postMultiply(MatrixI in)
{
- if (in.rows != this.cols)
+ if (in.height() != this.cols)
{
throw new IllegalArgumentException("Can't post-multiply " + this.cols
- + " columns by " + in.rows + " rows");
+ + " columns by " + in.height() + " rows");
}
return in.preMultiply(this);
}
*
* @return
*/
- public Matrix copy()
+ @Override
+ public MatrixI copy()
{
double[][] newmat = new double[rows][cols];
/**
* DOCUMENT ME!
*/
+ @Override
public void tred()
{
int n = rows;
- int l;
int k;
int j;
int i;
for (i = n; i >= 2; i--)
{
- l = i - 1;
+ final int l = i - 1;
h = 0.0;
scale = 0.0;
{
for (k = 1; k <= l; k++)
{
- scale += Math.abs(value[i - 1][k - 1]);
+ double v = Math.abs(getValue(i - 1, k - 1));
+ scale += v;
}
if (scale == 0.0)
{
- e[i - 1] = value[i - 1][l - 1];
+ e[i - 1] = getValue(i - 1, l - 1);
}
else
{
for (k = 1; k <= l; k++)
{
- value[i - 1][k - 1] /= scale;
- h += (value[i - 1][k - 1] * value[i - 1][k - 1]);
+ double v = divideValue(i - 1, k - 1, scale);
+ h += v * v;
}
- f = value[i - 1][l - 1];
+ f = getValue(i - 1, l - 1);
if (f > 0)
{
e[i - 1] = scale * g;
h -= (f * g);
- value[i - 1][l - 1] = f - g;
+ setValue(i - 1, l - 1, f - g);
f = 0.0;
for (j = 1; j <= l; j++)
{
- value[j - 1][i - 1] = value[i - 1][j - 1] / h;
+ double val = getValue(i - 1, j - 1) / h;
+ setValue(j - 1, i - 1, val);
g = 0.0;
for (k = 1; k <= j; k++)
{
- g += (value[j - 1][k - 1] * value[i - 1][k - 1]);
+ g += (getValue(j - 1, k - 1) * getValue(i - 1, k - 1));
}
for (k = j + 1; k <= l; k++)
{
- g += (value[k - 1][j - 1] * value[i - 1][k - 1]);
+ g += (getValue(k - 1, j - 1) * getValue(i - 1, k - 1));
}
e[j - 1] = g / h;
- f += (e[j - 1] * value[i - 1][j - 1]);
+ f += (e[j - 1] * getValue(i - 1, j - 1));
}
hh = f / (h + h);
for (j = 1; j <= l; j++)
{
- f = value[i - 1][j - 1];
+ f = getValue(i - 1, j - 1);
g = e[j - 1] - (hh * f);
e[j - 1] = g;
for (k = 1; k <= j; k++)
{
- value[j - 1][k - 1] -= ((f * e[k - 1]) + (g * value[i - 1][k - 1]));
+ double val = (f * e[k - 1]) + (g * getValue(i - 1, k - 1));
+ addValue(j - 1, k - 1, -val);
}
}
}
}
else
{
- e[i - 1] = value[i - 1][l - 1];
+ e[i - 1] = getValue(i - 1, l - 1);
}
d[i - 1] = h;
for (i = 1; i <= n; i++)
{
- l = i - 1;
+ final int l = i - 1;
if (d[i - 1] != 0.0)
{
for (k = 1; k <= l; k++)
{
- g += (value[i - 1][k - 1] * value[k - 1][j - 1]);
+ g += (getValue(i - 1, k - 1) * getValue(k - 1, j - 1));
}
for (k = 1; k <= l; k++)
{
- value[k - 1][j - 1] -= (g * value[k - 1][i - 1]);
+ addValue(k - 1, j - 1, -(g * getValue(k - 1, i - 1)));
}
}
}
- d[i - 1] = value[i - 1][i - 1];
- value[i - 1][i - 1] = 1.0;
+ d[i - 1] = getValue(i - 1, i - 1);
+ setValue(i - 1, i - 1, 1.0);
for (j = 1; j <= l; j++)
{
- value[j - 1][i - 1] = 0.0;
- value[i - 1][j - 1] = 0.0;
+ setValue(j - 1, i - 1, 0.0);
+ setValue(i - 1, j - 1, 0.0);
}
}
}
/**
+ * Adds f to the value at [i, j] and returns the new value
+ *
+ * @param i
+ * @param j
+ * @param f
+ */
+ protected double addValue(int i, int j, double f)
+ {
+ double v = value[i][j] + f;
+ value[i][j] = v;
+ return v;
+ }
+
+ /**
+ * Divides the value at [i, j] by divisor and returns the new value. If d is
+ * zero, returns the unchanged value.
+ *
+ * @param i
+ * @param j
+ * @param divisor
+ * @return
+ */
+ protected double divideValue(int i, int j, double divisor)
+ {
+ if (divisor == 0d)
+ {
+ return getValue(i, j);
+ }
+ double v = value[i][j];
+ v = v / divisor;
+ value[i][j] = v;
+ return v;
+ }
+
+ /**
* DOCUMENT ME!
*/
+ @Override
public void tqli() throws Exception
{
int n = rows;
double s;
double r;
double p;
- ;
double g;
double f;
for (k = 1; k <= n; k++)
{
- f = value[k - 1][i];
- value[k - 1][i] = (s * value[k - 1][i - 1]) + (c * f);
- value[k - 1][i - 1] = (c * value[k - 1][i - 1]) - (s * f);
+ f = getValue(k - 1, i);
+ setValue(k - 1, i, (s * getValue(k - 1, i - 1)) + (c * f));
+ setValue(k - 1, i - 1, (c * getValue(k - 1, i - 1)) - (s * f));
}
}
}
}
+ @Override
+ public double getValue(int i, int j)
+ {
+ return value[i][j];
+ }
+
+ @Override
+ public void setValue(int i, int j, double val)
+ {
+ value[i][j] = val;
+ }
+
/**
* DOCUMENT ME!
*/
}
/**
- * DOCUMENT ME!
+ * Answers the first argument with the sign of the second argument
*
* @param a
- * DOCUMENT ME!
* @param b
- * DOCUMENT ME!
*
- * @return DOCUMENT ME!
+ * @return
*/
- public double sign(double a, double b)
+ static double sign(double a, double b)
{
if (b < 0)
{
*
* @param ps
* DOCUMENT ME!
+ * @param format
*/
- public void printD(PrintStream ps)
+ @Override
+ public void printD(PrintStream ps, String format)
{
for (int j = 0; j < rows; j++)
{
- Format.print(ps, "%15.4e", d[j]);
+ Format.print(ps, format, d[j]);
}
}
*
* @param ps
* DOCUMENT ME!
+ * @param format TODO
*/
- public void printE(PrintStream ps)
+ @Override
+ public void printE(PrintStream ps, String format)
{
for (int j = 0; j < rows; j++)
{
- Format.print(ps, "%15.4e", e[j]);
+ Format.print(ps, format, e[j]);
+ }
+ }
+
+ @Override
+ public double[] getD()
+ {
+ return d;
+ }
+
+ @Override
+ public double[] getE()
+ {
+ return e;
+ }
+
+ @Override
+ public int height() {
+ return rows;
+ }
+
+ @Override
+ public int width()
+ {
+ return cols;
+ }
+
+ @Override
+ public double[] getRow(int i)
+ {
+ double[] row = new double[cols];
+ System.arraycopy(value[i], 0, row, 0, cols);
+ return row;
+ }
+
+ /**
+ * Returns a length 2 array of {minValue, maxValue} of all values in the
+ * matrix. Returns null if the matrix is null or empty.
+ *
+ * @return
+ */
+ double[] findMinMax()
+ {
+ if (value == null)
+ {
+ return null;
+ }
+ double min = Double.MAX_VALUE;
+ double max = -Double.MAX_VALUE;
+ boolean empty = true;
+ for (double[] row : value)
+ {
+ if (row != null)
+ {
+ for (double x : row)
+ {
+ empty = false;
+ if (x > max)
+ {
+ max = x;
+ }
+ if (x < min)
+ {
+ min = x;
+ }
+ }
+ }
+ }
+ return empty ? null : new double[] { min, max };
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void reverseRange(boolean maxToZero)
+ {
+ if (value == null)
+ {
+ return;
+ }
+ double[] minMax = findMinMax();
+ if (minMax == null)
+ {
+ return; // empty matrix
+ }
+ double subtractFrom = maxToZero ? minMax[1] : minMax[0] + minMax[1];
+
+ for (double[] row : value)
+ {
+ if (row != null)
+ {
+ int j = 0;
+ for (double x : row)
+ {
+ row[j] = subtractFrom - x;
+ j++;
+ }
+ }
+ }
+ }
+
+ /**
+ * Multiplies every entry in the matrix by the given value.
+ *
+ * @param
+ */
+ @Override
+ public void multiply(double by)
+ {
+ for (double[] row : value)
+ {
+ if (row != null)
+ {
+ for (int i = 0; i < row.length; i++)
+ {
+ row[i] *= by;
+ }
+ }
}
}
}
--- /dev/null
+package jalview.math;
+
+import java.io.PrintStream;
+
+public interface MatrixI
+{
+ /**
+ * Answers the number of columns
+ *
+ * @return
+ */
+ int width();
+
+ /**
+ * Answers the number of rows
+ *
+ * @return
+ */
+ int height();
+
+ /**
+ * Answers the value at row i, column j
+ *
+ * @param i
+ * @param j
+ * @return
+ */
+ double getValue(int i, int j);
+
+ /**
+ * Sets the value at row i, colum j
+ *
+ * @param i
+ * @param j
+ * @param d
+ */
+ void setValue(int i, int j, double d);
+
+ /**
+ * Answers a copy of the values in the i'th row
+ *
+ * @return
+ */
+ double[] getRow(int i);
+
+ MatrixI copy();
+
+ MatrixI transpose();
+
+ MatrixI preMultiply(MatrixI m);
+
+ MatrixI postMultiply(MatrixI m);
+
+ double[] getD();
+
+ double[] getE();
+
+ void print(PrintStream ps, String format);
+
+ void printD(PrintStream ps, String format);
+
+ void printE(PrintStream ps, String format);
+
+ void tqli() throws Exception;
+
+ void tred();
+
+ /**
+ * Reverses the range of the matrix values, so that the smallest values become
+ * the largest, and the largest become the smallest. This operation supports
+ * using a distance measure as a similarity measure, or vice versa.
+ * <p>
+ * If parameter <code>maxToZero</code> is true, then the maximum value becomes
+ * zero, i.e. all values are subtracted from the maximum. This is consistent
+ * with converting an identity similarity score to a distance score - the most
+ * similar (identity) corresponds to zero distance. However note that the
+ * operation is not reversible (unless the original minimum value is zero).
+ * For example a range of 10-40 would become 30-0, which would reverse a
+ * second time to 0-30. Also note that a general similarity measure (such as
+ * BLOSUM) may give different 'identity' scores for different sequences, so
+ * they cannot all convert to zero distance.
+ * <p>
+ * If parameter <code>maxToZero</code> is false, then the values are reflected
+ * about the average of {min, max} (effectively swapping min and max). This
+ * operation <em>is</em> reversible.
+ *
+ * @param maxToZero
+ */
+ void reverseRange(boolean maxToZero);
+
+ /**
+ * Multiply all entries by the given value
+ *
+ * @param d
+ */
+ void multiply(double d);
+}
--- /dev/null
+package jalview.math;
+
+import jalview.ext.android.SparseDoubleArray;
+
+/**
+ * A variant of Matrix intended for use for sparse (mostly zero) matrices. This
+ * class uses a SparseDoubleArray to hold each row of the matrix. The sparse
+ * array only stores non-zero values. This gives a smaller memory footprint, and
+ * fewer matrix calculation operations, for mostly zero matrices.
+ *
+ * @author gmcarstairs
+ */
+public class SparseMatrix extends Matrix
+{
+ /*
+ * we choose columns for the sparse arrays as this allows
+ * optimisation of the preMultiply() method used in PCA.run()
+ */
+ SparseDoubleArray[] sparseColumns;
+
+ /**
+ * Constructor given data in [row][column] order
+ *
+ * @param v
+ */
+ public SparseMatrix(double[][] v)
+ {
+ rows = v.length;
+ if (rows > 0) {
+ cols = v[0].length;
+ }
+ sparseColumns = new SparseDoubleArray[cols];
+
+ /*
+ * transpose v[row][col] into [col][row] order
+ */
+ for (int col = 0; col < cols; col++)
+ {
+ SparseDoubleArray sparseColumn = new SparseDoubleArray();
+ sparseColumns[col] = sparseColumn;
+ for (int row = 0; row < rows; row++)
+ {
+ double value = v[row][col];
+ if (value != 0d)
+ {
+ sparseColumn.put(row, value);
+ }
+ }
+ }
+ }
+
+ /**
+ * Answers the value at row i, column j
+ */
+ @Override
+ public double getValue(int i, int j)
+ {
+ return sparseColumns[j].get(i);
+ }
+
+ /**
+ * Sets the value at row i, column j to val
+ */
+ @Override
+ public void setValue(int i, int j, double val)
+ {
+ if (val == 0d)
+ {
+ sparseColumns[j].delete(i);
+ }
+ else
+ {
+ sparseColumns[j].put(i, val);
+ }
+ }
+
+ @Override
+ public double[] getColumn(int i)
+ {
+ double[] col = new double[height()];
+
+ SparseDoubleArray vals = sparseColumns[i];
+ for (int nonZero = 0; nonZero < vals.size(); nonZero++)
+ {
+ col[vals.keyAt(nonZero)] = vals.valueAt(nonZero);
+ }
+ return col;
+ }
+
+ @Override
+ public MatrixI copy()
+ {
+ double[][] vals = new double[height()][width()];
+ for (int i = 0; i < height(); i++)
+ {
+ vals[i] = getRow(i);
+ }
+ return new SparseMatrix(vals);
+ }
+
+ @Override
+ public MatrixI transpose()
+ {
+ double[][] out = new double[cols][rows];
+
+ /*
+ * for each column...
+ */
+ for (int i = 0; i < cols; i++)
+ {
+ /*
+ * put non-zero values into the corresponding row
+ * of the transposed matrix
+ */
+ SparseDoubleArray vals = sparseColumns[i];
+ for (int nonZero = 0; nonZero < vals.size(); nonZero++)
+ {
+ out[i][vals.keyAt(nonZero)] = vals.valueAt(nonZero);
+ }
+ }
+
+ return new SparseMatrix(out);
+ }
+
+ /**
+ * Answers a new matrix which is the product in.this. If the product contains
+ * less than 20% non-zero values, it is returned as a SparseMatrix, else as a
+ * Matrix.
+ * <p>
+ * This method is optimised for the sparse arrays which store column values
+ * for a SparseMatrix. Note that postMultiply is not so optimised. That would
+ * require redundantly also storing sparse arrays for the rows, which has not
+ * been done. Currently only preMultiply is used in Jalview.
+ */
+ @Override
+ public MatrixI preMultiply(MatrixI in)
+ {
+ if (in.width() != rows)
+ {
+ throw new IllegalArgumentException("Can't pre-multiply " + this.rows
+ + " rows by " + in.width() + " columns");
+ }
+ double[][] tmp = new double[in.height()][this.cols];
+
+ long count = 0L;
+ for (int i = 0; i < in.height(); i++)
+ {
+ for (int j = 0; j < this.cols; j++)
+ {
+ /*
+ * result[i][j] is the vector product of
+ * in.row[i] and this.column[j]
+ * we only need to use non-zero values from the column
+ */
+ SparseDoubleArray vals = sparseColumns[j];
+ boolean added = false;
+ for (int nonZero = 0; nonZero < vals.size(); nonZero++)
+ {
+ int myRow = vals.keyAt(nonZero);
+ double myValue = vals.valueAt(nonZero);
+ tmp[i][j] += (in.getValue(i, myRow) * myValue);
+ added = true;
+ }
+ if (added && tmp[i][j] != 0d)
+ {
+ count++; // non-zero entry in product
+ }
+ }
+ }
+
+ /*
+ * heuristic rule - if product is more than 80% zero
+ * then construct a SparseMatrix, else a Matrix
+ */
+ if (count * 5 < in.height() * cols)
+ {
+ return new SparseMatrix(tmp);
+ }
+ else
+ {
+ return new Matrix(tmp);
+ }
+ }
+
+ @Override
+ protected double divideValue(int i, int j, double divisor)
+ {
+ if (divisor == 0d)
+ {
+ return getValue(i, j);
+ }
+ double v = sparseColumns[j].divide(i, divisor);
+ return v;
+ }
+
+ @Override
+ protected double addValue(int i, int j, double addend)
+ {
+ double v = sparseColumns[j].add(i, addend);
+ return v;
+ }
+
+ /**
+ * Returns the fraction of the whole matrix size that is actually modelled in
+ * sparse arrays (normally, the non-zero values)
+ *
+ * @return
+ */
+ public float getFillRatio()
+ {
+ long count = 0L;
+ for (SparseDoubleArray col : sparseColumns)
+ {
+ count += col.size();
+ }
+ return count / (float) (height() * width());
+ }
+}
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.Annotation;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.ProfilesI;
import jalview.renderer.api.AnnotationRendererFactoryI;
import jalview.renderer.api.AnnotationRowRendererI;
ResidueShaderI profcolour = null;
private ColumnSelection columnSelection;
+
+ private HiddenColumns hiddenColumns;
private ProfilesI hconsensus;
public void updateFromAlignViewport(AlignViewportI av)
{
charWidth = av.getCharWidth();
- endRes = av.getEndRes();
+ endRes = av.getRanges().getEndRes();
charHeight = av.getCharHeight();
hasHiddenColumns = av.hasHiddenColumns();
validCharWidth = av.isValidCharWidth();
profcolour = new ResidueShader(col);
}
columnSelection = av.getColumnSelection();
+ hiddenColumns = av.getAlignment().getHiddenColumns();
hconsensus = av.getSequenceConsensusHash();
complementConsensus = av.getComplementConsensusHash();
hStrucConsensus = av.getRnaStructureConsensusHash();
{
if (hasHiddenColumns)
{
- column = columnSelection.adjustForHiddenColumns(startRes + x);
+ column = hiddenColumns.adjustForHiddenColumns(startRes + x);
if (column > row_annotations.length - 1)
{
break;
if (renderer != null)
{
renderer.renderRow(g, charWidth, charHeight,
- hasHiddenColumns, av, columnSelection, row,
- row_annotations, startRes, endRes, row.graphMin,
+ hasHiddenColumns, av, hiddenColumns, columnSelection,
+ row, row_annotations, startRes, endRes, row.graphMin,
row.graphMax, y);
}
if (debugRedraw)
column = sRes + x;
if (hasHiddenColumns)
{
- column = columnSelection.adjustForHiddenColumns(column);
+ column = hiddenColumns.adjustForHiddenColumns(column);
}
if (column > aaMax)
column = sRes + x;
if (hasHiddenColumns)
{
- column = columnSelection.adjustForHiddenColumns(column);
+ column = hiddenColumns.adjustForHiddenColumns(column);
}
if (column > aaMax)
import jalview.datamodel.ColumnSelection;
import jalview.datamodel.ContactListI;
import jalview.datamodel.ContactRange;
+import jalview.datamodel.HiddenColumns;
import jalview.renderer.api.AnnotationRowRendererI;
import java.awt.Color;
@Override
public void renderRow(Graphics g, int charWidth, int charHeight,
- boolean hasHiddenColumns, AlignViewportI viewport,
+ boolean hasHiddenColumns, AlignViewportI viewport, HiddenColumns hiddenColumns,
ColumnSelection columnSelection, AlignmentAnnotation _aa,
Annotation[] aa_annotations, int sRes, int eRes, float min,
float max, int y)
column = sRes + x;
if (hasHiddenColumns)
{
- column = columnSelection.adjustForHiddenColumns(column);
+ column = hiddenColumns.adjustForHiddenColumns(column);
}
if (column > aaMax)
--- /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.
+ */
+package jalview.renderer;
+
+import jalview.api.AlignmentColsCollectionI;
+import jalview.api.AlignmentRowsCollectionI;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
+import jalview.renderer.seqfeatures.FeatureRenderer;
+import jalview.viewmodel.OverviewDimensions;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+
+public class OverviewRenderer
+{
+ private FeatureColourFinder finder;
+
+ private jalview.api.SequenceRenderer sr;
+
+ // image to render on
+ private BufferedImage miniMe;
+
+ // raw number of pixels to allocate to each column
+ private float pixelsPerCol;
+
+ // raw number of pixels to allocate to each row
+ private float pixelsPerSeq;
+
+ public OverviewRenderer(jalview.api.SequenceRenderer seqRenderer,
+ FeatureRenderer fr, OverviewDimensions od)
+ // FeatureColourFinder colfinder, OverviewDimensions od)
+ {
+ sr = seqRenderer;
+ finder = new FeatureColourFinder(fr); // colfinder;
+
+ pixelsPerCol = od.getPixelsPerCol();
+ pixelsPerSeq = od.getPixelsPerSeq();
+ miniMe = new BufferedImage(od.getWidth(), od.getHeight(),
+ BufferedImage.TYPE_INT_RGB);
+ }
+
+ /**
+ * Draw alignment rows and columns onto an image
+ *
+ * @param rit
+ * Iterator over rows to be drawn
+ * @param cit
+ * Iterator over columns to be drawn
+ * @return image containing the drawing
+ */
+ public BufferedImage draw(AlignmentRowsCollectionI rows,
+ AlignmentColsCollectionI cols)
+ {
+ int rgbcolor = Color.white.getRGB();
+ int seqIndex = 0;
+ int pixelRow = 0;
+ for (int alignmentRow : rows)
+ {
+ // get details of this alignment row
+ boolean hidden = rows.isHidden(alignmentRow);
+ SequenceI seq = rows.getSequence(alignmentRow);
+
+ // calculate where this row extends to in pixels
+ int endRow = Math.min(Math.round((seqIndex + 1) * pixelsPerSeq) - 1,
+ miniMe.getHeight() - 1);
+
+ int colIndex = 0;
+ int pixelCol = 0;
+ for (int alignmentCol : cols)
+ {
+ // calculate where this column extends to in pixels
+ int endCol = Math.min(
+ Math.round((colIndex + 1) * pixelsPerCol) - 1,
+ miniMe.getWidth() - 1);
+
+ // don't do expensive colour determination if we're not going to use it
+ // NB this is important to avoid performance issues in the overview
+ // panel
+ if (pixelCol <= endCol)
+ {
+ // determine the colour based on the sequence and column position
+ rgbcolor = getColumnColourFromSequence(seq,
+ hidden || cols.isHidden(alignmentCol), alignmentCol,
+ finder);
+
+ // fill in the appropriate number of pixels
+ for (int row = pixelRow; row <= endRow; ++row)
+ {
+ for (int col = pixelCol; col <= endCol; ++col)
+ {
+ miniMe.setRGB(col, row, rgbcolor);
+ }
+ }
+
+ pixelCol = endCol + 1;
+ }
+ colIndex++;
+ }
+ pixelRow = endRow + 1;
+ seqIndex++;
+ }
+ return miniMe;
+ }
+
+ /*
+ * Find the colour of a sequence at a specified column position
+ */
+ private int getColumnColourFromSequence(jalview.datamodel.SequenceI seq,
+ boolean isHidden, int lastcol, FeatureColourFinder fcfinder)
+ {
+ Color color = Color.white;
+
+ if ((seq != null) && (seq.getLength() > lastcol))
+ {
+ color = sr.getResidueColour(seq, lastcol, fcfinder);
+ }
+
+ if (isHidden)
+ {
+ color = color.darker().darker();
+ }
+
+ return color.getRGB();
+ }
+
+ /**
+ * Draw the alignment annotation in the overview panel
+ *
+ * @param g
+ * the graphics object to draw on
+ * @param anno
+ * alignment annotation information
+ * @param charWidth
+ * alignment character width value
+ * @param y
+ * y-position for the annotation graph
+ * @param cols
+ * the collection of columns used in the overview panel
+ */
+ public void drawGraph(Graphics g, AlignmentAnnotation anno, int charWidth,
+ int y, AlignmentColsCollectionI cols)
+ {
+ Annotation[] annotations = anno.annotations;
+ g.setColor(Color.white);
+ g.fillRect(0, 0, miniMe.getWidth(), y);
+
+ int height;
+ int colIndex = 0;
+ int pixelCol = 0;
+ for (int alignmentCol : cols)
+ {
+ if (alignmentCol >= annotations.length)
+ {
+ break; // no more annotations to draw here
+ }
+ else
+ {
+ int endCol = Math.min(
+ Math.round((colIndex + 1) * pixelsPerCol) - 1,
+ miniMe.getWidth() - 1);
+
+ if (annotations[alignmentCol] != null)
+ {
+ if (annotations[alignmentCol].colour == null)
+ {
+ g.setColor(Color.black);
+ }
+ else
+ {
+ g.setColor(annotations[alignmentCol].colour);
+ }
+
+ height = (int) ((annotations[alignmentCol].value / anno.graphMax) * y);
+ if (height > y)
+ {
+ height = y;
+ }
+
+ g.fillRect(pixelCol, y - height, endCol - pixelCol + 1, height);
+ }
+ pixelCol = endCol + 1;
+ colIndex++;
+ }
+ }
+ }
+}
{
// find bounds and set origin appopriately
// locate first visible position for this sequence
- int[] refbounds = av.getColumnSelection()
+ int[] refbounds = av.getAlignment().getHiddenColumns()
.locateVisibleBoundsOfSequence(refSeq);
refSp = refbounds[0];
{
if (refSeq == null)
{
- iadj = av.getColumnSelection().adjustForHiddenColumns(i - 1) + 1;
+ iadj = av.getAlignment().getHiddenColumns()
+ .adjustForHiddenColumns(i - 1) + 1;
string = String.valueOf(iadj);
}
else
{
- iadj = av.getColumnSelection().adjustForHiddenColumns(i - 1);
+ iadj = av.getAlignment().getHiddenColumns()
+ .adjustForHiddenColumns(i - 1);
refN = refSeq.findPosition(iadj);
// TODO show bounds if position is a gap
// - ie L--R -> "1L|2R" for
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.Annotation;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import java.awt.Graphics;
void renderRow(Graphics g, int charWidth, int charHeight,
boolean hasHiddenColumns, AlignViewportI av,
+ HiddenColumns hiddenColumns,
ColumnSelection columnSelection, AlignmentAnnotation row,
Annotation[] row_annotations, int startRes, int endRes,
float graphMin, float graphMax, int y);
--- /dev/null
+package jalview.renderer.seqfeatures;
+
+import jalview.api.FeatureRenderer;
+import jalview.api.FeaturesDisplayedI;
+import jalview.datamodel.SequenceI;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+
+/**
+ * A helper class to find feature colour using an associated FeatureRenderer
+ *
+ * @author gmcarstairs
+ *
+ */
+public class FeatureColourFinder
+{
+ /*
+ * the class we delegate feature finding to
+ */
+ private FeatureRenderer featureRenderer;
+
+ /*
+ * a 1-pixel image on which features can be drawn, for the case where
+ * transparency allows 'see-through' of multiple feature colours
+ */
+ private BufferedImage offscreenImage;
+
+ /**
+ * Constructor
+ *
+ * @param fr
+ */
+ public FeatureColourFinder(FeatureRenderer fr)
+ {
+ featureRenderer = fr;
+ offscreenImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
+ }
+
+ /**
+ * Answers the feature colour to show for the given sequence and column
+ * position. This delegates to the FeatureRenderer to find the colour, which
+ * will depend on feature location, visibility, ordering, colour scheme, and
+ * whether or not transparency is applied. For feature rendering with
+ * transparency, this class provides a dummy 'offscreen' graphics context
+ * where multiple feature colours can be overlaid and the combined colour read
+ * back.
+ * <p>
+ * This method is not thread-safe when transparency is applied, since a shared
+ * BufferedImage would be used by all threads to hold the composite colour at
+ * a position. Each thread should use a separate instance of this class.
+ *
+ * @param defaultColour
+ * @param seq
+ * @param column
+ * alignment column position (base zero)
+ * @return
+ */
+ public Color findFeatureColour(Color defaultColour, SequenceI seq,
+ int column)
+ {
+ if (noFeaturesDisplayed())
+ {
+ return defaultColour;
+ }
+
+ Graphics g = null;
+
+ /*
+ * if transparency applies, provide a notional 1x1 graphics context
+ * that has been primed with the default colour
+ */
+ if (featureRenderer.getTransparency() != 1f)
+ {
+ g = offscreenImage.getGraphics();
+ if (defaultColour != null)
+ {
+ offscreenImage.setRGB(0, 0, defaultColour.getRGB());
+ }
+ }
+
+ Color c = featureRenderer.findFeatureColour(seq, column, g);
+ if (c == null)
+ {
+ return defaultColour;
+ }
+
+ if (g != null)
+ {
+ c = new Color(offscreenImage.getRGB(0, 0));
+ }
+ return c;
+ }
+
+ /**
+ * Answers true if feature display is turned off, or there are no features
+ * configured to be visible
+ *
+ * @return
+ */
+ boolean noFeaturesDisplayed()
+ {
+ if (featureRenderer == null
+ || !featureRenderer.getViewport().isShowSequenceFeatures())
+ {
+ return true;
+ }
+
+ if (!((FeatureRendererModel) featureRenderer).hasRenderOrder())
+ {
+ return true;
+ }
+
+ FeaturesDisplayedI displayed = featureRenderer.getFeaturesDisplayed();
+ if (displayed == null || displayed.getVisibleFeatureCount() == 0)
+ {
+ return true;
+ }
+
+ return false;
+ }
+}
import jalview.api.AlignViewportI;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.util.Comparison;
import jalview.viewmodel.seqfeatures.FeatureRendererModel;
import java.awt.AlphaComposite;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
-import java.awt.image.BufferedImage;
public class FeatureRenderer extends FeatureRendererModel
{
-
- FontMetrics fm;
-
- int charOffset;
-
- boolean offscreenRender = false;
-
- protected SequenceI lastSeq;
-
- char s;
-
- int i;
-
- int av_charHeight, av_charWidth;
-
- boolean av_validCharWidth, av_isShowSeqFeatureHeight;
-
- private Integer currentColour;
+ private static final AlphaComposite NO_TRANSPARENCY = AlphaComposite
+ .getInstance(AlphaComposite.SRC_OVER, 1.0f);
/**
* Constructor given a viewport
this.av = viewport;
}
- protected void updateAvConfig()
+ /**
+ * Renders the sequence using the given feature colour between the given start
+ * and end columns. Returns true if at least one column is drawn, else false
+ * (the feature range does not overlap the start and end positions).
+ *
+ * @param g
+ * @param seq
+ * @param featureStart
+ * @param featureEnd
+ * @param featureColour
+ * @param start
+ * @param end
+ * @param y1
+ * @param colourOnly
+ * @return
+ */
+ boolean renderFeature(Graphics g, SequenceI seq, int featureStart,
+ int featureEnd, Color featureColour, int start, int end, int y1,
+ boolean colourOnly)
{
- av_charHeight = av.getCharHeight();
- av_charWidth = av.getCharWidth();
- av_validCharWidth = av.isValidCharWidth();
- av_isShowSeqFeatureHeight = av.isShowSequenceFeaturesHeight();
- }
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
+ boolean validCharWidth = av.isValidCharWidth();
- void renderFeature(Graphics g, SequenceI seq, int fstart, int fend,
- Color featureColour, int start, int end, int y1)
- {
- updateAvConfig();
- if (((fstart <= end) && (fend >= start)))
+ if (featureStart > end || featureEnd < start)
{
- if (fstart < start)
- { // fix for if the feature we have starts before the sequence start,
- fstart = start; // but the feature end is still valid!!
- }
-
- if (fend >= end)
- {
- fend = end;
- }
- int pady = (y1 + av_charHeight) - av_charHeight / 5;
- for (i = fstart; i <= fend; i++)
- {
- s = seq.getCharAt(i);
-
- if (jalview.util.Comparison.isGap(s))
- {
- continue;
- }
-
- g.setColor(featureColour);
-
- g.fillRect((i - start) * av_charWidth, y1, av_charWidth,
- av_charHeight);
-
- if (offscreenRender || !av_validCharWidth)
- {
- continue;
- }
-
- g.setColor(Color.white);
- charOffset = (av_charWidth - fm.charWidth(s)) / 2;
- g.drawString(String.valueOf(s), charOffset
- + (av_charWidth * (i - start)), pady);
+ return false;
+ }
- }
+ if (featureStart < start)
+ {
+ featureStart = start;
}
- }
+ if (featureEnd >= end)
+ {
+ featureEnd = end;
+ }
+ int pady = (y1 + charHeight) - charHeight / 5;
- void renderScoreFeature(Graphics g, SequenceI seq, int fstart, int fend,
- Color featureColour, int start, int end, int y1, byte[] bs)
- {
- updateAvConfig();
- if (((fstart <= end) && (fend >= start)))
+ FontMetrics fm = g.getFontMetrics();
+ for (int i = featureStart; i <= featureEnd; i++)
{
- if (fstart < start)
- { // fix for if the feature we have starts before the sequence start,
- fstart = start; // but the feature end is still valid!!
- }
+ char s = seq.getCharAt(i);
- if (fend >= end)
- {
- fend = end;
- }
- int pady = (y1 + av_charHeight) - av_charHeight / 5;
- int ystrt = 0, yend = av_charHeight;
- if (bs[0] != 0)
- {
- // signed - zero is always middle of residue line.
- if (bs[1] < 128)
- {
- yend = av_charHeight * (128 - bs[1]) / 512;
- ystrt = av_charHeight - yend / 2;
- }
- else
- {
- ystrt = av_charHeight / 2;
- yend = av_charHeight * (bs[1] - 128) / 512;
- }
- }
- else
+ if (Comparison.isGap(s))
{
- yend = av_charHeight * bs[1] / 255;
- ystrt = av_charHeight - yend;
-
+ continue;
}
- for (i = fstart; i <= fend; i++)
- {
- s = seq.getCharAt(i);
-
- if (jalview.util.Comparison.isGap(s))
- {
- continue;
- }
- g.setColor(featureColour);
- int x = (i - start) * av_charWidth;
- g.drawRect(x, y1, av_charWidth, av_charHeight);
- g.fillRect(x, y1 + ystrt, av_charWidth, yend);
+ g.setColor(featureColour);
- if (offscreenRender || !av_validCharWidth)
- {
- continue;
- }
+ g.fillRect((i - start) * charWidth, y1, charWidth,
+ charHeight);
- g.setColor(Color.black);
- charOffset = (av_charWidth - fm.charWidth(s)) / 2;
- g.drawString(String.valueOf(s), charOffset
- + (av_charWidth * (i - start)), pady);
+ if (colourOnly || !validCharWidth)
+ {
+ continue;
}
- }
- }
-
- BufferedImage offscreenImage;
- @Override
- public Color findFeatureColour(Color initialCol, SequenceI seq, int res)
- {
- return new Color(findFeatureColour(initialCol.getRGB(), seq, res));
+ g.setColor(Color.white);
+ int charOffset = (charWidth - fm.charWidth(s)) / 2;
+ g.drawString(String.valueOf(s), charOffset
+ + (charWidth * (i - start)), pady);
+ }
+ return true;
}
/**
- * This is used by Structure Viewers and the Overview Window to get the
- * feature colour of the rendered sequence, returned as an RGB value
+ * Renders the sequence using the given SCORE feature colour between the given
+ * start and end columns. Returns true if at least one column is drawn, else
+ * false (the feature range does not overlap the start and end positions).
*
- * @param defaultColour
+ * @param g
* @param seq
- * @param column
+ * @param fstart
+ * @param fend
+ * @param featureColour
+ * @param start
+ * @param end
+ * @param y1
+ * @param bs
+ * @param colourOnly
* @return
*/
- public synchronized int findFeatureColour(int defaultColour,
- final SequenceI seq, int column)
+ boolean renderScoreFeature(Graphics g, SequenceI seq, int fstart,
+ int fend, Color featureColour, int start, int end, int y1,
+ byte[] bs, boolean colourOnly)
{
- if (!av.isShowSequenceFeatures())
+ if (fstart > end || fend < start)
{
- return defaultColour;
+ return false;
}
- SequenceFeature[] sequenceFeatures = seq.getSequenceFeatures();
- if (seq != lastSeq)
+ if (fstart < start)
+ { // fix for if the feature we have starts before the sequence start,
+ fstart = start; // but the feature end is still valid!!
+ }
+
+ if (fend >= end)
+ {
+ fend = end;
+ }
+ int charHeight = av.getCharHeight();
+ int pady = (y1 + charHeight) - charHeight / 5;
+ int ystrt = 0, yend = charHeight;
+ if (bs[0] != 0)
{
- lastSeq = seq;
- lastSequenceFeatures = sequenceFeatures;
- if (lastSequenceFeatures != null)
+ // signed - zero is always middle of residue line.
+ if (bs[1] < 128)
{
- sfSize = lastSequenceFeatures.length;
+ yend = charHeight * (128 - bs[1]) / 512;
+ ystrt = charHeight - yend / 2;
+ }
+ else
+ {
+ ystrt = charHeight / 2;
+ yend = charHeight * (bs[1] - 128) / 512;
}
}
else
{
- if (lastSequenceFeatures != sequenceFeatures)
+ yend = charHeight * bs[1] / 255;
+ ystrt = charHeight - yend;
+
+ }
+
+ FontMetrics fm = g.getFontMetrics();
+ int charWidth = av.getCharWidth();
+
+ for (int i = fstart; i <= fend; i++)
+ {
+ char s = seq.getCharAt(i);
+
+ if (Comparison.isGap(s))
{
- lastSequenceFeatures = sequenceFeatures;
- if (lastSequenceFeatures != null)
- {
- sfSize = lastSequenceFeatures.length;
- }
+ continue;
}
+
+ g.setColor(featureColour);
+ int x = (i - start) * charWidth;
+ g.drawRect(x, y1, charWidth, charHeight);
+ g.fillRect(x, y1 + ystrt, charWidth, yend);
+
+ if (colourOnly || !av.isValidCharWidth())
+ {
+ continue;
+ }
+
+ g.setColor(Color.black);
+ int charOffset = (charWidth - fm.charWidth(s)) / 2;
+ g.drawString(String.valueOf(s), charOffset
+ + (charWidth * (i - start)), pady);
}
+ return true;
+ }
- if (lastSequenceFeatures == null || sfSize == 0)
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Color findFeatureColour(SequenceI seq, int column, Graphics g)
+ {
+ if (!av.isShowSequenceFeatures())
{
- return defaultColour;
+ return null;
}
- if (jalview.util.Comparison.isGap(lastSeq.getCharAt(column)))
+ SequenceFeature[] sequenceFeatures = seq.getSequenceFeatures();
+
+ if (sequenceFeatures == null || sequenceFeatures.length == 0)
{
- return Color.white.getRGB();
+ return null;
}
- // Only bother making an offscreen image if transparency is applied
- if (transparency != 1.0f && offscreenImage == null)
+ if (Comparison.isGap(seq.getCharAt(column)))
{
- offscreenImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
+ return Color.white;
}
- currentColour = null;
- // TODO: non-threadsafe - each rendering thread needs its own instance of
- // the feature renderer - or this should be synchronized.
- offscreenRender = true;
-
- if (offscreenImage != null)
+ Color renderedColour = null;
+ if (transparency == 1.0f)
{
- offscreenImage.setRGB(0, 0, defaultColour);
- drawSequence(offscreenImage.getGraphics(), lastSeq, column, column, 0);
-
- return offscreenImage.getRGB(0, 0);
+ /*
+ * simple case - just find the topmost rendered visible feature colour
+ */
+ renderedColour = findFeatureColour(seq, seq.findPosition(column));
}
else
{
- drawSequence(null, lastSeq, lastSeq.findPosition(column), -1, -1);
-
- if (currentColour == null)
- {
- return defaultColour;
- }
- else
- {
- return currentColour.intValue();
- }
+ /*
+ * transparency case - draw all visible features in render order to
+ * build up a composite colour on the graphics context
+ */
+ renderedColour = drawSequence(g, seq, column, column, 0, true);
}
-
+ return renderedColour;
}
- private volatile SequenceFeature[] lastSequenceFeatures;
-
- int sfSize;
-
- int sfindex;
-
- int spos;
-
- int epos;
-
/**
- * Draws the sequence on the graphics context, or just determines the colour
- * that would be drawn (if flag offscreenrender is true).
+ * Draws the sequence features on the graphics context, or just determines the
+ * colour that would be drawn (if flag colourOnly is true). Returns the last
+ * colour drawn (which may not be the effective colour if transparency
+ * applies), or null if no feature is drawn in the range given.
*
* @param g
+ * the graphics context to draw on (may be null if colourOnly==true)
* @param seq
* @param start
- * start column (or sequence position in offscreenrender mode)
+ * start column
* @param end
- * end column (not used in offscreenrender mode)
+ * end column
* @param y1
* vertical offset at which to draw on the graphics
+ * @param colourOnly
+ * if true, only do enough to determine the colour for the position,
+ * do not draw the character
+ * @return
*/
- public synchronized void drawSequence(Graphics g, final SequenceI seq,
- int start, int end, int y1)
+ public synchronized Color drawSequence(final Graphics g,
+ final SequenceI seq, int start, int end, int y1,
+ boolean colourOnly)
{
SequenceFeature[] sequenceFeatures = seq.getSequenceFeatures();
if (sequenceFeatures == null || sequenceFeatures.length == 0)
{
- return;
- }
-
- if (g != null)
- {
- fm = g.getFontMetrics();
+ return null;
}
updateFeatures();
- if (lastSeq == null || seq != lastSeq
- || sequenceFeatures != lastSequenceFeatures)
- {
- lastSeq = seq;
- lastSequenceFeatures = sequenceFeatures;
- }
-
- if (transparency != 1 && g != null)
+ if (transparency != 1f && g != null)
{
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
transparency));
}
- if (!offscreenRender)
- {
- spos = lastSeq.findPosition(start);
- epos = lastSeq.findPosition(end);
- }
+ int startPos = seq.findPosition(start);
+ int endPos = seq.findPosition(end);
+
+ int sfSize = sequenceFeatures.length;
+ Color drawnColour = null;
- sfSize = lastSequenceFeatures.length;
+ /*
+ * iterate over features in ordering of their rendering (last is on top)
+ */
for (int renderIndex = 0; renderIndex < renderOrder.length; renderIndex++)
{
String type = renderOrder[renderIndex];
// loop through all features in sequence to find
// current feature to render
- for (sfindex = 0; sfindex < sfSize; sfindex++)
+ for (int sfindex = 0; sfindex < sfSize; sfindex++)
{
- final SequenceFeature sequenceFeature = lastSequenceFeatures[sfindex];
+ final SequenceFeature sequenceFeature = sequenceFeatures[sfindex];
if (!sequenceFeature.type.equals(type))
{
continue;
}
+ /*
+ * a feature type may be flagged as shown but the group
+ * an instance of it belongs to may be hidden
+ */
if (featureGroupNotShown(sequenceFeature))
{
continue;
}
/*
- * check feature overlaps the visible part of the alignment,
- * unless doing offscreenRender (to the Overview window or a
- * structure viewer) which is not limited
+ * check feature overlaps the target range
+ * TODO: efficient retrieval of features overlapping a range
*/
- if (!offscreenRender
- && (sequenceFeature.getBegin() > epos || sequenceFeature
- .getEnd() < spos))
+ if (sequenceFeature.getBegin() > endPos
+ || sequenceFeature.getEnd() < startPos)
{
continue;
}
Color featureColour = getColour(sequenceFeature);
boolean isContactFeature = sequenceFeature.isContactFeature();
- if (offscreenRender && offscreenImage == null)
- {
- /*
- * offscreen mode with no image (image is only needed if transparency
- * is applied to feature colours) - just check feature is rendered at
- * the requested position (start == sequence position in this mode)
- */
- boolean featureIsAtPosition = sequenceFeature.begin <= start
- && sequenceFeature.end >= start;
- if (isContactFeature)
- {
- featureIsAtPosition = sequenceFeature.begin == start
- || sequenceFeature.end == start;
- }
- if (featureIsAtPosition)
- {
- // this is passed out to the overview and other sequence renderers
- // (e.g. molecule viewer) to get displayed colour for rendered
- // sequence
- currentColour = new Integer(featureColour.getRGB());
- // used to be retreived from av.featuresDisplayed
- // currentColour = av.featuresDisplayed
- // .get(sequenceFeatures[sfindex].type);
-
- }
- }
- else if (isContactFeature)
+ if (isContactFeature)
{
- renderFeature(g, seq, seq.findIndex(sequenceFeature.begin) - 1,
+ boolean drawn = renderFeature(g, seq,
+ seq.findIndex(sequenceFeature.begin) - 1,
seq.findIndex(sequenceFeature.begin) - 1, featureColour,
- start, end, y1);
- renderFeature(g, seq, seq.findIndex(sequenceFeature.end) - 1,
+ start, end, y1, colourOnly);
+ drawn |= renderFeature(g, seq,
+ seq.findIndex(sequenceFeature.end) - 1,
seq.findIndex(sequenceFeature.end) - 1, featureColour,
- start, end, y1);
-
+ start, end, y1, colourOnly);
+ if (drawn)
+ {
+ drawnColour = featureColour;
+ }
}
else if (showFeature(sequenceFeature))
{
- if (av_isShowSeqFeatureHeight
+ if (av.isShowSequenceFeaturesHeight()
&& !Float.isNaN(sequenceFeature.score))
{
- renderScoreFeature(g, seq,
+ boolean drawn = renderScoreFeature(g, seq,
seq.findIndex(sequenceFeature.begin) - 1,
- seq.findIndex(sequenceFeature.end) - 1,
- featureColour, start, end, y1,
- normaliseScore(sequenceFeature));
+ seq.findIndex(sequenceFeature.end) - 1, featureColour,
+ start, end, y1, normaliseScore(sequenceFeature),
+ colourOnly);
+ if (drawn)
+ {
+ drawnColour = featureColour;
+ }
}
else
{
- renderFeature(g, seq, seq.findIndex(sequenceFeature.begin) - 1,
- seq.findIndex(sequenceFeature.end) - 1,
- featureColour, start, end, y1);
+ boolean drawn = renderFeature(g, seq,
+ seq.findIndex(sequenceFeature.begin) - 1,
+ seq.findIndex(sequenceFeature.end) - 1, featureColour,
+ start, end, y1, colourOnly);
+ if (drawn)
+ {
+ drawnColour = featureColour;
+ }
}
}
}
if (transparency != 1.0f && g != null)
{
+ /*
+ * reset transparency
+ */
Graphics2D g2 = (Graphics2D) g;
- g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
- 1.0f));
+ g2.setComposite(NO_TRANSPARENCY);
}
+
+ return drawnColour;
}
/**
@Override
public void featuresAdded()
{
- lastSeq = null;
findAllFeatures();
}
+
+ /**
+ * Returns the sequence feature colour rendered at the given sequence
+ * position, or null if none found. The feature of highest render order (i.e.
+ * on top) is found, subject to both feature type and feature group being
+ * visible, and its colour returned.
+ *
+ * @param seq
+ * @param pos
+ * @return
+ */
+ Color findFeatureColour(SequenceI seq, int pos)
+ {
+ SequenceFeature[] sequenceFeatures = seq.getSequenceFeatures();
+ if (sequenceFeatures == null || sequenceFeatures.length == 0)
+ {
+ return null;
+ }
+
+ /*
+ * check for new feature added while processing
+ */
+ updateFeatures();
+
+ /*
+ * inspect features in reverse renderOrder (the last in the array is
+ * displayed on top) until we find one that is rendered at the position
+ */
+ for (int renderIndex = renderOrder.length - 1; renderIndex >= 0; renderIndex--)
+ {
+ String type = renderOrder[renderIndex];
+ if (!showFeatureOfType(type))
+ {
+ continue;
+ }
+
+ for (int sfindex = 0; sfindex < sequenceFeatures.length; sfindex++)
+ {
+ SequenceFeature sequenceFeature = sequenceFeatures[sfindex];
+ if (!sequenceFeature.type.equals(type))
+ {
+ continue;
+ }
+
+ if (featureGroupNotShown(sequenceFeature))
+ {
+ continue;
+ }
+
+ /*
+ * check the column position is within the feature range
+ * (or is one of the two contact positions for a contact feature)
+ */
+ boolean featureIsAtPosition = sequenceFeature.begin <= pos
+ && sequenceFeature.end >= pos;
+ if (sequenceFeature.isContactFeature())
+ {
+ featureIsAtPosition = sequenceFeature.begin == pos
+ || sequenceFeature.end == pos;
+ }
+ if (featureIsAtPosition)
+ {
+ return getColour(sequenceFeature);
+ }
+ }
+ }
+
+ /*
+ * no displayed feature found at position
+ */
+ return null;
+ }
}
import jalview.datamodel.GraphLine;
import jalview.datamodel.SequenceCollectionI;
import jalview.datamodel.SequenceI;
+import jalview.renderer.AnnotationRenderer;
+import jalview.util.Comparison;
import java.awt.Color;
import java.util.IdentityHashMap;
public static final int ABOVE_THRESHOLD = 1;
- public AlignmentAnnotation annotation;
+ private final AlignmentAnnotation annotation;
- int aboveAnnotationThreshold = -1;
+ private final int aboveAnnotationThreshold;
public boolean thresholdIsMinMax = false;
- GraphLine annotationThreshold;
+ private GraphLine annotationThreshold;
- float r1, g1, b1, rr, gg, bb;
+ private int redMin;
+
+ private int greenMin;
+
+ private int blueMin;
+
+ private int redRange;
+
+ private int greenRange;
+
+ private int blueRange;
private boolean predefinedColours = false;
*/
private boolean noGradient = false;
- IdentityHashMap<SequenceI, AlignmentAnnotation> seqannot = null;
+ private IdentityHashMap<SequenceI, AlignmentAnnotation> seqannot = null;
@Override
public ColourSchemeI getInstance(AnnotatedCollectionI sg,
acg.thresholdIsMinMax = thresholdIsMinMax;
acg.annotationThreshold = (annotationThreshold == null) ? null
: new GraphLine(annotationThreshold);
- acg.r1 = r1;
- acg.g1 = g1;
- acg.b1 = b1;
- acg.rr = rr;
- acg.gg = gg;
- acg.bb = bb;
+ acg.redMin = redMin;
+ acg.greenMin = greenMin;
+ acg.blueMin = blueMin;
+ acg.redRange = redRange;
+ acg.greenRange = greenRange;
+ acg.blueRange = blueRange;
acg.predefinedColours = predefinedColours;
acg.seqAssociated = seqAssociated;
acg.noGradient = noGradient;
annotationThreshold = annotation.threshold;
}
// clear values so we don't get weird black bands...
- r1 = 254;
- g1 = 254;
- b1 = 254;
- rr = 0;
- gg = 0;
- bb = 0;
+ redMin = 254;
+ greenMin = 254;
+ blueMin = 254;
+ redRange = 0;
+ greenRange = 0;
+ blueRange = 0;
noGradient = true;
checkLimits();
annotationThreshold = annotation.threshold;
}
- r1 = minColour.getRed();
- g1 = minColour.getGreen();
- b1 = minColour.getBlue();
+ redMin = minColour.getRed();
+ greenMin = minColour.getGreen();
+ blueMin = minColour.getBlue();
- rr = maxColour.getRed() - r1;
- gg = maxColour.getGreen() - g1;
- bb = maxColour.getBlue() - b1;
+ redRange = maxColour.getRed() - redMin;
+ greenRange = maxColour.getGreen() - greenMin;
+ blueRange = maxColour.getBlue() - blueMin;
noGradient = false;
checkLimits();
float aamin = 0f, aamax = 0f;
- public String getAnnotation()
+ public AlignmentAnnotation getAnnotation()
{
- return annotation.label;
+ return annotation;
}
public int getAboveThreshold()
public Color getMinColour()
{
- return new Color((int) r1, (int) g1, (int) b1);
+ return new Color(redMin, greenMin, blueMin);
}
public Color getMaxColour()
{
- return new Color((int) (r1 + rr), (int) (g1 + gg), (int) (b1 + bb));
+ return new Color(redMin + redRange, greenMin + greenRange, blueMin
+ + blueRange);
}
/**
}
/**
- * DOCUMENT ME!
+ * Returns the colour for a given character and position in a sequence
*
- * @param n
- * DOCUMENT ME!
+ * @param c
+ * the residue character
* @param j
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
+ * the aligned position
+ * @param seq
+ * the sequence
+ * @return
*/
@Override
public Color findColour(char c, int j, SequenceI seq)
{
- Color currentColour = Color.white;
- AlignmentAnnotation annotation = (seqAssociated && seqannot != null ? seqannot
+ /*
+ * locate the annotation we are configured to colour by
+ */
+ AlignmentAnnotation ann = (seqAssociated && seqannot != null ? seqannot
.get(seq) : this.annotation);
- if (annotation == null)
+
+ /*
+ * if gap or no annotation at position, no colour (White)
+ */
+ if (ann == null || ann.annotations == null
+ || j >= ann.annotations.length || ann.annotations[j] == null
+ || Comparison.isGap(c))
{
- return currentColour;
+ return Color.white;
}
- // if ((threshold == 0) || aboveThreshold(c, j))
- // {
- if (annotation.annotations != null && j < annotation.annotations.length
- && annotation.annotations[j] != null
- && !jalview.util.Comparison.isGap(c))
+
+ Annotation aj = ann.annotations[j];
+ // 'use original colours' => colourScheme != null
+ // -> look up colour to be used
+ // predefined colours => preconfigured shading
+ // -> only use original colours reference if thresholding enabled &
+ // minmax exists
+ // annotation.hasIcons => null or black colours replaced with glyph
+ // colours
+ // -> reuse original colours if present
+ // -> if thresholding enabled then return colour on non-whitespace glyph
+
+ /*
+ * if threshold applies, and annotation fails the test - no colour (white)
+ */
+ if (annotationThreshold != null)
{
- Annotation aj = annotation.annotations[j];
- // 'use original colours' => colourScheme != null
- // -> look up colour to be used
- // predefined colours => preconfigured shading
- // -> only use original colours reference if thresholding enabled &
- // minmax exists
- // annotation.hasIcons => null or black colours replaced with glyph
- // colours
- // -> reuse original colours if present
- // -> if thresholding enabled then return colour on non-whitespace glyph
-
- if (aboveAnnotationThreshold == NO_THRESHOLD
- || (annotationThreshold != null && (aboveAnnotationThreshold == ABOVE_THRESHOLD ? aj.value >= annotationThreshold.value
- : aj.value <= annotationThreshold.value)))
+ if ((aboveAnnotationThreshold == ABOVE_THRESHOLD && aj.value < annotationThreshold.value)
+ || (aboveAnnotationThreshold == BELOW_THRESHOLD && aj.value > annotationThreshold.value))
{
- if (predefinedColours && aj.colour != null
- && !aj.colour.equals(Color.black))
- {
- currentColour = aj.colour;
- }
- else if (annotation.hasIcons
- && annotation.graph == AlignmentAnnotation.NO_GRAPH)
+ return Color.white;
+ }
+ }
+
+ /*
+ * If 'use original colours' then return the colour of the annotation
+ * at the aligned position - computed using the background colour scheme
+ */
+ if (predefinedColours && aj.colour != null
+ && !aj.colour.equals(Color.black))
+ {
+ return aj.colour;
+ }
+
+ Color result = Color.white;
+ if (ann.hasIcons && ann.graph == AlignmentAnnotation.NO_GRAPH)
+ {
+ /*
+ * secondary structure symbol colouring
+ */
+ if (aj.secondaryStructure > ' ' && aj.secondaryStructure != '.'
+ && aj.secondaryStructure != '-')
+ {
+ if (getColourScheme() != null)
{
- if (aj.secondaryStructure > ' ' && aj.secondaryStructure != '.'
- && aj.secondaryStructure != '-')
- {
- if (getColourScheme() != null)
- {
- currentColour = getColourScheme().findColour(c, j, seq, null,
- 0f);
- }
- else
- {
- if (annotation.isRNA())
- {
- currentColour = ColourSchemeProperty.rnaHelices[(int) aj.value];
- }
- else
- {
- currentColour = annotation.annotations[j].secondaryStructure == 'H' ? jalview.renderer.AnnotationRenderer.HELIX_COLOUR
- : annotation.annotations[j].secondaryStructure == 'E' ? jalview.renderer.AnnotationRenderer.SHEET_COLOUR
- : jalview.renderer.AnnotationRenderer.STEM_COLOUR;
- }
- }
- }
- else
- {
- //
- return Color.white;
- }
+ result = getColourScheme().findColour(c, j, seq, null, 0f);
}
- else if (noGradient)
+ else
{
- if (getColourScheme() != null)
+ if (ann.isRNA())
{
- currentColour = getColourScheme().findColour(c, j, seq, null,
- 0f);
+ result = ColourSchemeProperty.rnaHelices[(int) aj.value];
}
else
{
- if (aj.colour != null)
- {
- currentColour = aj.colour;
- }
+ result = ann.annotations[j].secondaryStructure == 'H' ? AnnotationRenderer.HELIX_COLOUR
+ : ann.annotations[j].secondaryStructure == 'E' ? AnnotationRenderer.SHEET_COLOUR
+ : AnnotationRenderer.STEM_COLOUR;
}
}
- else
+ }
+ else
+ {
+ return Color.white;
+ }
+ }
+ else if (noGradient)
+ {
+ if (getColourScheme() != null)
+ {
+ result = getColourScheme().findColour(c, j, seq, null, 0f);
+ }
+ else
+ {
+ if (aj.colour != null)
{
- currentColour = shadeCalculation(annotation, j);
+ result = aj.colour;
}
}
- // if (conservationColouring)
- // {
- // currentColour = applyConservation(currentColour, j);
- // }
}
- // }
- return currentColour;
+ else
+ {
+ result = shadeCalculation(ann, j);
+ }
+
+ return result;
}
- private Color shadeCalculation(AlignmentAnnotation annotation, int j)
+ /**
+ * Returns a graduated colour for the annotation at the given column. If there
+ * is a threshold value, and it is used as the top/bottom of the colour range,
+ * and the value satisfies the threshold condition, then a colour
+ * proportionate to the range from the threshold is calculated. For all other
+ * cases, a colour proportionate to the annotation's min-max range is
+ * calulated. Note that thresholding is _not_ done here (a colour is computed
+ * even if threshold is not passed).
+ *
+ * @param ann
+ * @param col
+ * @return
+ */
+ Color shadeCalculation(AlignmentAnnotation ann, int col)
{
-
- // calculate a shade
float range = 1f;
- if (thresholdIsMinMax
- && annotation.threshold != null
+ float value = ann.annotations[col].value;
+ if (thresholdIsMinMax && ann.threshold != null
&& aboveAnnotationThreshold == ABOVE_THRESHOLD
- && annotation.annotations[j].value >= annotation.threshold.value)
+ && value >= ann.threshold.value)
{
- range = (annotation.annotations[j].value - annotation.threshold.value)
- / (annotation.graphMax - annotation.threshold.value);
+ range = (value - ann.threshold.value)
+ / (ann.graphMax - ann.threshold.value);
}
- else if (thresholdIsMinMax && annotation.threshold != null
+ else if (thresholdIsMinMax && ann.threshold != null
&& aboveAnnotationThreshold == BELOW_THRESHOLD
- && annotation.annotations[j].value >= annotation.graphMin)
+ && value <= ann.threshold.value)
{
- range = (annotation.annotations[j].value - annotation.graphMin)
- / (annotation.threshold.value - annotation.graphMin);
+ range = (value - ann.graphMin) / (ann.threshold.value - ann.graphMin);
}
else
{
- if (annotation.graphMax != annotation.graphMin)
+ if (ann.graphMax != ann.graphMin)
{
- range = (annotation.annotations[j].value - annotation.graphMin)
- / (annotation.graphMax - annotation.graphMin);
+ range = (value - ann.graphMin) / (ann.graphMax - ann.graphMin);
}
else
{
}
}
- int dr = (int) (rr * range + r1), dg = (int) (gg * range + g1), db = (int) (bb
- * range + b1);
+ int dr = (int) (redRange * range + redMin);
+ int dg = (int) (greenRange * range + greenMin);
+ int db = (int) (blueRange * range + blueMin);
return new Color(dr, dg, db);
-
}
public boolean isPredefinedColours()
seqAssociated = sassoc;
}
+ public boolean isThresholdIsMinMax()
+ {
+ return thresholdIsMinMax;
+ }
+
+ public void setThresholdIsMinMax(boolean minMax)
+ {
+ this.thresholdIsMinMax = minMax;
+ }
+
@Override
public String getSchemeName()
{
*/
package jalview.schemes;
+import jalview.analysis.scoremodels.ScoreModels;
+import jalview.api.analysis.PairwiseScoreModelI;
import jalview.datamodel.AnnotatedCollectionI;
import jalview.datamodel.SequenceCollectionI;
import jalview.datamodel.SequenceI;
public Color findColour(char res, int j, SequenceI seq,
String consensusResidue, float pid)
{
+ PairwiseScoreModelI sm = ScoreModels.getInstance().getBlosum62();
+
/*
* compare as upper case; note consensusResidue is
* always computed as uppercase
}
else
{
- int c = 0;
+ float score = 0;
for (char consensus : consensusResidue.toCharArray())
{
- c += ResidueProperties.getBLOSUM62(consensus, res);
+ score += sm.getPairwiseScore(consensus, res);
}
- if (c > 0)
+ if (score > 0)
{
colour = LIGHT_BLUE;
}
--- /dev/null
+package jalview.schemes;
+
+import jalview.binding.JalviewUserColours;
+
+import java.awt.Color;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+
+import org.exolab.castor.xml.Unmarshaller;
+
+public class ColourSchemeLoader
+{
+
+ /**
+ * Loads a user defined colour scheme from file. The file should contain a
+ * definition of residue colours in XML format as defined in
+ * JalviewUserColours.xsd.
+ *
+ * @param filePath
+ *
+ * @return
+ */
+ public static UserColourScheme loadColourScheme(String filePath)
+ {
+ UserColourScheme ucs = null;
+ Color[] newColours = null;
+ File file = new File(filePath);
+ try
+ {
+ InputStreamReader in = new InputStreamReader(
+ new FileInputStream(file), "UTF-8");
+
+ jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
+
+ org.exolab.castor.xml.Unmarshaller unmar = new org.exolab.castor.xml.Unmarshaller(
+ jucs);
+ jucs = (jalview.schemabinding.version2.JalviewUserColours) unmar
+ .unmarshal(in);
+
+ /*
+ * non-case-sensitive colours are for 20 amino acid codes,
+ * B, Z, X and Gap
+ * optionally, lower-case alternatives for all except Gap
+ */
+ newColours = new Color[24];
+ Color[] lowerCase = new Color[23];
+ boolean caseSensitive = false;
+
+ String name;
+ int index;
+ for (int i = 0; i < jucs.getColourCount(); i++)
+ {
+ name = jucs.getColour(i).getName();
+ if (ResidueProperties.aa3Hash.containsKey(name))
+ {
+ index = ResidueProperties.aa3Hash.get(name).intValue();
+ }
+ else
+ {
+ index = ResidueProperties.aaIndex[name.charAt(0)];
+ }
+ if (index == -1)
+ {
+ continue;
+ }
+
+ Color color = new Color(Integer.parseInt(jucs.getColour(i)
+ .getRGB(), 16));
+ if (name.toLowerCase().equals(name))
+ {
+ caseSensitive = true;
+ lowerCase[index] = color;
+ }
+ else
+ {
+ newColours[index] = color;
+ }
+ }
+
+ /*
+ * instantiate the colour scheme
+ */
+ ucs = new UserColourScheme(newColours);
+ ucs.setName(jucs.getSchemeName());
+ if (caseSensitive)
+ {
+ ucs.setLowerCaseColours(lowerCase);
+ }
+ } catch (Exception ex)
+ {
+ // Could be old Jalview Archive format
+ try
+ {
+ InputStreamReader in = new InputStreamReader(new FileInputStream(
+ file), "UTF-8");
+
+ jalview.binding.JalviewUserColours jucs = new jalview.binding.JalviewUserColours();
+
+ jucs = JalviewUserColours.unmarshal(in);
+
+ newColours = new Color[jucs.getColourCount()];
+
+ for (int i = 0; i < 24; i++)
+ {
+ newColours[i] = new Color(Integer.parseInt(jucs.getColour(i)
+ .getRGB(), 16));
+ }
+ ucs = new UserColourScheme(newColours);
+ ucs.setName(jucs.getSchemeName());
+ } catch (Exception ex2)
+ {
+ ex2.printStackTrace();
+ }
+
+ if (newColours == null)
+ {
+ System.out.println("Error loading User ColourFile\n" + ex);
+ }
+ }
+
+ return ucs;
+ }
+
+}
package jalview.schemes;
-import jalview.binding.JalviewUserColours;
import jalview.datamodel.AnnotatedCollectionI;
import jalview.datamodel.SequenceCollectionI;
import jalview.datamodel.SequenceI;
-import java.awt.Color;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStreamReader;
import java.util.LinkedHashMap;
import java.util.Map;
private static ColourSchemes instance = new ColourSchemes();
/*
- * a map from scheme name to an instance of it
+ * a map from scheme name (lower-cased) to an instance of it
*/
private Map<String, ColourSchemeI> schemes;
*/
public void removeColourScheme(String name)
{
- schemes.remove(name);
+ if (name != null)
+ {
+ schemes.remove(name.toLowerCase());
+ }
}
/**
{
return false;
}
- name = name.toLowerCase();
- for (ColourSchemeI scheme : getColourSchemes())
- {
- if (name.equals(scheme.getSchemeName().toLowerCase()))
- {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Loads a user defined colour scheme from file. The file should contain a
- * definition of residue colours in XML format as defined in
- * JalviewUserColours.xsd.
- *
- * @param filePath
- *
- * @return
- */
- public static UserColourScheme loadColourScheme(String filePath)
- {
- UserColourScheme ucs = null;
- Color[] newColours = null;
- File file = new File(filePath);
- try
- {
- InputStreamReader in = new InputStreamReader(
- new FileInputStream(file), "UTF-8");
-
- jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
-
- org.exolab.castor.xml.Unmarshaller unmar = new org.exolab.castor.xml.Unmarshaller(
- jucs);
- jucs = (jalview.schemabinding.version2.JalviewUserColours) unmar
- .unmarshal(in);
-
- /*
- * non-case-sensitive colours are for 20 amino acid codes,
- * B, Z, X and Gap
- * optionally, lower-case alternatives for all except Gap
- */
- newColours = new Color[24];
- Color[] lowerCase = new Color[23];
- boolean caseSensitive = false;
-
- String name;
- int index;
- for (int i = 0; i < jucs.getColourCount(); i++)
- {
- name = jucs.getColour(i).getName();
- if (ResidueProperties.aa3Hash.containsKey(name))
- {
- index = ResidueProperties.aa3Hash.get(name).intValue();
- }
- else
- {
- index = ResidueProperties.aaIndex[name.charAt(0)];
- }
- if (index == -1)
- {
- continue;
- }
-
- Color color = new Color(Integer.parseInt(jucs.getColour(i)
- .getRGB(), 16));
- if (name.toLowerCase().equals(name))
- {
- caseSensitive = true;
- lowerCase[index] = color;
- }
- else
- {
- newColours[index] = color;
- }
- }
-
- /*
- * instantiate the colour scheme
- */
- ucs = new UserColourScheme(newColours);
- ucs.setName(jucs.getSchemeName());
- if (caseSensitive)
- {
- ucs.setLowerCaseColours(lowerCase);
- }
- } catch (Exception ex)
- {
- // Could be old Jalview Archive format
- try
- {
- InputStreamReader in = new InputStreamReader(new FileInputStream(
- file), "UTF-8");
-
- jalview.binding.JalviewUserColours jucs = new jalview.binding.JalviewUserColours();
-
- jucs = JalviewUserColours.unmarshal(in);
-
- newColours = new Color[jucs.getColourCount()];
-
- for (int i = 0; i < 24; i++)
- {
- newColours[i] = new Color(Integer.parseInt(jucs.getColour(i)
- .getRGB(), 16));
- }
- ucs = new UserColourScheme(newColours);
- ucs.setName(jucs.getSchemeName());
- } catch (Exception ex2)
- {
- ex2.printStackTrace();
- }
-
- if (newColours == null)
- {
- System.out.println("Error loading User ColourFile\n" + ex);
- }
- }
-
- return ucs;
+ return schemes.containsKey(name.toLowerCase());
}
}
*/
package jalview.schemes;
-import jalview.analysis.scoremodels.FeatureScoreModel;
-import jalview.analysis.scoremodels.PIDScoreModel;
-import jalview.api.analysis.ScoreModelI;
-
import java.awt.Color;
import java.util.ArrayList;
import java.util.Arrays;
public class ResidueProperties
{
- public static Hashtable<String, ScoreModelI> scoreMatrices = new Hashtable<String, ScoreModelI>();
-
// Stores residue codes/names and colours and other things
public static final int[] aaIndex; // aaHash version 2.1.1 and below
// public static final double hydmax = 1.38;
// public static final double hydmin = -2.53;
- private static final int[][] BLOSUM62 = {
- { 4, -1, -2, -2, 0, -1, -1, 0, -2, -1, -1, -1, -1, -2, -1, 1, 0, -3,
- -2, 0, -2, -1, 0, -4 },
- { -1, 5, 0, -2, -3, 1, 0, -2, 0, -3, -2, 2, -1, -3, -2, -1, -1, -3,
- -2, -3, -1, 0, -1, -4 },
- { -2, 0, 6, 1, -3, 0, 0, 0, 1, -3, -3, 0, -2, -3, -2, 1, 0, -4, -2,
- -3, 3, 0, -1, -4 },
- { -2, -2, 1, 6, -3, 0, 2, -1, -1, -3, -4, -1, -3, -3, -1, 0, -1, -4,
- -3, -3, 4, 1, -1, -4 },
- { 0, 3, -3, -3, 9, -3, -4, -3, -3, -1, -1, -3, -1, -2, -3, -1, -1,
- -2, -2, -1, -3, -3, -2, -4 },
- { -1, 1, 0, 0, -3, 5, 2, -2, 0, -3, -2, 1, 0, -3, -1, 0, -1, -2, -1,
- -2, 0, 3, -1, -4 },
- { -1, 0, 0, 2, -4, 2, 5, -2, 0, -3, -3, 1, -2, -3, -1, 0, -1, -3, -2,
- -2, 1, 4, -1, -4 },
- { 0, -2, 0, -1, -3, -2, -2, 6, -2, -4, -4, -2, -3, -3, -2, 0, -2, -2,
- -3, -3, -1, -2, -1, -4 },
- { -2, 0, 1, -1, -3, 0, 0, -2, 8, -3, -3, -1, -2, -1, -2, -1, -2, -2,
- 2, -3, 0, 0, -1, -4 },
- { -1, -3, -3, -3, -1, -3, -3, -4, -3, 4, 2, -3, 1, 0, -3, -2, -1, -3,
- -1, 3, -3, -3, -1, -4 },
- { -1, -2, -3, -4, -1, -2, -3, -4, -3, 2, 4, -2, 2, 0, -3, -2, -1, -2,
- -1, 1, -4, -3, -1, -4 },
- { -1, 2, 0, -1, -3, 1, 1, -2, -1, -3, -2, 5, -1, -3, -1, 0, -1, -3,
- -2, -2, 0, 1, -1, -4 },
- { -1, -1, -2, -3, -1, 0, -2, -3, -2, 1, 2, -1, 5, 0, -2, -1, -1, -1,
- -1, 1, -3, -1, -1, -4 },
- { -2, -3, -3, -3, -2, -3, -3, -3, -1, 0, 0, -3, 0, 6, -4, -2, -2, 1,
- 3, -1, -3, -3, -1, -4 },
- { -1, -2, -2, -1, -3, -1, -1, -2, -2, -3, -3, -1, -2, -4, 7, -1, -1,
- -4, -3, -2, -2, -1, -2, -4 },
- { 1, -1, 1, 0, -1, 0, 0, 0, -1, -2, -2, 0, -1, -2, -1, 4, 1, -3, -2,
- -2, 0, 0, 0, -4 },
- { 0, -1, 0, -1, -1, -1, -1, -2, -2, -1, -1, -1, -1, -2, -1, 1, 5, -2,
- -2, 0, -1, -1, 0, -4 },
- { -3, -3, -4, -4, -2, -2, -3, -2, -2, -3, -2, -3, -1, 1, -4, -3, -2,
- 11, 2, -3, -4, -3, -2, -4 },
- { -2, -2, -2, -3, -2, -1, -2, -3, 2, -1, -1, -2, -1, 3, -3, -2, -2,
- 2, 7, -1, -3, -2, -1, -4 },
- { 0, -3, -3, -3, -1, -2, -2, -3, -3, 3, 1, -2, 1, -1, -2, -2, 0, -3,
- -1, 4, -3, -2, -1, -4 },
- { -2, -1, 3, 4, -3, 0, 1, -1, 0, -3, -4, 0, -3, -3, -2, 0, -1, -4,
- -3, -3, 4, 1, -1, -4 },
- { -1, 0, 0, 1, -3, 3, 4, -2, 0, -3, -3, 1, -1, -3, -1, 0, -1, -3, -2,
- -2, 1, 4, -1, -4 },
- { 0, -1, -1, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, 0, 0,
- -2, -1, -1, -1, -1, -1, -4 },
- { -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
- -4, -4, -4, -4, -4, -4, 1 }, };
-
- static final int[][] PAM250 = {
- { 2, -2, 0, 0, -2, 0, 0, 1, -1, -1, -2, -1, -1, -3, 1, 1, 1, -6, -3,
- 0, 0, 0, 0, -8 },
- { -2, 6, 0, -1, -4, 1, -1, -3, 2, -2, -3, 3, 0, -4, 0, 0, -1, 2, -4,
- -2, -1, 0, -1, -8 },
- { 0, 0, 2, 2, -4, 1, 1, 0, 2, -2, -3, 1, -2, -3, 0, 1, 0, -4, -2, -2,
- 2, 1, 0, -8 },
- { 0, -1, 2, 4, -5, 2, 3, 1, 1, -2, -4, 0, -3, -6, -1, 0, 0, -7, -4,
- -2, 3, 3, -1, -8 },
- { -2, -4, -4, -5, 12, -5, -5, -3, -3, -2, -6, -5, -5, -4, -3, 0, -2,
- -8, 0, -2, -4, -5, -3, -8 },
- { 0, 1, 1, 2, -5, 4, 2, -1, 3, -2, -2, 1, -1, -5, 0, -1, -1, -5, -4,
- -2, 1, 3, -1, -8 },
- { 0, -1, 1, 3, -5, 2, 4, 0, 1, -2, -3, 0, -2, -5, -1, 0, 0, -7, -4,
- -2, 3, 3, -1, -8 },
- { 1, -3, 0, 1, -3, -1, 0, 5, -2, -3, -4, -2, -3, -5, 0, 1, 0, -7, -5,
- -1, 0, 0, -1, -8 },
- { -1, 2, 2, 1, -3, 3, 1, -2, 6, -2, -2, 0, -2, -2, 0, -1, -1, -3, 0,
- -2, 1, 2, -1, -8 },
- { -1, -2, -2, -2, -2, -2, -2, -3, -2, 5, 2, -2, 2, 1, -2, -1, 0, -5,
- -1, 4, -2, -2, -1, -8 },
- { -2, -3, -3, -4, -6, -2, -3, -4, -2, 2, 6, -3, 4, 2, -3, -3, -2, -2,
- -1, 2, -3, -3, -1, -8 },
- { -1, 3, 1, 0, -5, 1, 0, -2, 0, -2, -3, 5, 0, -5, -1, 0, 0, -3, -4,
- -2, 1, 0, -1, -8 },
- { -1, 0, -2, -3, -5, -1, -2, -3, -2, 2, 4, 0, 6, 0, -2, -2, -1, -4,
- -2, 2, -2, -2, -1, -8 },
- { -3, -4, -3, -6, -4, -5, -5, -5, -2, 1, 2, -5, 0, 9, -5, -3, -3, 0,
- 7, -1, -4, -5, -2, -8 },
- { 1, 0, 0, -1, -3, 0, -1, 0, 0, -2, -3, -1, -2, -5, 6, 1, 0, -6, -5,
- -1, -1, 0, -1, -8 },
- { 1, 0, 1, 0, 0, -1, 0, 1, -1, -1, -3, 0, -2, -3, 1, 2, 1, -2, -3,
- -1, 0, 0, 0, -8 },
- { 1, -1, 0, 0, -2, -1, 0, 0, -1, 0, -2, 0, -1, -3, 0, 1, 3, -5, -3,
- 0, 0, -1, 0, -8 },
- { -6, 2, -4, -7, -8, -5, -7, -7, -3, -5, -2, -3, -4, 0, -6, -2, -5,
- 17, 0, -6, -5, -6, -4, -8 },
- { -3, -4, -2, -4, 0, -4, -4, -5, 0, -1, -1, -4, -2, 7, -5, -3, -3, 0,
- 10, -2, -3, -4, -2, -8 },
- { 0, -2, -2, -2, -2, -2, -2, -1, -2, 4, 2, -2, 2, -1, -1, -1, 0, -6,
- -2, 4, -2, -2, -1, -8 },
- { 0, -1, 2, 3, -4, 1, 3, 0, 1, -2, -3, 1, -2, -4, -1, 0, 0, -5, -3,
- -2, 3, 2, -1, -8 },
- { 0, 0, 1, 3, -5, 3, 3, 0, 2, -2, -3, 0, -2, -5, 0, 0, -1, -6, -4,
- -2, 2, 3, -1, -8 },
- { 0, -1, 0, -1, -3, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, 0, 0, -4,
- -2, -1, -1, -1, -1, -8 },
- { -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
- -8, -8, -8, -8, -8, -8, 1 }, };
// not currently used
// public static final Map<String, Color> ssHash = new Hashtable<String,
* Color.white, // R Color.white, // Y Color.white, // N Color.white, // Gap
*/
- // JBPNote: patch matrix for T/U equivalence when working with DNA or RNA.
- // Will equate sequences if working with mixed nucleotide sets.
- // treats T and U identically. R and Y weak equivalence with AG and CTU.
- // N matches any other base weakly
- //
- static final int[][] DNA = { { 10, -8, -8, -8, -8, 1, 1, 1, -8, 1, 1 }, // A
- { -8, 10, -8, -8, -8, 1, 1, -8, 1, 1, 1 }, // C
- { -8, -8, 10, -8, -8, 1, 1, 1, -8, 1, 1 }, // G
- { -8, -8, -8, 10, 10, 1, 1, -8, 1, 1, 1 }, // T
- { -8, -8, -8, 10, 10, 1, 1, -8, 1, 1, 1 }, // U
- { 1, 1, 1, 1, 1, 10, 0, 0, 0, 1, 1 }, // I
- { 1, 1, 1, 1, 1, 0, 10, 0, 0, 1, 1 }, // X
- { 1, -8, 1, -8, -8, 0, 0, 10, -8, 1, 1 }, // R
- { -8, 1, -8, 1, 1, 0, 0, -8, 10, 1, 1 }, // Y
- { 1, 1, 1, 1, 1, 1, 1, 1, 1, 10, 1 }, // N
- { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // -
- };
- /**
- * register matrices in list
- */
- static
- {
- scoreMatrices.put("BLOSUM62", new ScoreMatrix("BLOSUM62", BLOSUM62, 0));
- scoreMatrices.put("PAM250", new ScoreMatrix("PAM250", PAM250, 0));
- scoreMatrices.put("DNA", new ScoreMatrix("DNA", DNA, 1));
- }
-
public static List<String> STOP = Arrays.asList("TGA", "TAA", "TAG");
public static String START = "ATG";
propMatrixPos[i][i] = maxP;
propMatrixEpos[i][i] = maxEP;
}
- // JAL-1512 comment out physicochemical score matrices for 2.8.1 release
- // scoreMatrices.put("Conservation Pos", new
- // ScoreMatrix("Conservation Pos",propMatrixPos,0));
- // scoreMatrices.put("Conservation Both", new
- // ScoreMatrix("Conservation Both",propMatrixF,0));
- // scoreMatrices.put("Conservation EnhPos", new
- // ScoreMatrix("Conservation EnhPos",propMatrixEpos,0));
- scoreMatrices.put("PID", new PIDScoreModel());
- scoreMatrices.put("Displayed Features", new FeatureScoreModel());
}
private ResidueProperties()
return aa3Hash;
}
- public static int[][] getDNA()
- {
- return ResidueProperties.DNA;
- }
-
- public static int[][] getBLOSUM62()
- {
- return ResidueProperties.BLOSUM62;
- }
-
- public static int getPAM250(String A1, String A2)
- {
- return getPAM250(A1.charAt(0), A2.charAt(0));
- }
-
- public static int getBLOSUM62(char c1, char c2)
- {
- int pog = 0;
-
- try
- {
- int a = aaIndex[c1];
- int b = aaIndex[c2];
-
- pog = ResidueProperties.BLOSUM62[a][b];
- } catch (Exception e)
- {
- // System.out.println("Unknown residue in " + A1 + " " + A2);
- }
-
- return pog;
- }
-
public static String codonTranslate(String lccodon)
{
String cdn = codonHash2.get(lccodon.toUpperCase());
return cdn;
}
- public static int[][] getDefaultPeptideMatrix()
- {
- return ResidueProperties.getBLOSUM62();
- }
-
- public static int[][] getDefaultDnaMatrix()
- {
- return ResidueProperties.getDNA();
- }
-
- /**
- * get a ScoreMatrix based on its string name
- *
- * @param pwtype
- * @return matrix in scoreMatrices with key pwtype or null
- */
- public static ScoreMatrix getScoreMatrix(String pwtype)
- {
- Object val = scoreMatrices.get(pwtype);
- if (val != null && val instanceof ScoreMatrix)
- {
- return (ScoreMatrix) val;
- }
- return null;
- }
-
- /**
- * get a ScoreModel based on its string name
- *
- * @param pwtype
- * @return scoremodel of type pwtype or null
- */
- public static ScoreModelI getScoreModel(String pwtype)
- {
- return scoreMatrices.get(pwtype);
- }
-
- public static int getPAM250(char c, char d)
- {
- int a = aaIndex[c];
- int b = aaIndex[d];
-
- int pog = ResidueProperties.PAM250[a][b];
-
- return pog;
- }
-
public static Hashtable<String, String> toDssp3State;
static
{
+++ /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.
- */
-package jalview.schemes;
-
-import jalview.analysis.scoremodels.PairwiseSeqScoreModel;
-import jalview.api.analysis.ScoreModelI;
-
-public class ScoreMatrix extends PairwiseSeqScoreModel implements
- ScoreModelI
-{
- String name;
-
- @Override
- public String getName()
- {
- return name;
- }
-
- /**
- * reference to integer score matrix
- */
- int[][] matrix;
-
- /**
- * 0 for Protein Score matrix. 1 for dna score matrix
- */
- int type;
-
- /**
- *
- * @param name
- * Unique, human readable name for the matrix
- * @param matrix
- * Pairwise scores indexed according to appropriate symbol alphabet
- * @param type
- * 0 for Protein, 1 for NA
- */
- ScoreMatrix(String name, int[][] matrix, int type)
- {
- this.matrix = matrix;
- this.type = type;
- this.name = name;
- }
-
- @Override
- public boolean isDNA()
- {
- return type == 1;
- }
-
- @Override
- public boolean isProtein()
- {
- return type == 0;
- }
-
- @Override
- public int[][] getMatrix()
- {
- return matrix;
- }
-
- /**
- *
- * @param A1
- * @param A2
- * @return score for substituting first char in A1 with first char in A2
- */
- public int getPairwiseScore(String A1, String A2)
- {
- return getPairwiseScore(A1.charAt(0), A2.charAt(0));
- }
-
- public int getPairwiseScore(char c, char d)
- {
- int pog = 0;
-
- try
- {
- int a = (type == 0) ? ResidueProperties.aaIndex[c]
- : ResidueProperties.nucleotideIndex[c];
- int b = (type == 0) ? ResidueProperties.aaIndex[d]
- : ResidueProperties.nucleotideIndex[d];
-
- pog = matrix[a][b];
- } catch (Exception e)
- {
- // System.out.println("Unknown residue in " + A1 + " " + A2);
- }
-
- return pog;
- }
-
- /**
- * pretty print the matrix
- */
- public String toString()
- {
- return outputMatrix(false);
- }
-
- public String outputMatrix(boolean html)
- {
- StringBuffer sb = new StringBuffer();
- int[] symbols = (type == 0) ? ResidueProperties.aaIndex
- : ResidueProperties.nucleotideIndex;
- int symMax = (type == 0) ? ResidueProperties.maxProteinIndex
- : ResidueProperties.maxNucleotideIndex;
- boolean header = true;
- if (html)
- {
- sb.append("<table border=\"1\">");
- }
- for (char sym = 'A'; sym <= 'Z'; sym++)
- {
- if (symbols[sym] >= 0 && symbols[sym] < symMax)
- {
- if (header)
- {
- sb.append(html ? "<tr><td></td>" : "");
- for (char sym2 = 'A'; sym2 <= 'Z'; sym2++)
- {
- if (symbols[sym2] >= 0 && symbols[sym2] < symMax)
- {
- sb.append((html ? "<td> " : "\t") + sym2
- + (html ? " </td>" : ""));
- }
- }
- header = false;
- sb.append(html ? "</tr>\n" : "\n");
- }
- if (html)
- {
- sb.append("<tr>");
- }
- sb.append((html ? "<td>" : "") + sym + (html ? "</td>" : ""));
- for (char sym2 = 'A'; sym2 <= 'Z'; sym2++)
- {
- if (symbols[sym2] >= 0 && symbols[sym2] < symMax)
- {
- sb.append((html ? "<td>" : "\t")
- + matrix[symbols[sym]][symbols[sym2]]
- + (html ? "</td>" : ""));
- }
- }
- sb.append(html ? "</tr>\n" : "\n");
- }
- }
- if (html)
- {
- sb.append("</table>");
- }
- return sb.toString();
- }
-}
*/
public class AtomSpec
{
- // TODO clarify do we want pdbFile here, or pdbId?
- // compare highlightAtom in 2.8.2 for JalviewJmolBinding and
- // javascript.MouseOverStructureListener
+ int modelNo;
+
private String pdbFile;
private String chain;
private int atomIndex;
/**
+ * Parses a Chimera atomspec e.g. #1:12.A to construct an AtomSpec model (with
+ * null pdb file name)
+ *
+ * @param spec
+ * @return
+ * @throw IllegalArgumentException if the spec cannot be parsed, or represents
+ * more than one residue
+ */
+ public static AtomSpec fromChimeraAtomspec(String spec)
+ {
+ int colonPos = spec.indexOf(":");
+ if (colonPos == -1)
+ {
+ throw new IllegalArgumentException(spec);
+ }
+
+ int hashPos = spec.indexOf("#");
+ if (hashPos == -1 && colonPos != 0)
+ {
+ // # is missing but something precedes : - reject
+ throw new IllegalArgumentException(spec);
+ }
+
+ String modelSubmodel = spec.substring(hashPos + 1, colonPos);
+ int dotPos = modelSubmodel.indexOf(".");
+ int modelId = 0;
+ try
+ {
+ modelId = Integer.valueOf(dotPos == -1 ? modelSubmodel
+ : modelSubmodel.substring(0, dotPos));
+ } catch (NumberFormatException e)
+ {
+ // ignore, default to model 0
+ }
+
+ String residueChain = spec.substring(colonPos + 1);
+ dotPos = residueChain.indexOf(".");
+ int resNum = 0;
+ try
+ {
+ resNum = Integer.parseInt(dotPos == -1 ? residueChain
+ : residueChain.substring(0, dotPos));
+ } catch (NumberFormatException e)
+ {
+ // could be a range e.g. #1:4-7.B
+ throw new IllegalArgumentException(spec);
+ }
+
+ String chainId = dotPos == -1 ? "" : residueChain.substring(dotPos + 1);
+
+ return new AtomSpec(modelId, chainId, resNum, 0);
+ }
+
+ /**
* Constructor
*
* @param pdbFile
this.atomIndex = atomNo;
}
+ /**
+ * Constructor
+ *
+ * @param modelId
+ * @param chainId
+ * @param resNo
+ * @param atomNo
+ */
+ public AtomSpec(int modelId, String chainId, int resNo, int atomNo)
+ {
+ this.modelNo = modelId;
+ this.chain = chainId;
+ this.pdbResNum = resNo;
+ this.atomIndex = atomNo;
+ }
+
public String getPdbFile()
{
return pdbFile;
return atomIndex;
}
+ public int getModelNumber()
+ {
+ return modelNo;
+ }
+
+ public void setPdbFile(String file)
+ {
+ pdbFile = file;
+ }
+
@Override
public String toString()
{
* - source of the selection event
*/
public void selection(jalview.datamodel.SequenceGroup seqsel,
- jalview.datamodel.ColumnSelection colsel, SelectionSource source);
+ jalview.datamodel.ColumnSelection colsel,
+ jalview.datamodel.HiddenColumns hidden,
+ SelectionSource source);
}
* handles messages for, or null if generic listener (only used by
* removeListener method)
*/
- public String[] getPdbFile();
+ public String[] getStructureFiles();
/**
* Called by StructureSelectionManager to inform viewer to highlight given
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.SequenceI;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
public class StructureMapping
{
// and atomNo
HashMap<Integer, int[]> mapping;
+ /**
+ * Constructor
+ *
+ * @param seq
+ * @param pdbfile
+ * @param pdbid
+ * @param chain
+ * @param mapping
+ * a map from sequence to two values, { resNo, atomNo } in the
+ * structure
+ * @param mappingDetails
+ */
public StructureMapping(SequenceI seq, String pdbfile, String pdbid,
String chain, HashMap<Integer, int[]> mapping,
String mappingDetails)
}
/**
+ * Returns a (possibly empty) list of [start, end] residue positions in the
+ * mapped structure, corresponding to the given range of sequence positions
+ *
+ * @param fromSeqPos
+ * @param toSeqPos
+ * @return
+ */
+ public List<int[]> getPDBResNumRanges(int fromSeqPos, int toSeqPos)
+ {
+ List<int[]> result = new ArrayList<int[]>();
+ int startRes = -1;
+ int endRes = -1;
+
+ for (int i = fromSeqPos; i <= toSeqPos; i++)
+ {
+ int resNo = getPDBResNum(i);
+ if (resNo == UNASSIGNED_VALUE)
+ {
+ continue; // no mapping from this sequence position
+ }
+ if (startRes == -1)
+ {
+ startRes = resNo;
+ endRes = resNo;
+ }
+ if (resNo >= startRes && resNo <= endRes)
+ {
+ // within the current range - no change
+ continue;
+ }
+ if (resNo == startRes - 1)
+ {
+ // extend beginning of current range
+ startRes--;
+ continue;
+ }
+ if (resNo == endRes + 1)
+ {
+ // extend end of current range
+ endRes++;
+ continue;
+ }
+
+ /*
+ * resNo is not within or contiguous with last range,
+ * so write out the last range
+ */
+ result.add(new int[] { startRes, endRes });
+ startRes = resNo;
+ endRes = resNo;
+ }
+
+ /*
+ * and add the last range
+ */
+ if (startRes != -1)
+ {
+ result.add(new int[] { startRes, endRes });
+ }
+
+ return result;
+ }
+
+ /**
*
* @param pdbResNum
* @return -1 or the corresponding sequence position for a pdb residue number
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.Annotation;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SearchResults;
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceI;
import jalview.ext.jmol.JmolParser;
import jalview.gui.IProgressIndicator;
+import jalview.io.AppletFormatAdapter;
import jalview.io.DataSourceType;
import jalview.io.StructureFile;
import jalview.util.MappingUtils;
boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
try
{
+ sourceType = AppletFormatAdapter.checkProtocol(pdbFile);
pdb = new JmolParser(pdbFile, sourceType);
if (pdb.getId() != null && pdb.getId().trim().length() > 0
* Attempt pairwise alignment of the sequence with each chain in the PDB,
* and remember the highest scoring chain
*/
- int max = -10;
+ float max = -10;
AlignSeq maxAlignseq = null;
String maxChainId = " ";
PDBChain maxChain = null;
return pdb;
}
- private boolean isCIFFile(String filename)
+ public void addStructureMapping(StructureMapping sm)
{
- String fileExt = filename.substring(filename.lastIndexOf(".") + 1,
- filename.length());
- return "cif".equalsIgnoreCase(fileExt);
+ mappings.add(sm);
}
/**
if (listeners.elementAt(i) instanceof StructureListener)
{
sl = (StructureListener) listeners.elementAt(i);
- for (String pdbfile : sl.getPdbFile())
+ for (String pdbfile : sl.getStructureFiles())
{
pdbs.remove(pdbfile);
}
return;
}
+ SearchResultsI results = findAlignmentPositionsForStructurePositions(atoms);
+ for (Object li : listeners)
+ {
+ if (li instanceof SequenceListener)
+ {
+ ((SequenceListener) li).highlightSequence(results);
+ }
+ }
+ }
+
+ /**
+ * Constructs a SearchResults object holding regions (if any) in the Jalview
+ * alignment which have a mapping to the structure viewer positions in the
+ * supplied list
+ *
+ * @param atoms
+ * @return
+ */
+ public SearchResultsI findAlignmentPositionsForStructurePositions(
+ List<AtomSpec> atoms)
+ {
SearchResultsI results = new SearchResults();
for (AtomSpec atom : atoms)
{
}
}
}
- for (Object li : listeners)
- {
- if (li instanceof SequenceListener)
- {
- ((SequenceListener) li).highlightSequence(results);
- }
- }
+ return results;
}
/**
public synchronized void sendSelection(
jalview.datamodel.SequenceGroup selection,
- jalview.datamodel.ColumnSelection colsel, SelectionSource source)
+ jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
+ SelectionSource source)
{
for (SelectionListener slis : sel_listeners)
{
if (slis != source)
{
- slis.selection(selection, colsel, source);
+ slis.selection(selection, colsel, hidden, source);
}
}
}
--- /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.
+ */
+package jalview.structure;
+
+import jalview.analysis.AlignSeq;
+import jalview.api.StructureSelectionManagerProvider;
+import jalview.commands.CommandI;
+import jalview.commands.EditCommand;
+import jalview.commands.OrderCommand;
+import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SearchResults;
+import jalview.datamodel.SequenceI;
+import jalview.gui.IProgressIndicator;
+import jalview.io.AppletFormatAdapter;
+import jalview.io.StructureFile;
+import jalview.util.MappingUtils;
+import jalview.util.MessageManager;
+import jalview.ws.sifts.SiftsClient;
+import jalview.ws.sifts.SiftsException;
+import jalview.ws.sifts.SiftsSettings;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import MCview.Atom;
+import MCview.PDBChain;
+import MCview.PDBfile;
+
+public class StructureSelectionManager
+{
+ public final static String NEWLINE = System.lineSeparator();
+
+ static IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> instances;
+
+ private List<StructureMapping> mappings = new ArrayList<StructureMapping>();
+
+ private boolean processSecondaryStructure = false;
+
+ private boolean secStructServices = false;
+
+ private boolean addTempFacAnnot = false;
+
+ private SiftsClient siftsClient = null;
+
+ /*
+ * Set of any registered mappings between (dataset) sequences.
+ */
+ private List<AlignedCodonFrame> seqmappings = new ArrayList<AlignedCodonFrame>();
+
+ private List<CommandListener> commandListeners = new ArrayList<CommandListener>();
+
+ private List<SelectionListener> sel_listeners = new ArrayList<SelectionListener>();
+
+ /**
+ * @return true if will try to use external services for processing secondary
+ * structure
+ */
+ public boolean isSecStructServices()
+ {
+ return secStructServices;
+ }
+
+ /**
+ * control use of external services for processing secondary structure
+ *
+ * @param secStructServices
+ */
+ public void setSecStructServices(boolean secStructServices)
+ {
+ this.secStructServices = secStructServices;
+ }
+
+ /**
+ * flag controlling addition of any kind of structural annotation
+ *
+ * @return true if temperature factor annotation will be added
+ */
+ public boolean isAddTempFacAnnot()
+ {
+ return addTempFacAnnot;
+ }
+
+ /**
+ * set flag controlling addition of structural annotation
+ *
+ * @param addTempFacAnnot
+ */
+ public void setAddTempFacAnnot(boolean addTempFacAnnot)
+ {
+ this.addTempFacAnnot = addTempFacAnnot;
+ }
+
+ /**
+ *
+ * @return if true, the structure manager will attempt to add secondary
+ * structure lines for unannotated sequences
+ */
+
+ public boolean isProcessSecondaryStructure()
+ {
+ return processSecondaryStructure;
+ }
+
+ /**
+ * Control whether structure manager will try to annotate mapped sequences
+ * with secondary structure from PDB data.
+ *
+ * @param enable
+ */
+ public void setProcessSecondaryStructure(boolean enable)
+ {
+ processSecondaryStructure = enable;
+ }
+
+ /**
+ * debug function - write all mappings to stdout
+ */
+ public void reportMapping()
+ {
+ if (mappings.isEmpty())
+ {
+ System.err.println("reportMapping: No PDB/Sequence mappings.");
+ }
+ else
+ {
+ System.err.println("reportMapping: There are " + mappings.size()
+ + " mappings.");
+ int i = 0;
+ for (StructureMapping sm : mappings)
+ {
+ System.err.println("mapping " + i++ + " : " + sm.pdbfile);
+ }
+ }
+ }
+
+ /**
+ * map between the PDB IDs (or structure identifiers) used by Jalview and the
+ * absolute filenames for PDB data that corresponds to it
+ */
+ Map<String, String> pdbIdFileName = new HashMap<String, String>();
+
+ Map<String, String> pdbFileNameId = new HashMap<String, String>();
+
+ public void registerPDBFile(String idForFile, String absoluteFile)
+ {
+ pdbIdFileName.put(idForFile, absoluteFile);
+ pdbFileNameId.put(absoluteFile, idForFile);
+ }
+
+ public String findIdForPDBFile(String idOrFile)
+ {
+ String id = pdbFileNameId.get(idOrFile);
+ return id;
+ }
+
+ public String findFileForPDBId(String idOrFile)
+ {
+ String id = pdbIdFileName.get(idOrFile);
+ return id;
+ }
+
+ public boolean isPDBFileRegistered(String idOrFile)
+ {
+ return pdbFileNameId.containsKey(idOrFile)
+ || pdbIdFileName.containsKey(idOrFile);
+ }
+
+ private static StructureSelectionManager nullProvider = null;
+
+ public static StructureSelectionManager getStructureSelectionManager(
+ StructureSelectionManagerProvider context)
+ {
+ if (context == null)
+ {
+ if (nullProvider == null)
+ {
+ if (instances != null)
+ {
+ throw new Error(
+ MessageManager
+ .getString("error.implementation_error_structure_selection_manager_null"),
+ new NullPointerException(MessageManager
+ .getString("exception.ssm_context_is_null")));
+ }
+ else
+ {
+ nullProvider = new StructureSelectionManager();
+ }
+ return nullProvider;
+ }
+ }
+ if (instances == null)
+ {
+ instances = new java.util.IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager>();
+ }
+ StructureSelectionManager instance = instances.get(context);
+ if (instance == null)
+ {
+ if (nullProvider != null)
+ {
+ instance = nullProvider;
+ }
+ else
+ {
+ instance = new StructureSelectionManager();
+ }
+ instances.put(context, instance);
+ }
+ return instance;
+ }
+
+ /**
+ * flag controlling whether SeqMappings are relayed from received sequence
+ * mouse over events to other sequences
+ */
+ boolean relaySeqMappings = true;
+
+ /**
+ * Enable or disable relay of seqMapping events to other sequences. You might
+ * want to do this if there are many sequence mappings and the host computer
+ * is slow
+ *
+ * @param relay
+ */
+ public void setRelaySeqMappings(boolean relay)
+ {
+ relaySeqMappings = relay;
+ }
+
+ /**
+ * get the state of the relay seqMappings flag.
+ *
+ * @return true if sequence mouse overs are being relayed to other mapped
+ * sequences
+ */
+ public boolean isRelaySeqMappingsEnabled()
+ {
+ return relaySeqMappings;
+ }
+
+ Vector listeners = new Vector();
+
+ /**
+ * register a listener for alignment sequence mouseover events
+ *
+ * @param svl
+ */
+ public void addStructureViewerListener(Object svl)
+ {
+ if (!listeners.contains(svl))
+ {
+ listeners.addElement(svl);
+ }
+ }
+
+ /**
+ * Returns the file name for a mapped PDB id (or null if not mapped).
+ *
+ * @param pdbid
+ * @return
+ */
+ public String alreadyMappedToFile(String pdbid)
+ {
+ for (StructureMapping sm : mappings)
+ {
+ if (sm.getPdbId().equals(pdbid))
+ {
+ return sm.pdbfile;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Import structure data and register a structure mapping for broadcasting
+ * colouring, mouseovers and selection events (convenience wrapper).
+ *
+ * @param sequence
+ * - one or more sequences to be mapped to pdbFile
+ * @param targetChains
+ * - optional chain specification for mapping each sequence to pdb
+ * (may be nill, individual elements may be nill)
+ * @param pdbFile
+ * - structure data resource
+ * @param protocol
+ * - how to resolve data from resource
+ * @return null or the structure data parsed as a pdb file
+ */
+ synchronized public StructureFile setMapping(SequenceI[] sequence,
+ String[] targetChains, String pdbFile, String protocol,
+ IProgressIndicator progress)
+ {
+ return computeMapping(true, sequence, targetChains, pdbFile, protocol,
+ progress);
+ }
+
+
+ /**
+ * create sequence structure mappings between each sequence and the given
+ * pdbFile (retrieved via the given protocol).
+ *
+ * @param forStructureView
+ * when true, record the mapping for use in mouseOvers
+ *
+ * @param sequenceArray
+ * - one or more sequences to be mapped to pdbFile
+ * @param targetChainIds
+ * - optional chain specification for mapping each sequence to pdb
+ * (may be null, individual elements may be null)
+ * @param pdbFile
+ * - structure data resource
+ * @param protocol
+ * - how to resolve data from resource
+ * @return null or the structure data parsed as a pdb file
+ */
+ synchronized public StructureFile setMapping(boolean forStructureView,
+ SequenceI[] sequenceArray, String[] targetChainIds,
+ String pdbFile,
+ String protocol)
+ {
+ return computeMapping(forStructureView, sequenceArray, targetChainIds,
+ pdbFile, protocol, null);
+ }
+
+ synchronized public StructureFile computeMapping(
+ boolean forStructureView, SequenceI[] sequenceArray,
+ String[] targetChainIds, String pdbFile, String protocol,
+ IProgressIndicator progress)
+ {
+ long progressSessionId = System.currentTimeMillis() * 3;
+ /*
+ * There will be better ways of doing this in the future, for now we'll use
+ * the tried and tested MCview pdb mapping
+ */
+ boolean parseSecStr = processSecondaryStructure;
+ if (isPDBFileRegistered(pdbFile))
+ {
+ for (SequenceI sq : sequenceArray)
+ {
+ SequenceI ds = sq;
+ while (ds.getDatasetSequence() != null)
+ {
+ ds = ds.getDatasetSequence();
+ }
+ ;
+ if (ds.getAnnotation() != null)
+ {
+ for (AlignmentAnnotation ala : ds.getAnnotation())
+ {
+ // false if any annotation present from this structure
+ // JBPNote this fails for jmol/chimera view because the *file* is
+ // passed, not the structure data ID -
+ if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
+ {
+ parseSecStr = false;
+ }
+ }
+ }
+ }
+ }
+ StructureFile pdb = null;
+ boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
+ try
+ {
+
+ if (pdbFile != null && isCIFFile(pdbFile))
+ {
+ pdb = new jalview.ext.jmol.JmolParser(addTempFacAnnot, parseSecStr,
+ secStructServices, pdbFile, protocol);
+ }
+ else
+ {
+ pdb = new PDBfile(addTempFacAnnot, parseSecStr, secStructServices,
+ pdbFile, protocol);
+ }
+
+ if (pdb.getId() != null && pdb.getId().trim().length() > 0
+ && AppletFormatAdapter.FILE.equals(protocol))
+ {
+ registerPDBFile(pdb.getId().trim(), pdbFile);
+ }
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
+ return null;
+ }
+
+ try
+ {
+ if (isMapUsingSIFTs)
+ {
+ siftsClient = new SiftsClient(pdb);
+ }
+ } catch (SiftsException e)
+ {
+ isMapUsingSIFTs = false;
+ e.printStackTrace();
+ }
+
+ String targetChainId;
+ for (int s = 0; s < sequenceArray.length; s++)
+ {
+ boolean infChain = true;
+ final SequenceI seq = sequenceArray[s];
+ if (targetChainIds != null && targetChainIds[s] != null)
+ {
+ infChain = false;
+ targetChainId = targetChainIds[s];
+ }
+ else if (seq.getName().indexOf("|") > -1)
+ {
+ targetChainId = seq.getName().substring(
+ seq.getName().lastIndexOf("|") + 1);
+ if (targetChainId.length() > 1)
+ {
+ if (targetChainId.trim().length() == 0)
+ {
+ targetChainId = " ";
+ }
+ else
+ {
+ // not a valid chain identifier
+ targetChainId = "";
+ }
+ }
+ }
+ else
+ {
+ targetChainId = "";
+ }
+
+ /*
+ * Attempt pairwise alignment of the sequence with each chain in the PDB,
+ * and remember the highest scoring chain
+ */
+ int max = -10;
+ AlignSeq maxAlignseq = null;
+ String maxChainId = " ";
+ PDBChain maxChain = null;
+ boolean first = true;
+ for (PDBChain chain : pdb.getChains())
+ {
+ if (targetChainId.length() > 0 && !targetChainId.equals(chain.id)
+ && !infChain)
+ {
+ continue; // don't try to map chains don't match.
+ }
+ // TODO: correctly determine sequence type for mixed na/peptide
+ // structures
+ final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
+ AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
+ type);
+ // equivalent to:
+ // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
+ // as.calcScoreMatrix();
+ // as.traceAlignment();
+
+ if (first || as.maxscore > max
+ || (as.maxscore == max && chain.id.equals(targetChainId)))
+ {
+ first = false;
+ maxChain = chain;
+ max = as.maxscore;
+ maxAlignseq = as;
+ maxChainId = chain.id;
+ }
+ }
+ if (maxChain == null)
+ {
+ continue;
+ }
+
+ if (protocol.equals(jalview.io.AppletFormatAdapter.PASTE))
+ {
+ pdbFile = "INLINE" + pdb.getId();
+ }
+ ArrayList<StructureMapping> seqToStrucMapping = new ArrayList<StructureMapping>();
+ if (isMapUsingSIFTs)
+ {
+<<<<<<< Updated upstream
+ setProgressBar(null);
+ setProgressBar(MessageManager
+ .getString("status.obtaining_mapping_with_sifts"));
+=======
+ if (progress!=null) {
+ progress.setProgressBar("Obtaining mapping with SIFTS",
+ progressSessionId);
+ }
+>>>>>>> Stashed changes
+ jalview.datamodel.Mapping sqmpping = maxAlignseq
+ .getMappingFromS1(false);
+ if (targetChainId != null && !targetChainId.trim().isEmpty())
+ {
+ StructureMapping siftsMapping;
+ try
+ {
+ siftsMapping = getStructureMapping(seq, pdbFile, targetChainId,
+ pdb, maxChain, sqmpping, maxAlignseq);
+ seqToStrucMapping.add(siftsMapping);
+ maxChain.makeExactMapping(maxAlignseq, seq);
+ maxChain.transferRESNUMFeatures(seq, null);
+ maxChain.transferResidueAnnotation(siftsMapping, sqmpping);
+ } catch (SiftsException e)
+ {
+ // fall back to NW alignment
+ System.err.println(e.getMessage());
+ StructureMapping nwMapping = getNWMappings(seq, pdbFile,
+ targetChainId, maxChain, pdb, maxAlignseq);
+ seqToStrucMapping.add(nwMapping);
+ }
+ }
+ else
+ {
+ ArrayList<StructureMapping> foundSiftsMappings = new ArrayList<StructureMapping>();
+ for (PDBChain chain : pdb.getChains())
+ {
+ try
+ {
+ StructureMapping siftsMapping = getStructureMapping(seq,
+ pdbFile,
+ chain.id, pdb, chain, sqmpping, maxAlignseq);
+ foundSiftsMappings.add(siftsMapping);
+ } catch (SiftsException e)
+ {
+ System.err.println(e.getMessage());
+ }
+ }
+ if (!foundSiftsMappings.isEmpty())
+ {
+ seqToStrucMapping.addAll(foundSiftsMappings);
+ maxChain.makeExactMapping(maxAlignseq, seq);
+ maxChain.transferRESNUMFeatures(seq, null);
+ maxChain.transferResidueAnnotation(foundSiftsMappings.get(0),
+ sqmpping);
+ }
+ else
+ {
+ StructureMapping nwMapping = getNWMappings(seq, pdbFile,
+ maxChainId, maxChain, pdb, maxAlignseq);
+ seqToStrucMapping.add(nwMapping);
+ }
+ }
+ }
+ else
+ {
+<<<<<<< Updated upstream
+ setProgressBar(null);
+ setProgressBar(MessageManager
+ .getString("status.obtaining_mapping_with_nw_alignment"));
+=======
+ if (progress != null)
+ {
+ progress.setProgressBar("Obtaining mapping with NW alignment",
+ progressSessionId);
+ }
+>>>>>>> Stashed changes
+ seqToStrucMapping.add(getNWMappings(seq, pdbFile, maxChainId,
+ maxChain, pdb, maxAlignseq));
+ }
+ if (forStructureView)
+ {
+ mappings.addAll(seqToStrucMapping);
+ }
+ if (progress != null)
+ {
+ progress.setProgressBar(null, progressSessionId);
+ }
+ }
+ return pdb;
+ }
+
+ private boolean isCIFFile(String filename)
+ {
+ String fileExt = filename.substring(filename.lastIndexOf(".") + 1,
+ filename.length());
+ return "cif".equalsIgnoreCase(fileExt);
+ }
+
+ private StructureMapping getStructureMapping(SequenceI seq,
+ String pdbFile, String targetChainId, StructureFile pdb,
+ PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
+ AlignSeq maxAlignseq) throws SiftsException
+ {
+ StructureMapping curChainMapping = siftsClient
+ .getSiftsStructureMapping(seq, pdbFile, targetChainId);
+ try
+ {
+ PDBChain chain = pdb.findChain(targetChainId);
+ if (chain != null)
+ {
+ chain.transferResidueAnnotation(curChainMapping, sqmpping);
+ }
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return curChainMapping;
+ }
+
+ private StructureMapping getNWMappings(SequenceI seq,
+ String pdbFile,
+ String maxChainId, PDBChain maxChain, StructureFile pdb,
+ AlignSeq maxAlignseq)
+ {
+ final StringBuilder mappingDetails = new StringBuilder(128);
+ mappingDetails.append(NEWLINE).append(
+ "Sequence \u27f7 Structure mapping details");
+ mappingDetails.append(NEWLINE);
+ mappingDetails
+ .append("Method: inferred with Needleman & Wunsch alignment");
+ mappingDetails.append(NEWLINE).append("PDB Sequence is :")
+ .append(NEWLINE).append("Sequence = ")
+ .append(maxChain.sequence.getSequenceAsString());
+ mappingDetails.append(NEWLINE).append("No of residues = ")
+ .append(maxChain.residues.size()).append(NEWLINE)
+ .append(NEWLINE);
+ PrintStream ps = new PrintStream(System.out)
+ {
+ @Override
+ public void print(String x)
+ {
+ mappingDetails.append(x);
+ }
+
+ @Override
+ public void println()
+ {
+ mappingDetails.append(NEWLINE);
+ }
+ };
+
+ maxAlignseq.printAlignment(ps);
+
+ mappingDetails.append(NEWLINE).append("PDB start/end ");
+ mappingDetails.append(String.valueOf(maxAlignseq.seq2start))
+ .append(" ");
+ mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
+ mappingDetails.append(NEWLINE).append("SEQ start/end ");
+ mappingDetails.append(
+ String.valueOf(maxAlignseq.seq1start + (seq.getStart() - 1)))
+ .append(" ");
+ mappingDetails.append(String.valueOf(maxAlignseq.seq1end
+ + (seq.getStart() - 1)));
+ mappingDetails.append(NEWLINE);
+ maxChain.makeExactMapping(maxAlignseq, seq);
+ jalview.datamodel.Mapping sqmpping = maxAlignseq
+ .getMappingFromS1(false);
+ maxChain.transferRESNUMFeatures(seq, null);
+
+ HashMap<Integer, int[]> mapping = new HashMap<Integer, int[]>();
+ int resNum = -10000;
+ int index = 0;
+ char insCode = ' ';
+
+ do
+ {
+ Atom tmp = maxChain.atoms.elementAt(index);
+ if ((resNum != tmp.resNumber || insCode != tmp.insCode)
+ && tmp.alignmentMapping != -1)
+ {
+ resNum = tmp.resNumber;
+ insCode = tmp.insCode;
+ if (tmp.alignmentMapping >= -1)
+ {
+ mapping.put(tmp.alignmentMapping + 1, new int[] { tmp.resNumber,
+ tmp.atomIndex });
+ }
+ }
+
+ index++;
+ } while (index < maxChain.atoms.size());
+
+ StructureMapping nwMapping = new StructureMapping(seq, pdbFile,
+ pdb.getId(), maxChainId, mapping, mappingDetails.toString());
+ maxChain.transferResidueAnnotation(nwMapping, sqmpping);
+ return nwMapping;
+ }
+
+ public void removeStructureViewerListener(Object svl, String[] pdbfiles)
+ {
+ listeners.removeElement(svl);
+ if (svl instanceof SequenceListener)
+ {
+ for (int i = 0; i < listeners.size(); i++)
+ {
+ if (listeners.elementAt(i) instanceof StructureListener)
+ {
+ ((StructureListener) listeners.elementAt(i))
+ .releaseReferences(svl);
+ }
+ }
+ }
+
+ if (pdbfiles == null)
+ {
+ return;
+ }
+
+ /*
+ * Remove mappings to the closed listener's PDB files, but first check if
+ * another listener is still interested
+ */
+ List<String> pdbs = new ArrayList<String>(Arrays.asList(pdbfiles));
+
+ StructureListener sl;
+ for (int i = 0; i < listeners.size(); i++)
+ {
+ if (listeners.elementAt(i) instanceof StructureListener)
+ {
+ sl = (StructureListener) listeners.elementAt(i);
+ for (String pdbfile : sl.getPdbFile())
+ {
+ pdbs.remove(pdbfile);
+ }
+ }
+ }
+
+ /*
+ * Rebuild the mappings set, retaining only those which are for 'other' PDB
+ * files
+ */
+ if (pdbs.size() > 0)
+ {
+ List<StructureMapping> tmp = new ArrayList<StructureMapping>();
+ for (StructureMapping sm : mappings)
+ {
+ if (!pdbs.contains(sm.pdbfile))
+ {
+ tmp.add(sm);
+ }
+ }
+
+ mappings = tmp;
+ }
+ }
+
+ /**
+ * Propagate mouseover of a single position in a structure
+ *
+ * @param pdbResNum
+ * @param chain
+ * @param pdbfile
+ */
+ public void mouseOverStructure(int pdbResNum, String chain, String pdbfile)
+ {
+ AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
+ List<AtomSpec> atoms = Collections.singletonList(atomSpec);
+ mouseOverStructure(atoms);
+ }
+
+ /**
+ * Propagate mouseover or selection of multiple positions in a structure
+ *
+ * @param atoms
+ */
+ public void mouseOverStructure(List<AtomSpec> atoms)
+ {
+ if (listeners == null)
+ {
+ // old or prematurely sent event
+ return;
+ }
+ boolean hasSequenceListener = false;
+ for (int i = 0; i < listeners.size(); i++)
+ {
+ if (listeners.elementAt(i) instanceof SequenceListener)
+ {
+ hasSequenceListener = true;
+ }
+ }
+ if (!hasSequenceListener)
+ {
+ return;
+ }
+
+ SearchResults results = new SearchResults();
+ for (AtomSpec atom : atoms)
+ {
+ SequenceI lastseq = null;
+ int lastipos = -1;
+ for (StructureMapping sm : mappings)
+ {
+ if (sm.pdbfile.equals(atom.getPdbFile())
+ && sm.pdbchain.equals(atom.getChain()))
+ {
+ int indexpos = sm.getSeqPos(atom.getPdbResNum());
+ if (lastipos != indexpos && lastseq != sm.sequence)
+ {
+ results.addResult(sm.sequence, indexpos, indexpos);
+ lastipos = indexpos;
+ lastseq = sm.sequence;
+ // construct highlighted sequence list
+ for (AlignedCodonFrame acf : seqmappings)
+ {
+ acf.markMappedRegion(sm.sequence, indexpos, results);
+ }
+ }
+ }
+ }
+ }
+ for (Object li : listeners)
+ {
+ if (li instanceof SequenceListener)
+ {
+ ((SequenceListener) li).highlightSequence(results);
+ }
+ }
+ }
+
+ /**
+ * highlight regions associated with a position (indexpos) in seq
+ *
+ * @param seq
+ * the sequence that the mouse over occurred on
+ * @param indexpos
+ * the absolute position being mouseovered in seq (0 to seq.length())
+ * @param seqPos
+ * the sequence position (if -1, seq.findPosition is called to
+ * resolve the residue number)
+ */
+ public void mouseOverSequence(SequenceI seq, int indexpos, int seqPos,
+ VamsasSource source)
+ {
+ boolean hasSequenceListeners = handlingVamsasMo
+ || !seqmappings.isEmpty();
+ SearchResults results = null;
+ if (seqPos == -1)
+ {
+ seqPos = seq.findPosition(indexpos);
+ }
+ for (int i = 0; i < listeners.size(); i++)
+ {
+ Object listener = listeners.elementAt(i);
+ if (listener == source)
+ {
+ // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
+ // Temporary fudge with SequenceListener.getVamsasSource()
+ continue;
+ }
+ if (listener instanceof StructureListener)
+ {
+ highlightStructure((StructureListener) listener, seq, seqPos);
+ }
+ else
+ {
+ if (listener instanceof SequenceListener)
+ {
+ final SequenceListener seqListener = (SequenceListener) listener;
+ if (hasSequenceListeners
+ && seqListener.getVamsasSource() != source)
+ {
+ if (relaySeqMappings)
+ {
+ if (results == null)
+ {
+ results = MappingUtils.buildSearchResults(seq, seqPos,
+ seqmappings);
+ }
+ if (handlingVamsasMo)
+ {
+ results.addResult(seq, seqPos, seqPos);
+
+ }
+ if (!results.isEmpty())
+ {
+ seqListener.highlightSequence(results);
+ }
+ }
+ }
+ }
+ else if (listener instanceof VamsasListener && !handlingVamsasMo)
+ {
+ ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
+ source);
+ }
+ else if (listener instanceof SecondaryStructureListener)
+ {
+ ((SecondaryStructureListener) listener).mouseOverSequence(seq,
+ indexpos, seqPos);
+ }
+ }
+ }
+ }
+
+ /**
+ * Send suitable messages to a StructureListener to highlight atoms
+ * corresponding to the given sequence position(s)
+ *
+ * @param sl
+ * @param seq
+ * @param positions
+ */
+ public void highlightStructure(StructureListener sl, SequenceI seq,
+ int... positions)
+ {
+ if (!sl.isListeningFor(seq))
+ {
+ return;
+ }
+ int atomNo;
+ List<AtomSpec> atoms = new ArrayList<AtomSpec>();
+ for (StructureMapping sm : mappings)
+ {
+ if (sm.sequence == seq
+ || sm.sequence == seq.getDatasetSequence()
+ || (sm.sequence.getDatasetSequence() != null && sm.sequence
+ .getDatasetSequence() == seq.getDatasetSequence()))
+ {
+ for (int index : positions)
+ {
+ atomNo = sm.getAtomNum(index);
+
+ if (atomNo > 0)
+ {
+ atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain, sm
+ .getPDBResNum(index), atomNo));
+ }
+ }
+ }
+ }
+ sl.highlightAtoms(atoms);
+ }
+
+ /**
+ * true if a mouse over event from an external (ie Vamsas) source is being
+ * handled
+ */
+ boolean handlingVamsasMo = false;
+
+ long lastmsg = 0;
+
+ /**
+ * as mouseOverSequence but only route event to SequenceListeners
+ *
+ * @param sequenceI
+ * @param position
+ * in an alignment sequence
+ */
+ public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
+ VamsasSource source)
+ {
+ handlingVamsasMo = true;
+ long msg = sequenceI.hashCode() * (1 + position);
+ if (lastmsg != msg)
+ {
+ lastmsg = msg;
+ mouseOverSequence(sequenceI, position, -1, source);
+ }
+ handlingVamsasMo = false;
+ }
+
+ public Annotation[] colourSequenceFromStructure(SequenceI seq,
+ String pdbid)
+ {
+ return null;
+ // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
+ // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
+ /*
+ * Annotation [] annotations = new Annotation[seq.getLength()];
+ *
+ * StructureListener sl; int atomNo = 0; for (int i = 0; i <
+ * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
+ * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
+ *
+ * for (int j = 0; j < mappings.length; j++) {
+ *
+ * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
+ * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
+ * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
+ * "+mappings[j].pdbfile);
+ *
+ * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
+ * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
+ *
+ * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
+ * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
+ * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
+ * mappings[j].pdbfile); }
+ *
+ * annotations[index] = new Annotation("X",null,' ',0,col); } return
+ * annotations; } } } }
+ *
+ * return annotations;
+ */
+ }
+
+ public void structureSelectionChanged()
+ {
+ }
+
+ public void sequenceSelectionChanged()
+ {
+ }
+
+ public void sequenceColoursChanged(Object source)
+ {
+ StructureListener sl;
+ for (int i = 0; i < listeners.size(); i++)
+ {
+ if (listeners.elementAt(i) instanceof StructureListener)
+ {
+ sl = (StructureListener) listeners.elementAt(i);
+ sl.updateColours(source);
+ }
+ }
+ }
+
+ public StructureMapping[] getMapping(String pdbfile)
+ {
+ List<StructureMapping> tmp = new ArrayList<StructureMapping>();
+ for (StructureMapping sm : mappings)
+ {
+ if (sm.pdbfile.equals(pdbfile))
+ {
+ tmp.add(sm);
+ }
+ }
+ return tmp.toArray(new StructureMapping[tmp.size()]);
+ }
+
+ /**
+ * Returns a readable description of all mappings for the given pdbfile to any
+ * of the given sequences
+ *
+ * @param pdbfile
+ * @param seqs
+ * @return
+ */
+ public String printMappings(String pdbfile, List<SequenceI> seqs)
+ {
+ if (pdbfile == null || seqs == null || seqs.isEmpty())
+ {
+ return "";
+ }
+
+ StringBuilder sb = new StringBuilder(64);
+ for (StructureMapping sm : mappings)
+ {
+ if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
+ {
+ sb.append(sm.mappingDetails);
+ sb.append(NEWLINE);
+ // separator makes it easier to read multiple mappings
+ sb.append("=====================");
+ sb.append(NEWLINE);
+ }
+ }
+ sb.append(NEWLINE);
+
+ return sb.toString();
+ }
+
+ /**
+ * Remove the given mapping
+ *
+ * @param acf
+ */
+ public void deregisterMapping(AlignedCodonFrame acf)
+ {
+ if (acf != null)
+ {
+ boolean removed = seqmappings.remove(acf);
+ if (removed && seqmappings.isEmpty())
+ { // debug
+ System.out.println("All mappings removed");
+ }
+ }
+ }
+
+ /**
+ * Add each of the given codonFrames to the stored set, if not aready present.
+ *
+ * @param mappings
+ */
+ public void registerMappings(List<AlignedCodonFrame> mappings)
+ {
+ if (mappings != null)
+ {
+ for (AlignedCodonFrame acf : mappings)
+ {
+ registerMapping(acf);
+ }
+ }
+ }
+
+ /**
+ * Add the given mapping to the stored set, unless already stored.
+ */
+ public void registerMapping(AlignedCodonFrame acf)
+ {
+ if (acf != null)
+ {
+ if (!seqmappings.contains(acf))
+ {
+ seqmappings.add(acf);
+ }
+ }
+ }
+
+ /**
+ * Resets this object to its initial state by removing all registered
+ * listeners, codon mappings, PDB file mappings
+ */
+ public void resetAll()
+ {
+ if (mappings != null)
+ {
+ mappings.clear();
+ }
+ if (seqmappings != null)
+ {
+ seqmappings.clear();
+ }
+ if (sel_listeners != null)
+ {
+ sel_listeners.clear();
+ }
+ if (listeners != null)
+ {
+ listeners.clear();
+ }
+ if (commandListeners != null)
+ {
+ commandListeners.clear();
+ }
+ if (view_listeners != null)
+ {
+ view_listeners.clear();
+ }
+ if (pdbFileNameId != null)
+ {
+ pdbFileNameId.clear();
+ }
+ if (pdbIdFileName != null)
+ {
+ pdbIdFileName.clear();
+ }
+ }
+
+ public void addSelectionListener(SelectionListener selecter)
+ {
+ if (!sel_listeners.contains(selecter))
+ {
+ sel_listeners.add(selecter);
+ }
+ }
+
+ public void removeSelectionListener(SelectionListener toremove)
+ {
+ if (sel_listeners.contains(toremove))
+ {
+ sel_listeners.remove(toremove);
+ }
+ }
+
+ public synchronized void sendSelection(
+ jalview.datamodel.SequenceGroup selection,
+ jalview.datamodel.ColumnSelection colsel, SelectionSource source)
+ {
+ for (SelectionListener slis : sel_listeners)
+ {
+ if (slis != source)
+ {
+ slis.selection(selection, colsel, source);
+ }
+ }
+ }
+
+ Vector<AlignmentViewPanelListener> view_listeners = new Vector<AlignmentViewPanelListener>();
+
+ public synchronized void sendViewPosition(
+ jalview.api.AlignmentViewPanel source, int startRes, int endRes,
+ int startSeq, int endSeq)
+ {
+
+ if (view_listeners != null && view_listeners.size() > 0)
+ {
+ Enumeration<AlignmentViewPanelListener> listeners = view_listeners
+ .elements();
+ while (listeners.hasMoreElements())
+ {
+ AlignmentViewPanelListener slis = listeners.nextElement();
+ if (slis != source)
+ {
+ slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
+ }
+ ;
+ }
+ }
+ }
+
+ /**
+ * release all references associated with this manager provider
+ *
+ * @param jalviewLite
+ */
+ public static void release(StructureSelectionManagerProvider jalviewLite)
+ {
+ // synchronized (instances)
+ {
+ if (instances == null)
+ {
+ return;
+ }
+ StructureSelectionManager mnger = (instances.get(jalviewLite));
+ if (mnger != null)
+ {
+ instances.remove(jalviewLite);
+ try
+ {
+ mnger.finalize();
+ } catch (Throwable x)
+ {
+ }
+ }
+ }
+ }
+
+ public void registerPDBEntry(PDBEntry pdbentry)
+ {
+ if (pdbentry.getFile() != null
+ && pdbentry.getFile().trim().length() > 0)
+ {
+ registerPDBFile(pdbentry.getId(), pdbentry.getFile());
+ }
+ }
+
+ public void addCommandListener(CommandListener cl)
+ {
+ if (!commandListeners.contains(cl))
+ {
+ commandListeners.add(cl);
+ }
+ }
+
+ public boolean hasCommandListener(CommandListener cl)
+ {
+ return this.commandListeners.contains(cl);
+ }
+
+ public boolean removeCommandListener(CommandListener l)
+ {
+ return commandListeners.remove(l);
+ }
+
+ /**
+ * Forward a command to any command listeners (except for the command's
+ * source).
+ *
+ * @param command
+ * the command to be broadcast (in its form after being performed)
+ * @param undo
+ * if true, the command was being 'undone'
+ * @param source
+ */
+ public void commandPerformed(CommandI command, boolean undo,
+ VamsasSource source)
+ {
+ for (CommandListener listener : commandListeners)
+ {
+ listener.mirrorCommand(command, undo, this, source);
+ }
+ }
+
+ /**
+ * Returns a new CommandI representing the given command as mapped to the
+ * given sequences. If no mapping could be made, or the command is not of a
+ * mappable kind, returns null.
+ *
+ * @param command
+ * @param undo
+ * @param mapTo
+ * @param gapChar
+ * @return
+ */
+ public CommandI mapCommand(CommandI command, boolean undo,
+ final AlignmentI mapTo, char gapChar)
+ {
+ if (command instanceof EditCommand)
+ {
+ return MappingUtils.mapEditCommand((EditCommand) command, undo,
+ mapTo, gapChar, seqmappings);
+ }
+ else if (command instanceof OrderCommand)
+ {
+ return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
+ mapTo, seqmappings);
+ }
+ return null;
+ }
+
+ public List<AlignedCodonFrame> getSequenceMappings()
+ {
+ return seqmappings;
+ }
+
+}
package jalview.structures.models;
import jalview.api.AlignmentViewPanel;
-import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.api.StructureSelectionManagerProvider;
import jalview.api.structures.JalviewStructureDisplayI;
import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
import jalview.io.DataSourceType;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.List;
/**
* the sequence alignment which is the basis of structure
* superposition
* @param matched
- * an array of booleans, indexed by alignment column, where true
- * indicates that every structure has a mapped residue present in the
- * column (so the column can participate in structure alignment)
+ * a BitSet, where bit j is set to indicate that every structure has
+ * a mapped residue present in column j (so the column can
+ * participate in structure alignment)
* @param structures
* an array of data beans corresponding to pdb file index
* @return
*/
protected int findSuperposableResidues(AlignmentI alignment,
- boolean[] matched, SuperposeData[] structures)
+ BitSet matched, SuperposeData[] structures)
{
int refStructure = -1;
- String[] files = getPdbFile();
+ String[] files = getStructureFiles();
if (files == null)
{
return -1;
{
refStructure = pdbfnum;
}
- for (int r = 0; r < matched.length; r++)
+ for (int r = 0; r < alignment.getWidth(); r++)
{
- if (!matched[r])
+ if (!matched.get(r))
{
continue;
}
int pos = getMappedPosition(theSequence, r, mapping);
if (pos < 1 || pos == lastPos)
{
- matched[r] = false;
+ matched.clear(r);
continue;
}
lastPos = pos;
public abstract void setJalviewColourScheme(ColourSchemeI cs);
- public abstract void superposeStructures(AlignmentI[] als, int[] alm,
- ColumnSelection[] alc);
-
- public abstract void setBackgroundColour(Color col);
-
- protected abstract StructureMappingcommandSet[] getColourBySequenceCommands(
- String[] files, SequenceRenderer sr, FeatureRenderer fr,
- AlignmentI alignment);
-
/**
- * returns the current featureRenderer that should be used to colour the
- * structures
- *
- * @param alignment
+ * Constructs and sends a command to align structures against a reference
+ * structure, based on one or more sequence alignments. May optionally return
+ * an error or warning message for the alignment command.
*
+ * @param alignments
+ * an array of alignments to process
+ * @param structureIndices
+ * an array of corresponding reference structures (index into pdb
+ * file array); if a negative value is passed, the first PDB file
+ * mapped to an alignment sequence is used as the reference for
+ * superposition
+ * @param hiddenCols
+ * an array of corresponding hidden columns for each alignment
* @return
*/
- public abstract FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment);
+ public abstract String superposeStructures(AlignmentI[] alignments,
+ int[] structureIndices, HiddenColumns[] hiddenCols);
+
+ public abstract void setBackgroundColour(Color col);
+
+ protected abstract StructureMappingcommandSet[] getColourBySequenceCommands(
+ String[] files, SequenceRenderer sr, AlignmentViewPanel avp);
/**
* returns the current sequenceRenderer that should be used to colour the
*/
public void colourBySequence(AlignmentViewPanel alignmentv)
{
- boolean showFeatures = alignmentv.getAlignViewport()
- .isShowSequenceFeatures();
if (!colourBySequence || !isLoadingFinished())
{
return;
{
return;
}
- String[] files = getPdbFile();
+ String[] files = getStructureFiles();
SequenceRenderer sr = getSequenceRenderer(alignmentv);
- FeatureRenderer fr = null;
- if (showFeatures)
- {
- fr = getFeatureRenderer(alignmentv);
- }
- AlignmentI alignment = alignmentv.getAlignment();
-
StructureMappingcommandSet[] colourBySequenceCommands = getColourBySequenceCommands(
- files, sr, fr, alignment);
+ files, sr, alignmentv);
colourBySequence(colourBySequenceCommands);
}
{
return fileLoadingError != null && fileLoadingError.length() > 0;
}
+
+ public abstract jalview.api.FeatureRenderer getFeatureRenderer(
+ AlignmentViewPanel alignment);
}
public class UrlLinkDisplay
{
- private String id; // id is not supplied to display, but used to identify
- // entries when saved
+ // column positions
+ public static final int DATABASE = 0;
- private boolean isPrimary;
+ public static final int NAME = 1;
- private boolean isSelected;
+ public static final int URL = 2;
- private UrlLink link;
+ public static final int SELECTED = 3;
+
+ public static final int PRIMARY = 4;
+
+ public static final int ID = 5;
// Headers for columns in table
- private final static List<String> colNames = new ArrayList<String>()
+ @SuppressWarnings("serial")
+ private static final List<String> COLNAMES = new ArrayList<String>()
{
{
add(MessageManager.formatMessage("label.database"));
}
};
- // column positions
- public final static int DATABASE = 0;
-
- public final static int NAME = 1;
-
- public final static int URL = 2;
+ private String id; // id is not supplied to display, but used to identify
+ // entries when saved
- public final static int SELECTED = 3;
+ private boolean isPrimary;
- public final static int PRIMARY = 4;
+ private boolean isSelected;
- public final static int ID = 5;
+ private UrlLink link;
public UrlLinkDisplay(String rowId, UrlLink rowLink,
boolean rowSelected, boolean rowDefault)
break;
case NAME:
setDescription((String) value);
+ // deliberate fall through
case DATABASE:
setDBName((String) value);
break;
// so only allow editing if it is not
return (!link.usesDBAccession());
}
- else if (index == SELECTED)
- {
- return true;
- }
else
{
- return false;
+ return index == SELECTED;
}
}
public static List<String> getDisplayColumnNames()
{
// Display names between DESCRIPTION and ID (excludes ID)
- return colNames.subList(DATABASE, ID);
+ return COLNAMES.subList(DATABASE, ID);
}
}
private static final int TO_UPPER_CASE = 'a' - 'A';
- private static final char GAP_SPACE = ' ';
+ public static final char GAP_SPACE = ' ';
- private static final char GAP_DOT = '.';
+ public static final char GAP_DOT = '.';
- private static final char GAP_DASH = '-';
+ public static final char GAP_DASH = '-';
public static final String GapChars = new String(new char[] { GAP_SPACE,
GAP_DOT, GAP_DASH });
* @param s2
* SequenceI
* @return float
+ * @deprecated use PIDModel.computePID()
*/
+ @Deprecated
public final static float PID(String seq1, String seq2)
{
return PID(seq1, seq2, 0, seq1.length());
static final int caseShift = 'a' - 'A';
// Another pid with region specification
+ /**
+ * @deprecated use PIDModel.computePID()
+ */
+ @Deprecated
public final static float PID(String seq1, String seq2, int start, int end)
{
return PID(seq1, seq2, start, end, true, false);
* @param ungappedOnly
* - if true - only count PID over ungapped columns
* @return
+ * @deprecated use PIDModel.computePID()
*/
+ @Deprecated
public final static float PID(String seq1, String seq2, int start,
int end, boolean wcGaps, boolean ungappedOnly)
{
*/
public class LinkedIdentityHashSet<E> extends AbstractSet<E>
{
- LinkedHashMap<IdentityWrapper, IdentityWrapper> set = new LinkedHashMap<IdentityWrapper, IdentityWrapper>();
+ LinkedHashMap<IdentityWrapper, IdentityWrapper> set = new LinkedHashMap<>();
static class IdentityWrapper
{
@Override
public boolean equals(Object obj)
{
- return this.obj == obj;
+ return this.obj == ((IdentityWrapper) obj).obj;
}
@Override
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentOrder;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SearchResultMatchI;
import jalview.datamodel.SearchResults;
import jalview.datamodel.SearchResultsI;
* @param mapTo
* @return
*/
- public static ColumnSelection mapColumnSelection(ColumnSelection colsel,
- AlignViewportI mapFrom, AlignViewportI mapTo)
+ public static void mapColumnSelection(ColumnSelection colsel,
+ HiddenColumns hiddencols, AlignViewportI mapFrom,
+ AlignViewportI mapTo, ColumnSelection newColSel,
+ HiddenColumns newHidden)
{
boolean targetIsNucleotide = mapTo.isNucleotide();
AlignViewportI protein = targetIsNucleotide ? mapFrom : mapTo;
List<AlignedCodonFrame> codonFrames = protein.getAlignment()
.getCodonFrames();
- ColumnSelection mappedColumns = new ColumnSelection();
+ // ColumnSelection mappedColumns = new ColumnSelection();
if (colsel == null)
{
- return mappedColumns;
+ return; // mappedColumns;
}
char fromGapChar = mapFrom.getAlignment().getGapCharacter();
for (Integer sel : colsel.getSelected())
{
- mapColumn(sel.intValue(), codonFrames, mappedColumns, fromSequences,
+ mapColumn(sel.intValue(), codonFrames, newColSel, fromSequences,
toSequences, fromGapChar);
}
- for (int[] hidden : colsel.getHiddenColumns())
+ for (int[] hidden : hiddencols.getHiddenRegions())
{
- mapHiddenColumns(hidden, codonFrames, mappedColumns, fromSequences,
+ mapHiddenColumns(hidden, codonFrames, newHidden, fromSequences,
toSequences, fromGapChar);
}
- return mappedColumns;
+ return; // mappedColumns;
}
/**
* @param fromGapChar
*/
protected static void mapHiddenColumns(int[] hidden,
- List<AlignedCodonFrame> mappings, ColumnSelection mappedColumns,
+ List<AlignedCodonFrame> mappings, HiddenColumns mappedColumns,
List<SequenceI> fromSequences, List<SequenceI> toSequences,
char fromGapChar)
{
--- /dev/null
+package jalview.util;
+
+import java.util.Comparator;
+
+/**
+ * A comparator to order [from, to] ranges into ascending or descending order of
+ * their start position
+ */
+public class RangeComparator implements Comparator<int[]>
+{
+ boolean forwards;
+
+ public RangeComparator(boolean forward)
+ {
+ forwards = forward;
+ }
+
+ @Override
+ public int compare(int[] o1, int[] o2)
+ {
+ int compared = Integer.compare(o1[0], o2[0]);
+ return forwards ? compared : -compared;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package jalview.util;
+
+import java.util.Set;
+
+public class SetUtils
+{
+ /**
+ * Returns the count of things that are in one or other of two sets but not in
+ * both. The sets are not modified.
+ *
+ * @param set1
+ * @param set2
+ * @return
+ */
+ public static int countDisjunction(Set<? extends Object> set1,
+ Set<? extends Object> set2)
+ {
+ if (set1 == null)
+ {
+ return set2 == null ? 0 : set2.size();
+ }
+ if (set2 == null)
+ {
+ return set1.size();
+ }
+
+ int size1 = set1.size();
+ int size2 = set2.size();
+ Set<? extends Object> smallerSet = size1 < size2 ? set1 : set2;
+ Set<? extends Object> largerSet = (smallerSet == set1 ? set2 : set1);
+ int inCommon = 0;
+ for (Object k : smallerSet)
+ {
+ if (largerSet.contains(k))
+ {
+ inCommon++;
+ }
+ }
+
+ int notInCommon = (size1 - inCommon) + (size2 - inCommon);
+ return notInCommon;
+ }
+}
--- /dev/null
+package jalview.util;
+
+import jalview.ext.android.SparseIntArray;
+import jalview.ext.android.SparseShortArray;
+
+/**
+ * A class to count occurrences of characters with minimal memory footprint.
+ * Sparse arrays of short values are used to hold the counts, with automatic
+ * promotion to arrays of int if any count exceeds the maximum value for a
+ * short.
+ *
+ * @author gmcarstairs
+ *
+ */
+public class SparseCount
+{
+ private static final int DEFAULT_PROFILE_SIZE = 2;
+
+ /*
+ * array of keys (chars) and values (counts)
+ * held either as shorts or (if shorts overflow) as ints
+ */
+ private SparseShortArray shortProfile;
+
+ private SparseIntArray intProfile;
+
+ /*
+ * flag is set true after short overflow occurs
+ */
+ private boolean useInts;
+
+ /**
+ * Constructor which initially creates a new sparse array of short values to
+ * hold counts.
+ *
+ * @param profileSize
+ */
+ public SparseCount(int profileSize)
+ {
+ this.shortProfile = new SparseShortArray(profileSize);
+ }
+
+ /**
+ * Constructor which allocates an initial count array for only two distinct
+ * values (the array will grow if needed)
+ */
+ public SparseCount()
+ {
+ this(DEFAULT_PROFILE_SIZE);
+ }
+
+ /**
+ * Adds the given value for the given key (or sets the initial value), and
+ * returns the new value
+ *
+ * @param key
+ * @param value
+ */
+ public int add(int key, int value)
+ {
+ int newValue = 0;
+ if (useInts)
+ {
+ newValue = intProfile.add(key, value);
+ }
+ else
+ {
+ try {
+ newValue = shortProfile.add(key, value);
+ } catch (ArithmeticException e) {
+ handleOverflow();
+ newValue = intProfile.add(key, value);
+ }
+ }
+ return newValue;
+ }
+
+ /**
+ * Switch from counting shorts to counting ints
+ */
+ synchronized void handleOverflow()
+ {
+ int size = shortProfile.size();
+ intProfile = new SparseIntArray(size);
+ for (int i = 0; i < size; i++)
+ {
+ short key = shortProfile.keyAt(i);
+ short value = shortProfile.valueAt(i);
+ intProfile.put(key, value);
+ }
+ shortProfile = null;
+ useInts = true;
+ }
+
+ /**
+ * Returns the size of the profile (number of distinct items counted)
+ *
+ * @return
+ */
+ public int size()
+ {
+ return useInts ? intProfile.size() : shortProfile.size();
+ }
+
+ /**
+ * Returns the value for the key (zero if no such key)
+ *
+ * @param key
+ * @return
+ */
+ public int get(int key)
+ {
+ return useInts ? intProfile.get(key) : shortProfile.get(key);
+ }
+
+ /**
+ * Sets the value for the given key
+ *
+ * @param key
+ * @param value
+ */
+ public void put(int key, int value)
+ {
+ if (useInts)
+ {
+ intProfile.put(key, value);
+ }
+ else
+ {
+ shortProfile.put(key, value);
+ }
+ }
+
+ public int keyAt(int k)
+ {
+ return useInts ? intProfile.keyAt(k) : shortProfile.keyAt(k);
+ }
+
+ public int valueAt(int k)
+ {
+ return useInts ? intProfile.valueAt(k) : shortProfile.valueAt(k);
+ }
+
+ /**
+ * Answers true if this object wraps arrays of int values, false if using
+ * short values
+ *
+ * @return
+ */
+ boolean isUsingInt()
+ {
+ return useInts;
+ }
+}
import jalview.datamodel.CigarArray;
import jalview.datamodel.ColumnSelection;
import jalview.datamodel.ContactListI;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.HiddenSequences;
import jalview.datamodel.ProfilesI;
import jalview.datamodel.SearchResultsI;
import jalview.util.Comparison;
import jalview.util.MapList;
import jalview.util.MappingUtils;
+import jalview.util.MessageManager;
import jalview.viewmodel.styles.ViewStyle;
import jalview.workers.AlignCalcManager;
import jalview.workers.ComplementConsensusThread;
public abstract class AlignmentViewport implements AlignViewportI,
CommandListener, VamsasSource
{
+ final protected ViewportRanges ranges;
+
protected ViewStyleI viewStyle = new ViewStyle();
/**
FeaturesDisplayedI featuresDisplayed = null;
- protected Deque<CommandI> historyList = new ArrayDeque<CommandI>();
+ protected Deque<CommandI> historyList = new ArrayDeque<>();
+
+ protected Deque<CommandI> redoList = new ArrayDeque<>();
- protected Deque<CommandI> redoList = new ArrayDeque<CommandI>();
+ /**
+ * alignment displayed in the viewport. Please use get/setter
+ */
+ protected AlignmentI alignment;
+
+ public AlignmentViewport(AlignmentI al)
+ {
+ setAlignment(al);
+ ranges = new ViewportRanges(al);
+ }
/**
* @param name
viewStyle.setSeqNameItalics(default1);
}
- /**
- * alignment displayed in the viewport. Please use get/setter
- */
- protected AlignmentI alignment;
+
@Override
public AlignmentI getAlignment()
protected boolean ignoreGapsInConsensusCalculation = false;
- protected ResidueShaderI residueShading;
+ protected ResidueShaderI residueShading = new ResidueShader();
@Override
public void setGlobalColourScheme(ColourSchemeI cs)
protected AlignmentAnnotation complementConsensus;
+ protected AlignmentAnnotation gapcounts;
+
protected AlignmentAnnotation strucConsensus;
protected AlignmentAnnotation conservation;
}
@Override
+ public AlignmentAnnotation getAlignmentGapAnnotation()
+ {
+ return gapcounts;
+ }
+
+ @Override
public AlignmentAnnotation getComplementConsensusAnnotation()
{
return complementConsensus;
}
}
- public void setHiddenColumns(ColumnSelection colsel)
+ public void setHiddenColumns(HiddenColumns hidden)
{
- this.colSel = colsel;
+ this.alignment.setHiddenColumns(hidden);
}
@Override
@Override
public boolean hasHiddenColumns()
{
- return colSel != null && colSel.hasHiddenColumns();
+ return colSel != null
+ && alignment.getHiddenColumns().hasHiddenColumns();
}
public void updateHiddenColumns()
protected boolean showConsensus = true;
- private Map<SequenceI, Color> sequenceColours = new HashMap<SequenceI, Color>();
+ protected boolean showOccupancy = true;
+
+ private Map<SequenceI, Color> sequenceColours = new HashMap<>();
protected SequenceAnnotationOrder sortAnnotationsBy = null;
*/
private boolean followHighlight = true;
- // TODO private with getters and setters?
- public int startRes;
-
- public int endRes;
-
- public int startSeq;
-
- public int endSeq;
-
/**
* Property change listener for changes in alignment
*
return;
}
- colSel.hideSelectedColumns();
+ colSel.hideSelectedColumns(alignment);
setSelectionGroup(null);
isColSelChanged(true);
}
{
if (start == end)
{
- colSel.hideColumns(start);
+ colSel.hideSelectedColumns(start, alignment.getHiddenColumns());
}
else
{
- colSel.hideColumns(start, end);
+ alignment.getHiddenColumns().hideColumns(start, end);
}
isColSelChanged(true);
}
public void showColumn(int col)
{
- colSel.revealHiddenColumns(col);
+ alignment.getHiddenColumns().revealHiddenColumns(col, colSel);
isColSelChanged(true);
}
public void showAllHiddenColumns()
{
- colSel.revealAllHiddenColumns();
+ alignment.getHiddenColumns().revealAllHiddenColumns(colSel);
isColSelChanged(true);
}
if (hiddenRepSequences == null)
{
- hiddenRepSequences = new Hashtable<SequenceI, SequenceCollectionI>();
+ hiddenRepSequences = new Hashtable<>();
}
hiddenRepSequences.put(repSequence, sg);
@Override
public void invertColumnSelection()
{
- colSel.invertColumnSelection(0, alignment.getWidth());
+ colSel.invertColumnSelection(0, alignment.getWidth(), alignment);
}
@Override
@Override
public CigarArray getViewAsCigars(boolean selectedRegionOnly)
{
- return new CigarArray(alignment, colSel,
+ return new CigarArray(alignment, alignment.getHiddenColumns(),
(selectedRegionOnly ? selectionGroup : null));
}
public jalview.datamodel.AlignmentView getAlignmentView(
boolean selectedOnly, boolean markGroups)
{
- return new AlignmentView(alignment, colSel, selectionGroup,
- colSel != null && colSel.hasHiddenColumns(), selectedOnly,
+ return new AlignmentView(alignment, alignment.getHiddenColumns(),
+ selectionGroup, alignment.getHiddenColumns() != null
+ && alignment.getHiddenColumns().hasHiddenColumns(),
+ selectedOnly,
markGroups);
}
}
selection = new String[iSize];
- if (colSel != null && colSel.hasHiddenColumns())
+ if (alignment.getHiddenColumns() != null
+ && alignment.getHiddenColumns().hasHiddenColumns())
{
- selection = colSel.getVisibleSequenceStrings(start, end, seqs);
+ selection = alignment.getHiddenColumns().getVisibleSequenceStrings(
+ start, end, seqs);
}
else
{
@Override
public List<int[]> getVisibleRegionBoundaries(int min, int max)
{
- ArrayList<int[]> regions = new ArrayList<int[]>();
+ ArrayList<int[]> regions = new ArrayList<>();
int start = min;
int end = max;
do
{
- if (colSel != null && colSel.hasHiddenColumns())
+ HiddenColumns hidden = alignment.getHiddenColumns();
+ if (hidden != null && hidden.hasHiddenColumns())
{
if (start == 0)
{
- start = colSel.adjustForHiddenColumns(start);
+ start = hidden.adjustForHiddenColumns(start);
}
- end = colSel.getHiddenBoundaryRight(start);
+ end = hidden.getHiddenBoundaryRight(start);
if (start == end)
{
end = max;
regions.add(new int[] { start, end });
- if (colSel != null && colSel.hasHiddenColumns())
+ if (hidden != null && hidden.hasHiddenColumns())
{
- start = colSel.adjustForHiddenColumns(end);
- start = colSel.getHiddenBoundaryLeft(start) + 1;
+ start = hidden.adjustForHiddenColumns(end);
+ start = hidden.getHiddenBoundaryLeft(start) + 1;
}
} while (end < max);
public List<AlignmentAnnotation> getVisibleAlignmentAnnotation(
boolean selectedOnly)
{
- ArrayList<AlignmentAnnotation> ala = new ArrayList<AlignmentAnnotation>();
+ ArrayList<AlignmentAnnotation> ala = new ArrayList<>();
AlignmentAnnotation[] aa;
if ((aa = alignment.getAlignmentAnnotation()) != null)
{
AlignmentAnnotation clone = new AlignmentAnnotation(annot);
if (selectedOnly && selectionGroup != null)
{
- colSel.makeVisibleAnnotation(selectionGroup.getStartRes(),
+ alignment.getHiddenColumns().makeVisibleAnnotation(
+ selectionGroup.getStartRes(),
selectionGroup.getEndRes(), clone);
}
else
{
- colSel.makeVisibleAnnotation(clone);
+ alignment.getHiddenColumns().makeVisibleAnnotation(clone);
}
ala.add(clone);
}
{
initRNAStructure();
}
- consensus = new AlignmentAnnotation("Consensus", "PID",
+ consensus = new AlignmentAnnotation("Consensus",
+ MessageManager.getString("label.consensus_descr"),
new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
initConsensus(consensus);
+ initGapCounts();
initComplementConsensus();
}
}
/**
- * If this is a protein alignment and there are mappings to cDNA, add the cDNA
- * consensus annotation.
+ * If this is a protein alignment and there are mappings to cDNA, adds the
+ * cDNA consensus annotation and returns true, else returns false.
*/
- public void initComplementConsensus()
+ public boolean initComplementConsensus()
{
if (!alignment.isNucleotide())
{
if (doConsensus)
{
complementConsensus = new AlignmentAnnotation("cDNA Consensus",
- "PID for cDNA", new Annotation[1], 0f, 100f,
+ MessageManager
+ .getString("label.complement_consensus_descr"),
+ new Annotation[1], 0f, 100f,
AlignmentAnnotation.BAR_GRAPH);
initConsensus(complementConsensus);
+ return true;
}
}
}
+ return false;
}
private void initConsensus(AlignmentAnnotation aa)
}
}
+ // these should be extracted from the view model - style and settings for
+ // derived annotation
+ private void initGapCounts()
+ {
+ if (showOccupancy)
+ {
+ gapcounts = new AlignmentAnnotation("Occupancy",
+ MessageManager.getString("label.occupancy_descr"),
+ new Annotation[1], 0f,
+ alignment.getHeight(), AlignmentAnnotation.BAR_GRAPH);
+ gapcounts.hasText = true;
+ gapcounts.autoCalculated = true;
+ gapcounts.scaleColLabel = true;
+ gapcounts.graph = AlignmentAnnotation.BAR_GRAPH;
+
+ alignment.addAnnotation(gapcounts);
+ }
+ }
+
private void initConservation()
{
if (showConservation)
if (conservation == null)
{
conservation = new AlignmentAnnotation("Conservation",
- "Conservation of total alignment less than "
- + getConsPercGaps() + "% gaps", new Annotation[1],
+ MessageManager.formatMessage("label.conservation_descr",
+ getConsPercGaps()), new Annotation[1],
0f, 11f, AlignmentAnnotation.BAR_GRAPH);
conservation.hasText = true;
conservation.autoCalculated = true;
if (quality == null)
{
quality = new AlignmentAnnotation("Quality",
- "Alignment Quality based on Blosum62 scores",
+ MessageManager.getString("label.quality_descr"),
new Annotation[1], 0f, 11f, AlignmentAnnotation.BAR_GRAPH);
quality.hasText = true;
quality.autoCalculated = true;
{
if (alignment.hasRNAStructure() && strucConsensus == null)
{
- strucConsensus = new AlignmentAnnotation("StrucConsensus", "PID",
+ strucConsensus = new AlignmentAnnotation("StrucConsensus",
+ MessageManager.getString("label.strucconsensus_descr"),
new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
strucConsensus.hasText = true;
strucConsensus.autoCalculated = true;
// intersect alignment annotation with alignment groups
AlignmentAnnotation[] aan = alignment.getAlignmentAnnotation();
- List<SequenceGroup> oldrfs = new ArrayList<SequenceGroup>();
+ List<SequenceGroup> oldrfs = new ArrayList<>();
if (aan != null)
{
for (int an = 0; an < aan.length; an++)
viewStyle.setScaleProteinAsCdna(b);
}
+ @Override
+ public boolean isProteinFontAsCdna()
+ {
+ return viewStyle.isProteinFontAsCdna();
+ }
+
+ @Override
+ public void setProteinFontAsCdna(boolean b)
+ {
+ viewStyle.setProteinFontAsCdna(b);
+ }
+
/**
* @return true if view should scroll to show the highlighted region of a
* sequence
this.followHighlight = b;
}
- public int getStartRes()
- {
- return startRes;
- }
-
@Override
- public int getEndRes()
- {
- return endRes;
- }
-
- public int getStartSeq()
- {
- return startSeq;
- }
-
- public void setStartRes(int res)
- {
- this.startRes = res;
- }
-
- public void setStartSeq(int seq)
- {
- this.startSeq = seq;
- }
-
- public void setEndRes(int res)
+ public ViewportRanges getRanges()
{
- if (res > alignment.getWidth() - 1)
- {
- // log.System.out.println(" Corrected res from " + res + " to maximum " +
- // (alignment.getWidth()-1));
- res = alignment.getWidth() - 1;
- }
- if (res < 0)
- {
- res = 0;
- }
- this.endRes = res;
- }
-
- public void setEndSeq(int seq)
- {
- if (seq > alignment.getHeight())
- {
- seq = alignment.getHeight();
- }
- if (seq < 0)
- {
- seq = 0;
- }
- this.endSeq = seq;
- }
-
- public int getEndSeq()
- {
- return endSeq;
+ return ranges;
}
/**
* locate 'middle' column (true middle if an odd number visible, left of
* middle if an even number visible)
*/
- int middleColumn = getStartRes() + (getEndRes() - getStartRes()) / 2;
+ int middleColumn = ranges.getStartRes()
+ + (ranges.getEndRes() - ranges.getStartRes()) / 2;
final HiddenSequences hiddenSequences = getAlignment()
.getHiddenSequences();
*/
int lastSeq = alignment.getHeight() - 1;
List<AlignedCodonFrame> seqMappings = null;
- for (int seqNo = getStartSeq(); seqNo < lastSeq; seqNo++, seqOffset++)
+ for (int seqNo = ranges.getStartSeq(); seqNo < lastSeq; seqNo++, seqOffset++)
{
sequence = getAlignment().getSequenceAt(seqNo);
if (hiddenSequences != null && hiddenSequences.isHidden(sequence))
*/
private boolean selectionIsDefinedGroup = false;
-
@Override
public boolean isSelectionDefinedGroup()
{
selectionIsDefinedGroup = gps.contains(selectionGroup);
}
}
- return selectionGroup.getContext() == alignment
- || selectionIsDefinedGroup;
+ return selectionGroup.isDefined() || selectionIsDefinedGroup;
}
/**
--- /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.
+ */
+package jalview.viewmodel;
+
+import jalview.api.AlignmentColsCollectionI;
+import jalview.api.AlignmentRowsCollectionI;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.HiddenSequences;
+
+import java.awt.Graphics;
+
+public abstract class OverviewDimensions
+{
+ protected static final int MAX_WIDTH = 400;
+
+ protected static final int MIN_WIDTH = 120;
+
+ protected static final int MIN_SEQ_HEIGHT = 40;
+
+ protected static final int MAX_SEQ_HEIGHT = 300;
+
+ private static final int DEFAULT_GRAPH_HEIGHT = 20;
+
+ protected int width;
+
+ protected int sequencesHeight;
+
+ protected int graphHeight = DEFAULT_GRAPH_HEIGHT;
+
+ protected int boxX = -1;
+
+ protected int boxY = -1;
+
+ protected int boxWidth = -1;
+
+ protected int boxHeight = -1;
+
+ protected int alwidth;
+
+ protected int alheight;
+
+ /**
+ * Create an OverviewDimensions object
+ *
+ * @param ranges
+ * positional properties of the viewport
+ * @param showAnnotationPanel
+ * true if the annotation panel is to be shown, false otherwise
+ */
+ public OverviewDimensions(ViewportRanges ranges,
+ boolean showAnnotationPanel)
+ {
+ // scale the initial size of overviewpanel to shape of alignment
+ float initialScale = (float) ranges.getAbsoluteAlignmentWidth()
+ / (float) ranges.getAbsoluteAlignmentHeight();
+
+ if (!showAnnotationPanel)
+ {
+ graphHeight = 0;
+ }
+
+ if (ranges.getAbsoluteAlignmentWidth() > ranges
+ .getAbsoluteAlignmentHeight())
+ {
+ // wider
+ width = MAX_WIDTH;
+ sequencesHeight = Math.round(MAX_WIDTH / initialScale);
+ if (sequencesHeight < MIN_SEQ_HEIGHT)
+ {
+ sequencesHeight = MIN_SEQ_HEIGHT;
+ }
+ }
+ else
+ {
+ // taller
+ width = Math.round(MAX_WIDTH * initialScale);
+ sequencesHeight = MAX_SEQ_HEIGHT;
+
+ if (width < MIN_WIDTH)
+ {
+ width = MIN_WIDTH;
+ }
+ }
+ }
+
+ /**
+ * Draw the overview panel's viewport box on a graphics object
+ *
+ * @param g
+ * the graphics object to draw on
+ */
+ public void drawBox(Graphics g)
+ {
+ g.drawRect(boxX, boxY, boxWidth, boxHeight);
+ g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);
+ }
+
+ public int getBoxX()
+ {
+ return boxX;
+ }
+
+ public int getBoxY()
+ {
+ return boxY;
+ }
+
+ public int getBoxWidth()
+ {
+ return boxWidth;
+ }
+
+ public int getBoxHeight()
+ {
+ return boxHeight;
+ }
+
+ public int getWidth()
+ {
+ return width;
+ }
+
+ public int getHeight()
+ {
+ return sequencesHeight + graphHeight;
+ }
+
+ public int getSequencesHeight()
+ {
+ return sequencesHeight;
+ }
+
+ public int getGraphHeight()
+ {
+ return graphHeight;
+ }
+
+ public float getPixelsPerCol()
+ {
+ resetAlignmentDims();
+ return (float) width / alwidth;
+ }
+
+ public float getPixelsPerSeq()
+ {
+ resetAlignmentDims();
+ return (float) sequencesHeight / alheight;
+ }
+
+ public void setWidth(int w)
+ {
+ width = w;
+ }
+
+ public void setHeight(int h)
+ {
+ sequencesHeight = h - graphHeight;
+ }
+
+ /**
+ * Update the viewport location from a mouse click in the overview panel
+ *
+ * @param mousex
+ * x location of mouse
+ * @param mousey
+ * y location of mouse
+ * @param hiddenSeqs
+ * the alignment's hidden sequences
+ * @param hiddenCols
+ * the alignment's hidden columns
+ */
+ public abstract void updateViewportFromMouse(int mousex, int mousey,
+ HiddenSequences hiddenSeqs, HiddenColumns hiddenCols);
+
+ /**
+ * Set the overview panel's box position to match the viewport
+ *
+ * @param hiddenSeqs
+ * the alignment's hidden sequences
+ * @param hiddenCols
+ * the alignment's hidden columns
+ */
+ public abstract void setBoxPosition(HiddenSequences hiddenSeqs,
+ HiddenColumns hiddenCols);
+
+ /**
+ * Get the collection of columns used by this overview dimensions object
+ *
+ * @param hiddenCols
+ * the alignment's hidden columns
+ * @return a column collection
+ */
+ public abstract AlignmentColsCollectionI getColumns(AlignmentI al);
+
+ /**
+ * Get the collection of rows used by this overview dimensions object
+ *
+ * @param al
+ * the alignment
+ * @return a row collection
+ */
+ public abstract AlignmentRowsCollectionI getRows(AlignmentI al);
+
+ /**
+ * Updates overview dimensions to account for current alignment dimensions
+ */
+ protected abstract void resetAlignmentDims();
+
+ protected void setBoxPosition(int startRes, int startSeq, int vpwidth,
+ int vpheight)
+ {
+ resetAlignmentDims();
+
+ // boxX, boxY is the x,y location equivalent to startRes, startSeq
+ boxX = Math.round((float) startRes * width / alwidth);
+ boxY = Math.round((float) startSeq * sequencesHeight / alheight);
+
+ // boxWidth is the width in residues translated to pixels
+ boxWidth = Math.round((float) vpwidth * width / alwidth);
+
+ // boxHeight is the height in sequences translated to pixels
+ boxHeight = Math.round((float) vpheight * sequencesHeight / alheight);
+ }
+}
\ No newline at end of file
--- /dev/null
+package jalview.viewmodel;
+
+import jalview.api.AlignmentColsCollectionI;
+import jalview.api.AlignmentRowsCollectionI;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.HiddenSequences;
+import jalview.datamodel.VisibleColsCollection;
+import jalview.datamodel.VisibleRowsCollection;
+
+public class OverviewDimensionsHideHidden extends OverviewDimensions
+{
+ private ViewportRanges ranges;
+
+ public OverviewDimensionsHideHidden(ViewportRanges vpranges,
+ boolean showAnnotationPanel)
+ {
+ super(vpranges, showAnnotationPanel);
+ ranges = vpranges;
+ resetAlignmentDims();
+ }
+
+ @Override
+ public void updateViewportFromMouse(int mousex, int mousey,
+ HiddenSequences hiddenSeqs, HiddenColumns hiddenCols)
+ {
+ resetAlignmentDims();
+
+ int x = mousex;
+ int y = mousey;
+
+ if (x < 0)
+ {
+ x = 0;
+ }
+
+ if (y < 0)
+ {
+ y = 0;
+ }
+
+ //
+ // Convert x value to residue position
+ //
+
+ // need to determine where scrollCol should be, given x
+ // to do this also need to know width of viewport, and some hidden column
+ // correction
+
+ // convert x to residues - this is an absolute position
+ int xAsRes = Math.round((float) x * alwidth / width);
+
+ // get viewport width in residues
+ int vpwidth = ranges.getViewportWidth();
+
+ if (xAsRes + vpwidth > alwidth)
+ {
+ // went past the end of the alignment, adjust backwards
+
+ // if last position was before the end of the alignment, need to update
+ if (ranges.getStartRes() < alwidth)
+ {
+ xAsRes = alwidth - vpwidth;
+ }
+ else
+ {
+ xAsRes = ranges.getStartRes();
+ }
+ }
+
+
+ //
+ // Convert y value to sequence position
+ //
+
+ // convert y to residues
+ int yAsSeq = Math.round((float) y * alheight / sequencesHeight);
+
+ // get viewport height in sequences
+ // add 1 because height includes both endSeq and startSeq
+ int vpheight = ranges.getViewportHeight();
+
+ if (yAsSeq + vpheight > alheight)
+ {
+ // went past the end of the alignment, adjust backwards
+ if (ranges.getEndSeq() < alheight)
+ {
+ yAsSeq = alheight - vpheight;
+ }
+ else
+ {
+ yAsSeq = ranges.getStartSeq();
+ }
+ }
+
+ // update viewport
+ ranges.setStartRes(xAsRes);
+ ranges.setStartSeq(yAsSeq);
+
+ }
+
+ @Override
+ public void setBoxPosition(HiddenSequences hiddenSeqs,
+ HiddenColumns hiddenCols)
+ {
+ setBoxPosition(ranges.getStartRes(), ranges.getStartSeq(),
+ ranges.getViewportWidth(), ranges.getViewportHeight());
+ }
+
+ @Override
+ public AlignmentColsCollectionI getColumns(AlignmentI al)
+ {
+ return new VisibleColsCollection(0,
+ ranges.getAbsoluteAlignmentWidth() - 1, al);
+ }
+
+ @Override
+ public AlignmentRowsCollectionI getRows(AlignmentI al)
+ {
+ return new VisibleRowsCollection(0,
+ ranges.getAbsoluteAlignmentHeight() - 1, al);
+ }
+
+ @Override
+ protected void resetAlignmentDims()
+ {
+ alwidth = ranges.getVisibleAlignmentWidth();
+ alheight = ranges.getVisibleAlignmentHeight();
+ }
+}
--- /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.
+ */
+package jalview.viewmodel;
+
+import jalview.api.AlignmentColsCollectionI;
+import jalview.api.AlignmentRowsCollectionI;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AllColsCollection;
+import jalview.datamodel.AllRowsCollection;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.HiddenSequences;
+
+public class OverviewDimensionsShowHidden extends OverviewDimensions
+{
+ private ViewportRanges ranges;
+
+ /**
+ * Create an OverviewDimensions object
+ *
+ * @param ranges
+ * positional properties of the viewport
+ * @param showAnnotationPanel
+ * true if the annotation panel is to be shown, false otherwise
+ */
+ public OverviewDimensionsShowHidden(ViewportRanges vpranges,
+ boolean showAnnotationPanel)
+ {
+ super(vpranges, showAnnotationPanel);
+ ranges = vpranges;
+ resetAlignmentDims();
+ }
+
+ /**
+ * Check box dimensions and scroll positions and correct if necessary
+ *
+ * @param mousex
+ * x position in overview panel
+ * @param mousey
+ * y position in overview panel
+ * @param hiddenSeqs
+ * hidden sequences
+ * @param hiddenCols
+ * hidden columns
+ * @param ranges
+ * viewport position properties
+ */
+ @Override
+ public void updateViewportFromMouse(int mousex, int mousey,
+ HiddenSequences hiddenSeqs, HiddenColumns hiddenCols)
+ {
+ int x = mousex;
+ int y = mousey;
+
+ resetAlignmentDims();
+
+ if (x < 0)
+ {
+ x = 0;
+ }
+
+ if (y < 0)
+ {
+ y = 0;
+ }
+
+ //
+ // Convert x value to residue position
+ //
+
+ // need to determine where scrollCol should be, given x
+ // to do this also need to know width of viewport, and some hidden column
+ // correction
+
+ // convert x to residues - this is an absolute position
+ int xAsRes = Math.round((float) x * alwidth / width);
+
+ // get viewport width in residues
+ int vpwidth = ranges.getViewportWidth();
+
+ // get where x should be when accounting for hidden cols
+ // if x is in a hidden col region, shift to left - but we still need
+ // absolute position
+ // so convert back after getting visible region position
+ int visXAsRes = hiddenCols.findColumnPosition(xAsRes);
+
+ // check in case we went off the edge of the alignment
+ int visAlignWidth = hiddenCols.findColumnPosition(alwidth - 1);
+ if (visXAsRes + vpwidth - 1 > visAlignWidth)
+ {
+ // went past the end of the alignment, adjust backwards
+
+ // if last position was before the end of the alignment, need to update
+ if (ranges.getEndRes() < visAlignWidth)
+ {
+ visXAsRes = hiddenCols.findColumnPosition(hiddenCols
+ .subtractVisibleColumns(vpwidth - 1, alwidth - 1));
+ }
+ else
+ {
+ visXAsRes = ranges.getStartRes();
+ }
+ }
+
+ //
+ // Convert y value to sequence position
+ //
+
+ // convert y to residues
+ int yAsSeq = Math.round((float) y * alheight / sequencesHeight);
+
+ // get viewport height in sequences
+ int vpheight = ranges.getViewportHeight();
+
+ // get where y should be when accounting for hidden rows
+ // if y is in a hidden row region, shift up - but we still need absolute
+ // position,
+ // so convert back after getting visible region position
+ yAsSeq = hiddenSeqs.adjustForHiddenSeqs(hiddenSeqs
+ .findIndexWithoutHiddenSeqs(yAsSeq));
+
+ // check in case we went off the edge of the alignment
+ int visAlignHeight = hiddenSeqs.findIndexWithoutHiddenSeqs(alheight);
+ int visYAsSeq = hiddenSeqs.findIndexWithoutHiddenSeqs(yAsSeq);
+ if (visYAsSeq + vpheight - 1 > visAlignHeight)
+ {
+ // went past the end of the alignment, adjust backwards
+ if (ranges.getEndSeq() < visAlignHeight)
+ {
+ visYAsSeq = hiddenSeqs.findIndexWithoutHiddenSeqs(hiddenSeqs
+ .subtractVisibleRows(vpheight - 1, alheight - 1));
+ }
+ else
+ {
+ visYAsSeq = ranges.getStartSeq();
+ }
+ }
+
+ // update viewport
+ ranges.setStartRes(visXAsRes);
+ ranges.setStartSeq(visYAsSeq);
+
+ }
+
+ /**
+ * Update the overview panel box when the associated alignment panel is
+ * changed
+ *
+ * @param hiddenSeqs
+ * hidden sequences
+ * @param hiddenCols
+ * hidden columns
+ * @param ranges
+ * viewport position properties
+ */
+ @Override
+ public void setBoxPosition(HiddenSequences hiddenSeqs,
+ HiddenColumns hiddenCols)
+ {
+ // work with absolute values of startRes and endRes
+ int startRes = hiddenCols.adjustForHiddenColumns(ranges.getStartRes());
+ int endRes = hiddenCols.adjustForHiddenColumns(ranges.getEndRes());
+
+ // work with absolute values of startSeq and endSeq
+ int startSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getStartSeq());
+ int endSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getEndSeq());
+
+ setBoxPosition(startRes, startSeq, endRes - startRes + 1, endSeq
+ - startSeq + 1);
+ }
+
+ @Override
+ public AlignmentColsCollectionI getColumns(AlignmentI al)
+ {
+ return new AllColsCollection(0,
+ ranges.getAbsoluteAlignmentWidth() - 1, al);
+ }
+
+ @Override
+ public AlignmentRowsCollectionI getRows(AlignmentI al)
+ {
+ return new AllRowsCollection(0,
+ ranges.getAbsoluteAlignmentHeight() - 1,
+ al);
+ }
+
+ @Override
+ protected void resetAlignmentDims()
+ {
+ alwidth = ranges.getAbsoluteAlignmentWidth();
+ alheight = ranges.getAbsoluteAlignmentHeight();
+ }
+}
import jalview.analysis.PCA;
import jalview.api.RotatableCanvasI;
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityParamsI;
import jalview.datamodel.AlignmentView;
import jalview.datamodel.SequenceI;
import jalview.datamodel.SequencePoint;
public class PCAModel
{
-
- public PCAModel(AlignmentView seqstrings2, SequenceI[] seqs2,
- boolean nucleotide2)
- {
- seqstrings = seqstrings2;
- seqs = seqs2;
- nucleotide = nucleotide2;
- score_matrix = nucleotide2 ? "PID" : "BLOSUM62";
- }
-
private volatile PCA pca;
int top;
SequenceI[] seqs;
- /**
- * Score matrix used to calculate PC
+ /*
+ * Name of score model used to calculate PCA
*/
- String score_matrix;
+ ScoreModelI scoreModel;
- /**
- * use the identity matrix for calculating similarity between sequences.
- */
private boolean nucleotide = false;
private Vector<SequencePoint> points;
- private boolean jvCalcMode = true;
+ private SimilarityParamsI similarityParams;
- public boolean isJvCalcMode()
+ /**
+ * Constructor given sequence data, score model and score calculation
+ * parameter options.
+ *
+ * @param seqData
+ * @param sqs
+ * @param nuc
+ * @param modelName
+ * @param params
+ */
+ public PCAModel(AlignmentView seqData, SequenceI[] sqs, boolean nuc,
+ ScoreModelI modelName,
+ SimilarityParamsI params)
{
- return jvCalcMode;
+ seqstrings = seqData;
+ seqs = sqs;
+ nucleotide = nuc;
+ scoreModel = modelName;
+ similarityParams = params;
}
public void run()
{
-
- pca = new PCA(seqstrings.getSequenceStrings(' '), nucleotide,
- score_matrix);
- pca.setJvCalcMode(jvCalcMode);
+ pca = new PCA(seqstrings, scoreModel, similarityParams);
pca.run();
// Now find the component coordinates
ii++;
}
- double[][] comps = new double[ii][ii];
-
- for (int i = 0; i < ii; i++)
- {
- if (pca.getEigenvalue(i) > 1e-4)
- {
- comps[i] = pca.component(i);
- }
- }
-
- top = pca.getM().rows - 1;
+ int height = pca.getHeight();
+ // top = pca.getM().height() - 1;
+ top = height - 1;
points = new Vector<SequencePoint>();
float[][] scores = pca.getComponents(top - 1, top - 2, top - 3, 100);
- for (int i = 0; i < pca.getM().rows; i++)
+ for (int i = 0; i < height; i++)
{
SequencePoint sp = new SequencePoint(seqs[i], scores[i]);
points.addElement(sp);
}
-
}
public void updateRc(RotatableCanvasI rc)
{
- rc.setPoints(points, pca.getM().rows);
+ rc.setPoints(points, pca.getHeight());
}
public boolean isNucleotide()
// note: actual indices for components are dim1-1, etc (patch for JAL-1123)
float[][] scores = pca.getComponents(dim1 - 1, dim2 - 1, dim3 - 1, 100);
- for (int i = 0; i < pca.getM().rows; i++)
+ for (int i = 0; i < pca.getHeight(); i++)
{
- ((SequencePoint) points.elementAt(i)).coord = scores[i];
+ points.elementAt(i).coord = scores[i];
}
}
return pts;
}
- public void setJvCalcMode(boolean state)
- {
- jvCalcMode = state;
- }
-
- public String getScore_matrix()
+ public String getScoreModelName()
{
- return score_matrix;
+ return scoreModel == null ? "" : scoreModel.getName();
}
- public void setScore_matrix(String score_matrix)
+ public void setScoreModel(ScoreModelI sm)
{
- this.score_matrix = score_matrix;
+ this.scoreModel = sm;
}
}
--- /dev/null
+package jalview.viewmodel;
+
+import java.beans.PropertyChangeListener;
+
+public interface ViewportListenerI extends PropertyChangeListener
+{
+
+}
* along with Jalview. If not, see <http://www.gnu.org/licenses/>.
* The Jalview Authors are detailed in the 'AUTHORS' file.
*/
-package jalview.api.analysis;
+package jalview.viewmodel;
-import jalview.api.AlignmentViewPanel;
+import java.beans.PropertyChangeSupport;
-public interface ViewBasedAnalysisI
+public abstract class ViewportProperties
{
+ protected PropertyChangeSupport changeSupport = new PropertyChangeSupport(
+ this);
- /**
- * Parameterise the analysis model using the current view
- *
- * @param view
- * @return true if model is applicable and calculation should proceed
- */
+ public void addPropertyChangeListener(ViewportListenerI listener)
+ {
+ changeSupport.addPropertyChangeListener(listener);
+ }
- boolean configureFromAlignmentView(AlignmentViewPanel view);
+ public void removePropertyChangeListener(ViewportListenerI listener)
+ {
+ changeSupport.removePropertyChangeListener(listener);
+ }
}
--- /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.
+ */
+package jalview.viewmodel;
+
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
+
+/**
+ * Slightly less embryonic class which: Supplies and updates viewport properties
+ * relating to position such as: start and end residues and sequences; ideally
+ * will serve hidden columns/rows too. Intention also to support calculations
+ * for positioning, scrolling etc. such as finding the middle of the viewport,
+ * checking for scrolls off screen
+ */
+public class ViewportRanges extends ViewportProperties
+{
+ // start residue of viewport
+ private int startRes;
+
+ // end residue of viewport
+ private int endRes;
+
+ // start sequence of viewport
+ private int startSeq;
+
+ // end sequence of viewport
+ private int endSeq;
+
+ // alignment
+ private AlignmentI al;
+
+ /**
+ * Constructor
+ *
+ * @param alignment
+ * the viewport's alignment
+ */
+ public ViewportRanges(AlignmentI alignment)
+ {
+ // initial values of viewport settings
+ this.startRes = 0;
+ this.endRes = alignment.getWidth() - 1;
+ this.startSeq = 0;
+ this.endSeq = alignment.getHeight() - 1;
+ this.al = alignment;
+ }
+
+ /**
+ * Get alignment width in cols, including hidden cols
+ */
+ public int getAbsoluteAlignmentWidth()
+ {
+ return al.getWidth();
+ }
+
+ /**
+ * Get alignment height in rows, including hidden rows
+ */
+ public int getAbsoluteAlignmentHeight()
+ {
+ return al.getHeight() + al.getHiddenSequences().getSize();
+ }
+
+ /**
+ * Get alignment width in cols, excluding hidden cols
+ */
+ public int getVisibleAlignmentWidth()
+ {
+ return al.getWidth() - al.getHiddenColumns().getSize();
+ }
+
+ /**
+ * Get alignment height in rows, excluding hidden rows
+ */
+ public int getVisibleAlignmentHeight()
+ {
+ return al.getHeight();
+ }
+
+ /**
+ * Set first residue visible in the viewport, and retain the current width.
+ * Fires a property change event.
+ *
+ * @param res
+ * residue position
+ */
+ public void setStartRes(int res)
+ {
+ int width = getViewportWidth();
+ setStartEndRes(res, res + width - 1);
+ }
+
+ /**
+ * Set start and end residues at the same time. This method only fires one
+ * event for the two changes, and should be used in preference to separate
+ * calls to setStartRes and setEndRes.
+ *
+ * @param start
+ * the start residue
+ * @param end
+ * the end residue
+ */
+ public void setStartEndRes(int start, int end)
+ {
+ int oldstartres = this.startRes;
+ if (start > getVisibleAlignmentWidth() - 1)
+ {
+ startRes = Math.max(getVisibleAlignmentWidth() - 1, 0);
+ }
+ else if (start < 0)
+ {
+ startRes = 0;
+ }
+ else
+ {
+ startRes = start;
+ }
+
+ int oldendres = this.endRes;
+ if (end < 0)
+ {
+ endRes = 0;
+ }
+ else if (end > getVisibleAlignmentWidth() - 1)
+ {
+ endRes = Math.max(getVisibleAlignmentWidth() - 1, 0);
+ }
+ else
+ {
+ endRes = end;
+ }
+
+ changeSupport.firePropertyChange("startres", oldstartres, startRes);
+ if (oldstartres == startRes)
+ {
+ // event won't be fired if start positions are same
+ // fire an event for the end positions in case they changed
+ changeSupport.firePropertyChange("endres", oldendres, endRes);
+ }
+ }
+
+ /**
+ * Set last residue visible in the viewport. Fires a property change event.
+ *
+ * @param res
+ * residue position
+ */
+ public void setEndRes(int res)
+ {
+ int startres = res;
+ int width = getViewportWidth();
+ if (startres + width - 1 > getVisibleAlignmentWidth() - 1)
+ {
+ startres = getVisibleAlignmentWidth() - width;
+ }
+ setStartEndRes(startres - width + 1, startres);
+ }
+
+ /**
+ * Set the first sequence visible in the viewport, maintaining the height. If
+ * the viewport would extend past the last sequence, sets the viewport so it
+ * sits at the bottom of the alignment. Fires a property change event.
+ *
+ * @param seq
+ * sequence position
+ */
+ public void setStartSeq(int seq)
+ {
+ int startseq = seq;
+ int height = getViewportHeight();
+ if (startseq + height - 1 > getVisibleAlignmentHeight() - 1)
+ {
+ startseq = getVisibleAlignmentHeight() - height;
+ }
+ setStartEndSeq(startseq, startseq + height - 1);
+ }
+
+ /**
+ * Set start and end sequences at the same time. The viewport height may
+ * change. This method only fires one event for the two changes, and should be
+ * used in preference to separate calls to setStartSeq and setEndSeq.
+ *
+ * @param start
+ * the start sequence
+ * @param end
+ * the end sequence
+ */
+ public void setStartEndSeq(int start, int end)
+ {
+ int oldstartseq = this.startSeq;
+ if (start > getVisibleAlignmentHeight() - 1)
+ {
+ startSeq = Math.max(getVisibleAlignmentHeight() - 1, 0);
+ }
+ else if (start < 0)
+ {
+ startSeq = 0;
+ }
+ else
+ {
+ startSeq = start;
+ }
+
+ int oldendseq = this.endSeq;
+ if (end >= getVisibleAlignmentHeight())
+ {
+ endSeq = Math.max(getVisibleAlignmentHeight() - 1, 0);
+ }
+ else if (end < 0)
+ {
+ endSeq = 0;
+ }
+ else
+ {
+ endSeq = end;
+ }
+
+ changeSupport.firePropertyChange("startseq", oldstartseq, startSeq);
+ if (oldstartseq == startSeq)
+ {
+ // event won't be fired if start positions are the same
+ // fire in case the end positions changed
+ changeSupport.firePropertyChange("endseq", oldendseq, endSeq);
+ }
+ }
+
+ /**
+ * Set the last sequence visible in the viewport. Fires a property change
+ * event.
+ *
+ * @param seq
+ * sequence position
+ */
+ public void setEndSeq(int seq)
+ {
+ int height = getViewportHeight();
+ setStartEndSeq(seq - height + 1, seq);
+ }
+
+ /**
+ * Get start residue of viewport
+ */
+ public int getStartRes()
+ {
+ return startRes;
+ }
+
+ /**
+ * Get end residue of viewport
+ */
+ public int getEndRes()
+ {
+ return endRes;
+ }
+
+ /**
+ * Get start sequence of viewport
+ */
+ public int getStartSeq()
+ {
+ return startSeq;
+ }
+
+ /**
+ * Get end sequence of viewport
+ */
+ public int getEndSeq()
+ {
+ return endSeq;
+ }
+
+ /**
+ * Set viewport width in residues, without changing startRes. Use in
+ * preference to calculating endRes from the width, to avoid out by one
+ * errors! Fires a property change event.
+ *
+ * @param w
+ * width in residues
+ */
+ public void setViewportWidth(int w)
+ {
+ setStartEndRes(startRes, startRes + w - 1);
+ }
+
+ /**
+ * Set viewport height in residues, without changing startSeq. Use in
+ * preference to calculating endSeq from the height, to avoid out by one
+ * errors! Fires a property change event.
+ *
+ * @param h
+ * height in sequences
+ */
+ public void setViewportHeight(int h)
+ {
+ setStartEndSeq(startSeq, startSeq + h - 1);
+ }
+
+ /**
+ * Set viewport horizontal start position and width. Use in preference to
+ * calculating endRes from the width, to avoid out by one errors! Fires a
+ * property change event.
+ *
+ * @param start
+ * start residue
+ * @param w
+ * width in residues
+ */
+ public void setViewportStartAndWidth(int start, int w)
+ {
+ int vpstart = start;
+ if (vpstart < 0)
+ {
+ vpstart = 0;
+ }
+ else if ((w <= getVisibleAlignmentWidth())
+ && (vpstart + w - 1 > getVisibleAlignmentWidth() - 1))
+ // viewport width is less than the full alignment and we are running off the
+ // RHS edge
+ {
+ vpstart = getVisibleAlignmentWidth() - w;
+ }
+ setStartEndRes(vpstart, vpstart + w - 1);
+ }
+
+ /**
+ * Set viewport vertical start position and height. Use in preference to
+ * calculating endSeq from the height, to avoid out by one errors! Fires a
+ * property change event.
+ *
+ * @param start
+ * start sequence
+ * @param h
+ * height in sequences
+ */
+ public void setViewportStartAndHeight(int start, int h)
+ {
+ int vpstart = start;
+ if (vpstart < 0)
+ {
+ vpstart = 0;
+ }
+ else if ((h <= getVisibleAlignmentHeight())
+ && (vpstart + h - 1 > getVisibleAlignmentHeight() - 1))
+ // viewport height is less than the full alignment and we are running off
+ // the bottom
+ {
+ vpstart = getVisibleAlignmentHeight() - h;
+ }
+ setStartEndSeq(vpstart, vpstart + h - 1);
+ }
+
+ /**
+ * Get width of viewport in residues
+ *
+ * @return width of viewport
+ */
+ public int getViewportWidth()
+ {
+ return (endRes - startRes + 1);
+ }
+
+ /**
+ * Get height of viewport in residues
+ *
+ * @return height of viewport
+ */
+ public int getViewportHeight()
+ {
+ return (endSeq - startSeq + 1);
+ }
+
+ /**
+ * Scroll the viewport range vertically. Fires a property change event.
+ *
+ * @param up
+ * true if scrolling up, false if down
+ *
+ * @return true if the scroll is valid
+ */
+ public boolean scrollUp(boolean up)
+ {
+ if (up)
+ {
+ if (startSeq < 1)
+ {
+ return false;
+ }
+
+ setStartSeq(startSeq - 1);
+ }
+ else
+ {
+ if (endSeq >= getVisibleAlignmentHeight() - 1)
+ {
+ return false;
+ }
+
+ setStartSeq(startSeq + 1);
+ }
+ return true;
+ }
+
+ /**
+ * Scroll the viewport range horizontally. Fires a property change event.
+ *
+ * @param right
+ * true if scrolling right, false if left
+ *
+ * @return true if the scroll is valid
+ */
+ public boolean scrollRight(boolean right)
+ {
+ if (!right)
+ {
+ if (startRes < 1)
+ {
+ return false;
+ }
+
+ setStartRes(startRes - 1);
+ }
+ else
+ {
+ if (endRes >= getVisibleAlignmentWidth() - 1)
+ {
+ return false;
+ }
+
+ setStartRes(startRes + 1);
+ }
+
+ return true;
+ }
+
+ /**
+ * Scroll a wrapped alignment so that the specified residue is visible. Fires
+ * a property change event.
+ *
+ * @param res
+ * residue position to scroll to
+ */
+ public void scrollToWrappedVisible(int res)
+ {
+ // get the start residue of the wrapped row which res is in
+ // and set that as our start residue
+ int width = getViewportWidth();
+ setStartRes((res / width) * width);
+ }
+
+ /**
+ * Scroll so that (x,y) is visible. Fires a property change event.
+ *
+ * @param x
+ * x position in alignment
+ * @param y
+ * y position in alignment
+ */
+ public void scrollToVisible(int x, int y)
+ {
+ while (y < startSeq)
+ {
+ scrollUp(true);
+ }
+ while (y > endSeq)
+ {
+ scrollUp(false);
+ }
+
+ HiddenColumns hidden = al.getHiddenColumns();
+ while (x < hidden.adjustForHiddenColumns(startRes))
+ {
+ if (!scrollRight(false))
+ {
+ break;
+ }
+ }
+ while (x > hidden.adjustForHiddenColumns(endRes))
+ {
+ if (!scrollRight(true))
+ {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Adjust sequence position for page up. Fires a property change event.
+ */
+ public void pageUp()
+ {
+ setViewportStartAndHeight(2 * startSeq - endSeq, getViewportHeight());
+ }
+
+ /**
+ * Adjust sequence position for page down. Fires a property change event.
+ */
+ public void pageDown()
+ {
+ setViewportStartAndHeight(endSeq, getViewportHeight());
+ }
+}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
{
minmax = new Hashtable<String, float[][]>();
}
+
+ Set<String> oldGroups = new HashSet<String>(featureGroups.keySet());
AlignmentI alignment = av.getAlignment();
for (int i = 0; i < alignment.getHeight(); i++)
{
int index = 0;
while (index < features.length)
{
+ String fgrp = features[index].getFeatureGroup();
+ oldGroups.remove(fgrp);
if (!featuresDisplayed.isRegistered(features[index].getType()))
{
- String fgrp = features[index].getFeatureGroup();
if (fgrp != null)
{
Boolean groupDisplayed = featureGroups.get(fgrp);
index++;
}
}
+
+ /*
+ * oldGroups now consists of groups that no longer
+ * have any feature in them - remove these
+ */
+ for (String grp : oldGroups)
+ {
+ featureGroups.remove(grp);
+ }
+
updateRenderOrder(allfeatures);
findingFeatures = false;
}
}
/**
- * calculate the render colour for a specific feature using current feature
- * settings.
+ * Returns the configured colour for a particular feature instance. This
+ * includes calculation of 'colour by label', or of a graduated score colour,
+ * if applicable. It does not take into account feature visibility or colour
+ * transparency.
*
* @param feature
- * @return render colour for the given feature
+ * @return
*/
public Color getColour(SequenceFeature feature)
{
featureColours.put(featureType, col);
}
+ @Override
public void setTransparency(float value)
{
transparency = value;
}
+ @Override
public float getTransparency()
{
return transparency;
* @return list of groups
*/
@Override
- public List getGroups(boolean visible)
+ public List<String> getGroups(boolean visible)
{
if (featureGroups != null)
{
*/
private boolean scaleProteinAsCdna = true;
+ /*
+ * if true, font changes to protein or cDNA are applied to both
+ * sides of a split screen
+ */
+ private boolean proteinFontAsCdna = true;
+
/**
* Copy constructor
*
setScaleAboveWrapped(vs.getScaleAboveWrapped());
setScaleLeftWrapped(vs.getScaleLeftWrapped());
setScaleProteinAsCdna(vs.isScaleProteinAsCdna());
+ setProteinFontAsCdna(vs.isProteinFontAsCdna());
setScaleRightWrapped(vs.getScaleRightWrapped());
setSeqNameItalics(vs.isSeqNameItalics());
setShowAnnotation(vs.isShowAnnotation());
&& getScaleAboveWrapped() == vs.getScaleAboveWrapped()
&& getScaleLeftWrapped() == vs.getScaleLeftWrapped()
&& isScaleProteinAsCdna() == vs.isScaleProteinAsCdna()
+ && isProteinFontAsCdna() == vs.isProteinFontAsCdna()
&& getScaleRightWrapped() == vs.getScaleRightWrapped()
&& isSeqNameItalics() == vs.isSeqNameItalics()
&& isShowAnnotation() == vs.isShowAnnotation()
{
this.scaleProteinAsCdna = b;
}
+
+ @Override
+ public boolean isProteinFontAsCdna()
+ {
+ return proteinFontAsCdna;
+ }
+
+ @Override
+ public void setProteinFontAsCdna(boolean b)
+ {
+ proteinFontAsCdna = b;
+ }
}
* @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];
+ long rmax = 0;
+ /*
+ * add counts as annotations. zeros are needed since select-by-annotation ignores empty annotation positions
+ */
+ for (int i = 0; i < counts.length; i++)
{
- Color color = ColorUtils.getGraduatedColour(count, 0, Color.cyan,
- max, Color.blue);
+ int count = counts[i][anrow];
+
+ Color color = ColorUtils.getGraduatedColour(count, 0, minColour,
+ max[anrow], maxColour);
String str = String.valueOf(count);
anns[i] = new Annotation(str, str, '0', count, color);
+ rmax = Math.max(count, rmax);
}
- }
- /*
- * 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;
+ ann.graphMin = 0f; // minimum always zero count
+ ann.graphMax = rmax; // maximum count from loop over feature columns
+ 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;
}
try
{
AlignmentAnnotation consensus = getConsensusAnnotation();
- if (consensus == null || calcMan.isPending(this))
+ AlignmentAnnotation gap = getGapAnnotation();
+ if ((consensus == null && gap == null) || calcMan.isPending(this))
{
calcMan.workerComplete(this);
return;
{
AlignmentAnnotation consensus = getConsensusAnnotation();
consensus.annotations = new Annotation[aWidth];
+ AlignmentAnnotation gap = getGapAnnotation();
+ if (gap != null)
+ {
+ gap.annotations = new Annotation[aWidth];
+ }
}
/**
SequenceI[] aseqs = getSequences();
int width = alignment.getWidth();
- ProfilesI hconsensus = AAFrequency.calculate(aseqs, width, 0,
- width, true);
+ ProfilesI hconsensus = AAFrequency.calculate(aseqs, width, 0, width,
+ true);
alignViewport.setSequenceConsensusHash(hconsensus);
setColourSchemeConsensus(hconsensus);
}
/**
+ * Get the Gap annotation for the alignment
+ *
+ * @return
+ */
+ protected AlignmentAnnotation getGapAnnotation()
+ {
+ return alignViewport.getAlignmentGapAnnotation();
+ }
+
+ /**
* update the consensus annotation from the sequence profile data using
* current visualization settings.
*/
&& hconsensus != null)
{
deriveConsensus(consensus, hconsensus);
+ AlignmentAnnotation gap = getGapAnnotation();
+ if (gap != null)
+ {
+ deriveGap(gap, hconsensus);
+ }
}
}
long nseq = getSequences().length;
AAFrequency.completeConsensus(consensusAnnotation, hconsensus,
- hconsensus.getStartColumn(),
- hconsensus.getEndColumn() + 1,
+ hconsensus.getStartColumn(), hconsensus.getEndColumn() + 1,
alignViewport.isIgnoreGapsConsensus(),
alignViewport.isShowSequenceLogo(), nseq);
}
/**
+ * Convert the computed consensus data into a gap annotation row for display.
+ *
+ * @param gapAnnotation
+ * the annotation to be populated
+ * @param hconsensus
+ * the computed consensus data
+ */
+ protected void deriveGap(AlignmentAnnotation gapAnnotation,
+ ProfilesI hconsensus)
+ {
+ long nseq = getSequences().length;
+ AAFrequency.completeGapAnnot(gapAnnotation, hconsensus,
+ hconsensus.getStartColumn(), hconsensus.getEndColumn() + 1,
+ nseq);
+ }
+
+ /**
* Get the consensus data stored on the viewport.
*
* @return
{
calcMan.notifyStart(this); // updatingConservation = true;
- while (!calcMan.notifyWorking(this))
+ while ((calcMan != null) && (!calcMan.notifyWorking(this)))
{
try
{
ex.printStackTrace();
}
}
- if (alignViewport.isClosed())
+ if ((alignViewport == null) || (calcMan == null)
+ || (alignViewport.isClosed()))
{
abortAndDestroy();
return;
}
calcMan.workerComplete(this);
+ if ((alignViewport == null) || (calcMan == null)
+ || (alignViewport.isClosed()))
+ {
+ abortAndDestroy();
+ return;
+ }
if (ap != null)
{
ap.paintAlignment(true);
* 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
}
af.getFeatureRenderer().featuresAdded();
- int start = af.getViewport().getStartSeq();
- int end = af.getViewport().getEndSeq();
+ int start = af.getViewport().getRanges().getStartSeq();
+ int end = af.getViewport().getRanges().getEndSeq();
int index;
for (index = start; index < end; index++)
{
--- /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.
+ */
+package jalview.ws.dbsources;
+
+import jalview.api.FeatureSettingsModelI;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.io.FormatAdapter;
+import jalview.io.PDBFeatureSettings;
+import jalview.util.MessageManager;
+import jalview.ws.ebi.EBIFetchClient;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+
+import com.stevesoft.pat.Regex;
+
+/**
+ * @author JimP
+ *
+ */
+public class Pdb extends EbiFileRetrievedProxy
+{
+ public Pdb()
+ {
+ super();
+ }
+
+ public static final String FEATURE_INSERTION = "INSERTION";
+
+ public static final String FEATURE_RES_NUM = "RESNUM";
+
+ private static String currentDefaultFormat = DBRefSource.PDB;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see jalview.ws.DbSourceProxy#getAccessionSeparator()
+ */
+ @Override
+ public String getAccessionSeparator()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see jalview.ws.DbSourceProxy#getAccessionValidator()
+ */
+ @Override
+ public Regex getAccessionValidator()
+ {
+ return new Regex("([1-9][0-9A-Za-z]{3}):?([ _A-Za-z0-9]?)");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see jalview.ws.DbSourceProxy#getDbSource()
+ */
+ @Override
+ public String getDbSource()
+ {
+ return DBRefSource.PDB;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see jalview.ws.DbSourceProxy#getDbVersion()
+ */
+ @Override
+ public String getDbVersion()
+ {
+ return "0";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see jalview.ws.DbSourceProxy#getSequenceRecords(java.lang.String[])
+ */
+ @Override
+ public AlignmentI getSequenceRecords(String queries) throws Exception
+ {
+ AlignmentI pdbAlignment = null;
+ Vector result = new Vector();
+ String chain = null;
+ String id = null;
+ if (queries.indexOf(":") > -1)
+ {
+ chain = queries.substring(queries.indexOf(":") + 1);
+ id = queries.substring(0, queries.indexOf(":"));
+ }
+ else
+ {
+ id = queries;
+ }
+ if (queries.length() > 4 && chain == null)
+ {
+ chain = queries.substring(4, 5);
+ id = queries.substring(0, 4);
+ }
+ if (!isValidReference(id))
+ {
+ System.err.println("Ignoring invalid pdb query: '" + id + "'");
+ stopQuery();
+ return null;
+ }
+ String ext = getCurrentDefaultFormat().equalsIgnoreCase("mmcif") ? ".cif"
+ : ".xml";
+ EBIFetchClient ebi = new EBIFetchClient();
+ file = ebi.fetchDataAsFile("pdb:" + id,
+<<<<<<< HEAD
+ getCurrentDefaultFomart().toLowerCase(), ext)
+=======
+ getCurrentDefaultFormat().toLowerCase(), "raw", ext)
+>>>>>>> develop
+ .getAbsolutePath();
+ stopQuery();
+ if (file == null)
+ {
+ return null;
+ }
+ try
+ {
+
+ pdbAlignment = new FormatAdapter().readFile(file,
+ jalview.io.AppletFormatAdapter.FILE,
+ getCurrentDefaultFormat());
+ if (pdbAlignment != null)
+ {
+ List<SequenceI> toremove = new ArrayList<SequenceI>();
+ for (SequenceI pdbcs : pdbAlignment.getSequences())
+ {
+ String chid = null;
+ // Mapping map=null;
+ for (PDBEntry pid : pdbcs.getAllPDBEntries())
+ {
+ if (pid.getFile() == file)
+ {
+ chid = pid.getChainCode();
+
+ }
+ ;
+
+ }
+ if (chain == null
+ || (chid != null && (chid.equals(chain)
+ || chid.trim().equals(chain.trim()) || (chain
+ .trim().length() == 0 && chid.equals("_")))))
+ {
+ pdbcs.setName(jalview.datamodel.DBRefSource.PDB + "|" + id
+ + "|" + pdbcs.getName());
+ // Might need to add more metadata to the PDBEntry object
+ // like below
+ /*
+ * PDBEntry entry = new PDBEntry(); // Construct the PDBEntry
+ * entry.setId(id); if (entry.getProperty() == null)
+ * entry.setProperty(new Hashtable());
+ * entry.getProperty().put("chains", pdbchain.id + "=" +
+ * sq.getStart() + "-" + sq.getEnd());
+ * sq.getDatasetSequence().addPDBId(entry);
+ */
+ // Add PDB DB Refs
+ // We make a DBRefEtntry because we have obtained the PDB file from
+ // a
+ // verifiable source
+ // JBPNote - PDB DBRefEntry should also carry the chain and mapping
+ // information
+ DBRefEntry dbentry = new DBRefEntry(getDbSource(),
+ getDbVersion(), (chid == null ? id : id + chid));
+ // dbentry.setMap()
+ pdbcs.addDBRef(dbentry);
+ }
+ else
+ {
+ // mark this sequence to be removed from the alignment
+ // - since it's not from the right chain
+ toremove.add(pdbcs);
+ }
+ }
+ // now remove marked sequences
+ for (SequenceI pdbcs : toremove)
+ {
+ pdbAlignment.deleteSequence(pdbcs);
+ if (pdbcs.getAnnotation() != null)
+ {
+ for (AlignmentAnnotation aa : pdbcs.getAnnotation())
+ {
+ pdbAlignment.deleteAnnotation(aa);
+ }
+ }
+ }
+ }
+
+ if (pdbAlignment == null || pdbAlignment.getHeight() < 1)
+ {
+ throw new Exception(MessageManager.formatMessage(
+ "exception.no_pdb_records_for_chain", new String[] { id,
+ ((chain == null) ? "' '" : chain) }));
+ }
+
+ } catch (Exception ex) // Problem parsing PDB file
+ {
+ stopQuery();
+ throw (ex);
+ }
+ return pdbAlignment;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see jalview.ws.DbSourceProxy#isValidReference(java.lang.String)
+ */
+ @Override
+ public boolean isValidReference(String accession)
+ {
+ Regex r = getAccessionValidator();
+ return r.search(accession.trim());
+ }
+
+ /**
+ * obtain human glyoxalase chain A sequence
+ */
+ @Override
+ public String getTestQuery()
+ {
+ return "1QIPA";
+ }
+
+ @Override
+ public String getDbName()
+ {
+ return "PDB"; // getDbSource();
+ }
+
+ @Override
+ public int getTier()
+ {
+ return 0;
+ }
+
+ public static String getCurrentDefaultFormat()
+ {
+ return currentDefaultFormat;
+ }
+
+ public static void setCurrentDefaultFormat(String currentDefaultFomart)
+ {
+ Pdb.currentDefaultFormat = currentDefaultFomart;
+ }
+
+ /**
+ * Returns a descriptor for suitable feature display settings with
+ * <ul>
+ * <li>ResNums or insertions features visible</li>
+ * <li>insertions features coloured red</li>
+ * <li>ResNum features coloured by label</li>
+ * <li>Insertions displayed above (on top of) ResNums</li>
+ * </ul>
+ */
+ @Override
+ public FeatureSettingsModelI getFeatureColourScheme()
+ {
+ return new PDBFeatureSettings();
+ }
+}
return loadingDasSources;
}
+ @Override
public String getDasRegistryURL()
{
String registry = jalview.bin.Cache.getDefault("DAS_REGISTRY_URL",
return dsrc;
} catch (Exception ex)
{
- System.err.println("Failed to contact DAS1 registry at "
- + registryURL);
- ex.printStackTrace();
+ System.out.println("DAS1 registry at " + registryURL
+ + " no longer exists");
return new ArrayList<jalviewSourceI>();
}
}
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentView;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
import jalview.gui.Desktop;
return null;
}
AlignmentI al = null;
- ColumnSelection alcsel = null;
+ HiddenColumns alhidden = null;
int FirstSeq = -1; // the position of the query sequence in Alignment al
JpredResult result = (JpredResult) this.result;
if (predMap != null)
{
Object[] alandcolsel = input
- .getAlignmentAndColumnSelection(getGapChar());
+ .getAlignmentAndHiddenColumns(getGapChar());
sqs = (SequenceI[]) alandcolsel[0];
al = new Alignment(sqs);
- alcsel = (ColumnSelection) alandcolsel[1];
+ alhidden = (HiddenColumns) alandcolsel[1];
}
else
{
{
char gc = getGapChar();
SequenceI[] sqs = (SequenceI[]) input
- .getAlignmentAndColumnSelection(gc)[0];
+ .getAlignmentAndHiddenColumns(gc)[0];
if (this.msaIndex >= sqs.length)
{
throw new Error(
{
// Adjust input view for gaps
// propagate insertions into profile
- alcsel = ColumnSelection.propagateInsertions(profileseq, al,
+ alhidden = HiddenColumns.propagateInsertions(profileseq, al,
input);
}
}
alant.sequenceRef);
}
}
- return new Object[] { al, alcsel }; // , FirstSeq, noMsa};
+ return new Object[] { al, alhidden }; // , FirstSeq, noMsa};
}
/**
if (res[1] != null)
{
af = new AlignFrame((Alignment) res[0],
- (ColumnSelection) res[1], AlignFrame.DEFAULT_WIDTH,
+ (HiddenColumns) res[1], AlignFrame.DEFAULT_WIDTH,
AlignFrame.DEFAULT_HEIGHT);
}
else
*/
af = new AlignFrame((Alignment) res[0],
- (ColumnSelection) res[1], AlignFrame.DEFAULT_WIDTH,
+ (HiddenColumns) res[1],
+ AlignFrame.DEFAULT_WIDTH,
AlignFrame.DEFAULT_HEIGHT);
}
Desktop.addInternalFrame(af, altitle, AlignFrame.DEFAULT_WIDTH,
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentOrder;
import jalview.datamodel.AlignmentView;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
import jalview.gui.Desktop;
orders[j] = null;
}
SequenceI[] alignment = (SequenceI[]) newview[0];
- ColumnSelection columnselection = (ColumnSelection) newview[1];
+ HiddenColumns hidden = (HiddenColumns) newview[1];
Alignment al = new Alignment(alignment);
// TODO: add 'provenance' property to alignment from the method notes
// accompanying each subjob
if (newFrame)
{
- AlignFrame af = new AlignFrame(al, columnselection,
+ AlignFrame af = new AlignFrame(al, hidden,
AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
// initialise with same renderer settings as in parent alignframe.
AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
if (nf != null)
{
- af.ShowNewickTree(nf, MessageManager.formatMessage(
+ af.showNewickTree(nf, MessageManager.formatMessage(
"label.tree_from", new String[] { this.alTitle }));
}
// initialise with same renderer settings as in parent alignframe.
+++ /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.
- */
-package jalview.ws.jws2;
-
-import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.Annotation;
-import jalview.gui.AlignFrame;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
-import jalview.ws.params.ArgumentI;
-import jalview.ws.params.OptionI;
-import jalview.ws.params.WsParamSetI;
-import jalview.ws.uimodel.AlignAnalysisUIText;
-
-import java.awt.Color;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import compbio.data.sequence.FastaSequence;
-import compbio.data.sequence.JpredAlignment;
-import compbio.metadata.Argument;
-
-public class JPred301Client extends JabawsMsaInterfaceAlignCalcWorker
-{
- /**
- *
- * @return default args for this service when run as dynamic web service
- */
- public List<Argument> selectDefaultArgs()
- {
- List<ArgumentI> rgs = new ArrayList<ArgumentI>();
- for (ArgumentI argi : service.getParamStore().getServiceParameters())
- {
- if (argi instanceof OptionI)
- {
- List<String> o = ((OptionI) argi).getPossibleValues();
- if (o.contains("-pred-nohits"))
- {
- OptionI cpy = ((OptionI) argi).copy();
- cpy.setValue("-pred-nohits");
- rgs.add(cpy);
- }
- }
- }
- return JabaParamStore.getJabafromJwsArgs(rgs);
- }
-
- public JPred301Client(Jws2Instance service, AlignFrame alignFrame,
- WsParamSetI preset, List<Argument> paramset)
- {
- super(service, alignFrame, preset, paramset);
- submitGaps = true;
- alignedSeqs = true;
- nucleotidesAllowed = false;
- proteinAllowed = true;
- gapMap = new boolean[0];
- updateParameters(null, selectDefaultArgs());
- }
-
- @Override
- boolean checkValidInputSeqs(boolean dynamic, List<FastaSequence> seqs)
- {
- return (seqs.size() > 1);
- }
-
- @Override
- public String getServiceActionText()
- {
- return "calculating consensus secondary structure prediction using JPred service";
- }
-
- private static Map<String, String[]> jpredRowLabels = new HashMap<String, String[]>();
-
- private static final Set<String> jpredRes_graph;
-
- private static final Set<String> jpredRes_ssonly;
- static
- {
- jpredRes_ssonly = new HashSet<String>();
- jpredRes_ssonly.add("jnetpred".toLowerCase());
- jpredRes_ssonly.add("jnetpssm".toLowerCase());
- jpredRes_ssonly.add("jnethmm".toLowerCase());
- jpredRes_graph = new HashSet<String>();
- jpredRes_graph.add("jnetconf".toLowerCase());
- jpredRes_graph.add("jnet burial".toLowerCase());
- }
-
- /**
- * update the consensus annotation from the sequence profile data using
- * current visualization settings.
- */
- @Override
- public void updateResultAnnotation(boolean immediate)
- {
- if (immediate || !calcMan.isWorking(this) && msascoreset != null)
- {
- if (msascoreset instanceof compbio.data.sequence.JpredAlignment)
- {
- JpredAlignment jpres = (JpredAlignment) msascoreset;
- int alWidth = alignViewport.getAlignment().getWidth();
- ArrayList<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
- char[] sol = new char[jpres.getJpredSequences().get(0).getLength()];
- boolean firstsol = true;
- for (FastaSequence fsq : jpres.getJpredSequences())
- {
- String[] k = jpredRowLabels.get(fsq.getId());
- if (k == null)
- {
- k = new String[] { fsq.getId(), "JNet Output" };
- }
- if (fsq.getId().startsWith("JNETSOL"))
- {
- char amnt = (fsq.getId().endsWith("25") ? "3" : fsq.getId()
- .endsWith("5") ? "6" : "9").charAt(0);
- char[] vseq = fsq.getSequence().toCharArray();
- for (int spos = 0, sposL = fsq.getLength(); spos < sposL; spos++)
- {
- if (firstsol)
- {
- sol[spos] = '0';
- }
- if (vseq[spos] == 'B'
- && (sol[spos] == '0' || sol[spos] < amnt))
- {
- sol[spos] = amnt;
- }
- }
- firstsol = false;
- }
- else
- {
- createAnnotationRowFromString(
- ourAnnot,
- getCalcId(),
- alWidth,
- k[0],
- k[1],
- jpredRes_graph.contains(fsq.getId()) ? AlignmentAnnotation.BAR_GRAPH
- : AlignmentAnnotation.NO_GRAPH, 0f, 9f,
- fsq.getSequence());
- }
-
- }
- createAnnotationRowFromString(
- ourAnnot,
- getCalcId(),
- alWidth,
- "Jnet Burial",
- "<html>Prediction of Solvent Accessibility<br/>levels are<ul><li>0 - Exposed</li><li>3 - 25% or more S.A. accessible</li><li>6 - 5% or more S.A. accessible</li><li>9 - Buried (<5% exposed)</li></ul>",
- AlignmentAnnotation.BAR_GRAPH, 0f, 9f, new String(sol));
- for (FastaSequence fsq : jpres.getSequences())
- {
- if (fsq.getId().equalsIgnoreCase("QUERY"))
- {
- createAnnotationRowFromString(ourAnnot, getCalcId(), alWidth,
- "Query", "JPred Reference Sequence",
- AlignmentAnnotation.NO_GRAPH, 0f, 0f, fsq.getSequence());
- }
- }
- if (ourAnnot.size() > 0)
- {
- updateOurAnnots(ourAnnot);
- }
- }
- }
- }
-
- private void createAnnotationRowFromString(
- ArrayList<AlignmentAnnotation> ourAnnot, String calcId,
- int alWidth, String label, String descr, int rowType, float min,
- float max, String jpredPrediction)
- {
- // simple annotation row
- AlignmentAnnotation annotation = alignViewport.getAlignment()
- .findOrCreateAnnotation(label, calcId, true, null, null);
- if (alWidth == gapMap.length) // scr.getScores().size())
- {
- annotation.label = new String(label);
- annotation.description = new String(descr);
- annotation.graph = rowType;
- annotation.graphMin = min;
- annotation.graphMax = max;
- if (constructAnnotationFromString(annotation, jpredPrediction,
- alWidth, rowType))
- {
- // created a valid annotation from the data
- ourAnnot.add(annotation);
- // annotation.validateRangeAndDisplay();
- }
- }
- }
-
- private boolean constructAnnotationFromString(
- AlignmentAnnotation annotation, String sourceData, int alWidth,
- int rowType)
- {
- if (sourceData.length() == 0 && alWidth > 0)
- {
- return false;
- }
- Annotation[] elm = new Annotation[alWidth];
- boolean ssOnly = jpredRes_ssonly.contains(annotation.label
- .toLowerCase());
- boolean graphOnly = rowType != AlignmentAnnotation.NO_GRAPH;
- if (!ssOnly && !graphOnly)
- {
- // for burial 'B'
- annotation.showAllColLabels = true;
- }
-
- for (int i = 0, iSize = sourceData.length(); i < iSize; i++)
- {
- char annot = sourceData.charAt(i);
- // if we're at a gapped column then skip to next ungapped position
- if (gapMap != null && gapMap.length > 0)
- {
- while (!gapMap[i])
- {
- elm[i++] = new Annotation("", "", ' ', Float.NaN);
- }
- }
- switch (rowType)
- {
- case AlignmentAnnotation.NO_GRAPH:
- elm[i] = ssOnly ? new Annotation("", "", annot, Float.NaN,
- colourSS(annot)) : new Annotation("" + annot, "" + annot,
- '\0', Float.NaN);
- break;
- default:
- try
- {
- elm[i] = new Annotation("" + annot, "" + annot, annot,
- Integer.valueOf("" + annot));
- } catch (Exception x)
- {
- System.err.println("Expected numeric value in character '"
- + annot + "'");
- }
- }
- }
-
- annotation.annotations = elm;
- annotation.belowAlignment = true;
- annotation.validateRangeAndDisplay();
- return true;
- }
-
- private Color colourSS(char annot)
- {
- switch (annot)
- {
- case 'H':
- return jalview.renderer.AnnotationRenderer.HELIX_COLOUR;
- case 'E':
- return jalview.renderer.AnnotationRenderer.SHEET_COLOUR;
- }
- return jalview.renderer.AnnotationRenderer.GLYPHLINE_COLOR;
- }
-
- @Override
- public String getCalcId()
- {
- return CALC_ID;
- }
-
- private static String CALC_ID = "jabaws21.JPred3Cons";
-
- public static AlignAnalysisUIText getAlignAnalysisUITest()
- {
- return new AlignAnalysisUIText(
- compbio.ws.client.Services.JpredWS.toString(),
- jalview.ws.jws2.JPred301Client.class, CALC_ID, false, true,
- true, "JPred Consensus",
- "When checked, JPred consensus is updated automatically.",
- "Change JPred Settings...",
- "Modify settings for JPred calculations.");
- }
-}
/*
* the .jalview_properties entry for JWS2 URLS
*/
- final static String JWS2HOSTURLS = "JWS2HOSTURLS";
+ private final static String JWS2HOSTURLS = "JWS2HOSTURLS";
/*
* Singleton instance
private PropertyChangeSupport changeSupport = new PropertyChangeSupport(
this);
- Vector<String> invalidServiceUrls = null, urlsWithoutServices = null,
- validServiceUrls = null;
+ private Vector<String> invalidServiceUrls = null;
- boolean running = false, aborted = false;
+ private Vector<String> urlsWithoutServices = null;
- Thread oldthread = null;
+ private Vector<String> validServiceUrls = null;
+
+ private volatile boolean running = false;
+
+ private volatile boolean aborted = false;
+
+ private Thread oldthread = null;
/**
* holds list of services.
public void setAborted(boolean aborted)
{
this.aborted = aborted;
-
}
+ @Override
public void run()
{
{
}
}
+ aborted = false;
Cache.log.debug("Old discovery thread has finished.");
}
running = true;
ignoredServices.add(ignored);
}
- changeSupport.firePropertyChange("services", services, new Vector());
+ changeSupport.firePropertyChange("services", services,
+ new Vector<Jws2Instance>());
oldthread = Thread.currentThread();
try
{
if (!aborted)
{
// resort services according to order found in jabaws service list
- // also ensure servics for each host are ordered in same way.
+ // also ensure services for each host are ordered in same way.
if (services != null && services.size() > 0)
{
}
oldthread = null;
running = false;
- changeSupport.firePropertyChange("services", new Vector(), services);
+ changeSupport.firePropertyChange("services",
+ new Vector<Jws2Instance>(), services);
}
/**
service.hasParameters();
if (validServiceUrls == null)
{
- validServiceUrls = new Vector();
+ validServiceUrls = new Vector<String>();
}
validServiceUrls.add(jwsservers);
}
* attach all available web services to the appropriate submenu in the given
* JMenu
*/
+ @Override
public void attachWSMenuEntry(JMenu wsmenu, final AlignFrame alignFrame)
{
// dynamically regenerate service list.
{
return;
}
- boolean byhost = Cache.getDefault("WSMENU_BYHOST", false), bytype = Cache
- .getDefault("WSMENU_BYTYPE", false);
+
/**
* eventually, JWS2 services will appear under the same align/etc submenus.
* for moment we keep them separate.
{
new Thread(new Runnable()
{
+ @Override
public void run()
{
setPreferredServiceFor(alignFrame, sv.serviceType,
sv.action, sv);
changeSupport.firePropertyChange("services",
- new Vector(), services);
+ new Vector<Jws2Instance>(), services);
};
}).start();
}
});
}
- /*
- * hitm.addActionListener(new ActionListener() {
- *
- * @Override public void actionPerformed(ActionEvent arg0) { new
- * Thread(new Runnable() {
- *
- * @Override public void run() { new SetPreferredServer(alignFrame,
- * service.serviceType, service.action); } }).start(); } });
- */
}
}
}
* for moment we keep them separate.
*/
JMenu atpoint;
- MsaWSClient msacl = new MsaWSClient();
+
List<String> hostLabels = new ArrayList<String>();
Hashtable<String, String> lasthostFor = new Hashtable<String, String>();
Hashtable<String, ArrayList<Jws2Instance>> hosts = new Hashtable<String, ArrayList<Jws2Instance>>();
new PropertyChangeListener()
{
+ @Override
public void propertyChange(PropertyChangeEvent evt)
{
if (getDiscoverer().services != null)
return true;
}
+ public boolean restart()
+ {
+ synchronized (this)
+ {
+ if (running)
+ {
+ aborted = true;
+ }
+ else
+ {
+ running = true;
+ }
+ return aborted;
+ }
+ }
+
/**
* Start a fresh discovery thread and notify the given object when we're
* finished. Any known existing threads will be killed before this one is
*/
public Thread startDiscoverer(PropertyChangeListener changeSupport2)
{
+ /* if (restart())
+ {
+ return;
+ }
+ else
+ {
+ Thread thr = new Thread(this);
+ thr.start();
+ }
+ */
if (isRunning())
{
setAborted(true);
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentOrder;
import jalview.datamodel.AlignmentView;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
orders[j] = null;
}
SequenceI[] alignment = (SequenceI[]) newview[0];
- ColumnSelection columnselection = (ColumnSelection) newview[1];
+ HiddenColumns hidden = (HiddenColumns) newview[1];
Alignment al = new Alignment(alignment);
// TODO: add 'provenance' property to alignment from the method notes
if (lastProgram != null)
if (newFrame)
{
- displayInNewFrame(al, alorders, columnselection);
+ displayInNewFrame(al, alorders, hidden);
}
else
* @param columnselection
*/
protected void displayInNewFrame(AlignmentI al,
- List<AlignmentOrder> alorders, ColumnSelection columnselection)
+ List<AlignmentOrder> alorders, HiddenColumns hidden)
{
- AlignFrame af = new AlignFrame(al, columnselection,
+ AlignFrame af = new AlignFrame(al, hidden,
AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
// initialise with same renderer settings as in parent alignframe.
package jalview.ws.jws2.jabaws2;
import jalview.ws.jws2.AAConClient;
-import jalview.ws.jws2.JPred301Client;
import jalview.ws.jws2.RNAalifoldClient;
import jalview.ws.uimodel.AlignAnalysisUIText;
AAConClient.getAlignAnalysisUITest());
aaConGUI.put(compbio.ws.client.Services.RNAalifoldWS.toString(),
RNAalifoldClient.getAlignAnalysisUITest());
- // disable the JPred301 client in jalview ...
+ // ignore list for JABAWS services not supported in jalview ...
ignoreGUI = new HashSet<String>();
- ignoreGUI.add(compbio.ws.client.Services.JpredWS.toString());
- aaConGUI.put(compbio.ws.client.Services.JpredWS.toString(),
- JPred301Client.getAlignAnalysisUITest());
}
}
{
// intersect groups with selected region
_input = new AlignmentView(av.getAlignment(),
- av.getColumnSelection(), av.getSelectionGroup(),
+ av.getAlignment()
+ .getHiddenColumns(), av.getSelectionGroup(),
av.hasHiddenColumns(), true, true);
viewTitle = MessageManager.formatMessage(
"label.select_visible_region_of",
{
// use selected region to partition alignment
_input = new AlignmentView(av.getAlignment(),
- av.getColumnSelection(), av.getSelectionGroup(),
+ av.getAlignment()
+ .getHiddenColumns(), av.getSelectionGroup(),
av.hasHiddenColumns(), false, true);
}
viewTitle = MessageManager.formatMessage(
{
// just take selected region intersection
_input = new AlignmentView(av.getAlignment(),
- av.getColumnSelection(), av.getSelectionGroup(),
+ av.getAlignment()
+ .getHiddenColumns(), av.getSelectionGroup(),
av.hasHiddenColumns(), true, true);
viewTitle = MessageManager.formatMessage(
"label.select_visible_region_of",
{
// standard alignment view without selection present
_input = new AlignmentView(av.getAlignment(),
- av.getColumnSelection(), null, av.hasHiddenColumns(), false,
+ av.getAlignment()
+ .getHiddenColumns(), null, av.hasHiddenColumns(), false,
true);
viewTitle = ""
+ (av.hasHiddenColumns() ? (new StringBuffer(" ")
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentOrder;
import jalview.datamodel.Annotation;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
private String getStage(Stage stg)
{
if (stg == Stage.SUBMIT)
+ {
return "submitting ";
+ }
if (stg == Stage.POLL)
+ {
return "checking status of ";
+ }
return (" being confused about ");
}
// total number of distinct alignment sets generated by job set.
int numAlSets = 0, als = 0;
List<AlignmentI> destAls = new ArrayList<AlignmentI>();
- List<jalview.datamodel.ColumnSelection> destColsel = new ArrayList<jalview.datamodel.ColumnSelection>();
+ List<jalview.datamodel.HiddenColumns> destColsel = new ArrayList<jalview.datamodel.HiddenColumns>();
List<List<NewickFile>> trees = new ArrayList<List<NewickFile>>();
do
RestJob rj = (RestJob) jobs[nrj];
int contigs[] = input.getVisibleContigs();
AlignmentI destAl = null;
- jalview.datamodel.ColumnSelection destCs = null;
+ jalview.datamodel.HiddenColumns destHCs = null;
// Resolve destAl for this data.
if (als == 0 && rj.isInputContextModified())
{
if (!restClient.isAlignmentModified() && merge)
{
destAl = restClient.av.getAlignment();
- destCs = restClient.av.getColumnSelection();
+ destHCs = restClient.av.getAlignment().getHiddenColumns();
resultDest
.add(restClient.isShowResultsInNewView() ? AddDataTo.newView
: AddDataTo.currentView);
newAlignment = true;
// recreate the input alignment data
Object[] idat = input
- .getAlignmentAndColumnSelection(gapCharacter);
+ .getAlignmentAndHiddenColumns(gapCharacter);
destAl = new Alignment((SequenceI[]) idat[0]);
- destCs = (ColumnSelection) idat[1];
+ destHCs = (HiddenColumns) idat[1];
resultDest.add(AddDataTo.newAlignment);
// but do not add to the alignment panel list - since we need to
// create a whole new alignFrame set.
}
destAls.add(destAl);
- destColsel.add(destCs);
+ destColsel.add(destHCs);
}
}
else
// recover reference to last alignment created for this rest frame
// ready for extension
destAl = destAls.get(als);
- destCs = destColsel.get(als);
+ destHCs = destColsel.get(als);
}
else
{
newview = input.getUpdatedView(rseqs, orders, gapCharacter);
}
destAl = new Alignment((SequenceI[]) newview[0]);
- destCs = (ColumnSelection) newview[1];
+ destHCs = (HiddenColumns) newview[1];
newAlignment = true;
// TODO create alignment from result data with propagated
// references.
destAls.add(destAl);
- destColsel.add(destCs);
+ destColsel.add(destHCs);
resultDest.add(AddDataTo.newAlignment);
throw new Error(
MessageManager
for (AddDataTo action : resultDest)
{
AlignmentI destal;
- ColumnSelection destcs;
+ HiddenColumns destcs;
String alTitle = MessageManager.formatMessage(
"label.webservice_job_title_on", new String[] {
restClient.service.details.Action,
package jalview.ws.sifts;
import jalview.analysis.AlignSeq;
+import jalview.analysis.scoremodels.ScoreMatrix;
+import jalview.analysis.scoremodels.ScoreModels;
import jalview.api.DBRefEntryI;
import jalview.api.SiftsClientI;
import jalview.datamodel.DBRefEntry;
public class SiftsClient implements SiftsClientI
{
+ /*
+ * for use in mocking out file fetch for tests only
+ * - reset to null after testing!
+ */
+ private static File mockSiftsFile;
+
private Entry siftsEntry;
private StructureFile pdb;
*/
public static File getSiftsFile(String pdbId) throws SiftsException
{
+ /*
+ * return mocked file if it has been set
+ */
+ if (mockSiftsFile != null)
+ {
+ return mockSiftsFile;
+ }
+
String siftsFileName = SiftsSettings.getSiftDownloadDirectory()
+ pdbId.toLowerCase() + ".xml.gz";
File siftsFile = new File(siftsFileName);
.equalsIgnoreCase(seqCoordSys.getName())
&& isAccessionMatched(cRefDb.getDbAccessionId()))
{
- String resNumIndexString = cRefDb.getDbResNum()
- .equalsIgnoreCase("None") ? String.valueOf(UNASSIGNED)
- : cRefDb.getDbResNum();
- try
- {
- currSeqIndex = Integer.valueOf(resNumIndexString);
- } catch (NumberFormatException nfe)
- {
- currSeqIndex = Integer.valueOf(resNumIndexString
- .split("[a-zA-Z]")[0]);
- continue;
- }
+ currSeqIndex = getLeadingIntegerValue(
+ cRefDb.getDbResNum(), UNASSIGNED);
if (pdbRefDb != null)
{
break;// exit loop if pdb and uniprot are already found
}
if (currSeqIndex >= seq.getStart() && currSeqIndex <= seq.getEnd())
{
- int resNum;
- try
- {
- resNum = (pdbRefDb == null) ? Integer.valueOf(residue
- .getDbResNum()) : Integer.valueOf(pdbRefDb
- .getDbResNum());
- } catch (NumberFormatException nfe)
- {
- resNum = (pdbRefDb == null) ? Integer.valueOf(residue
- .getDbResNum()) : Integer.valueOf(pdbRefDb
- .getDbResNum().split("[a-zA-Z]")[0]);
- continue;
- }
+
+ int resNum = (pdbRefDb == null) ? getLeadingIntegerValue(
+ residue.getDbResNum(), UNASSIGNED)
+ : getLeadingIntegerValue(pdbRefDb.getDbResNum(),
+ UNASSIGNED);
if (isResidueObserved(residue)
|| seqCoordSys == CoordinateSys.UNIPROT)
}
/**
+ * Get the leading integer part of a string that begins with an integer.
+ *
+ * @param input
+ * - the string input to process
+ * @param failValue
+ * - value returned if unsuccessful
+ * @return
+ */
+ static int getLeadingIntegerValue(String input, int failValue)
+ {
+ if (input == null)
+ {
+ return failValue;
+ }
+ String[] parts = input.split("(?=\\D)(?<=\\d)");
+ if (parts != null && parts.length > 0 && parts[0].matches("[0-9]+"))
+ {
+ return Integer.valueOf(parts[0]);
+ }
+ return failValue;
+ }
+
+
+ /**
*
* @param chainId
* Target chain to populate mapping of its atom positions.
}
@Override
- public StringBuffer getMappingOutput(MappingOutputPojo mp)
+ public StringBuilder getMappingOutput(MappingOutputPojo mp)
throws SiftsException
{
String seqRes = mp.getSeqResidue();
int nochunks = ((seqRes.length()) / len)
+ ((seqRes.length()) % len > 0 ? 1 : 0);
// output mappings
- StringBuffer output = new StringBuffer();
+ StringBuilder output = new StringBuilder(512);
output.append(NEWLINE);
output.append("Sequence \u27f7 Structure mapping details").append(
NEWLINE);
output.append(String.valueOf(pdbEnd));
output.append(NEWLINE).append(NEWLINE);
+ ScoreMatrix pam250 = ScoreModels.getInstance().getPam250();
int matchedSeqCount = 0;
for (int j = 0; j < nochunks; j++)
{
output.append(NEWLINE);
output.append(new Format("%" + (maxid) + "s").form(" ")).append(" ");
- // Print out the matching chars
+ /*
+ * Print out the match symbols:
+ * | for exact match (ignoring case)
+ * . if PAM250 score is positive
+ * else a space
+ */
for (int i = 0; i < len; i++)
{
try
{
if ((i + (j * len)) < seqRes.length())
{
- boolean sameChar = Comparison.isSameResidue(
- seqRes.charAt(i + (j * len)),
- strRes.charAt(i + (j * len)), false);
- if (sameChar
- && !jalview.util.Comparison.isGap(seqRes.charAt(i
- + (j * len))))
+ char c1 = seqRes.charAt(i + (j * len));
+ char c2 = strRes.charAt(i + (j * len));
+ boolean sameChar = Comparison.isSameResidue(c1, c2, false);
+ if (sameChar && !Comparison.isGap(c1))
{
matchedSeqCount++;
output.append("|");
}
else if (type.equals("pep"))
{
- if (ResidueProperties.getPAM250(seqRes.charAt(i + (j * len)),
- strRes.charAt(i + (j * len))) > 0)
+ if (pam250.getPairwiseScore(c1, c2) > 0)
{
output.append(".");
}
return siftsEntry.getDbVersion();
}
+ public static void setMockSiftsFile(File file)
+ {
+ mockSiftsFile = file;
+ }
+
}
* the name of file to save the URLs to
* @throws IOException
*/
- public void download(String urlstring, String outfile) throws IOException
+ public static void download(String urlstring, String outfile)
+ throws IOException
{
FileOutputStream fos = null;
ReadableByteChannel rbc = null;
*/
package jalview.analysis;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
+import jalview.datamodel.Sequence;
import jalview.gui.JvOptionPane;
import org.testng.annotations.BeforeClass;
assertNull(AlignSeq.extractGaps(null, "ACG"));
assertNull(AlignSeq.extractGaps("-. ", null));
- assertEquals(" AC-G.T", AlignSeq.extractGaps("", " AC-G.T"));
- assertEquals("AC-G.T", AlignSeq.extractGaps(" ", " AC-G.T"));
- assertEquals("ACG.T", AlignSeq.extractGaps(" -", " AC-G.T"));
- assertEquals("ACGT", AlignSeq.extractGaps(" -.", " AC-G.T ."));
- assertEquals(" ACG.T", AlignSeq.extractGaps("-", " AC-G.T"));
+ assertEquals(AlignSeq.extractGaps("", " AC-G.T"), " AC-G.T");
+ assertEquals(AlignSeq.extractGaps(" ", " AC-G.T"), "AC-G.T");
+ assertEquals(AlignSeq.extractGaps(" -", " AC-G.T"), "ACG.T");
+ assertEquals(AlignSeq.extractGaps(" -.", " AC-G.T ."), "ACGT");
+ assertEquals(AlignSeq.extractGaps("-", " AC-G.T"), " ACG.T");
+ }
+
+ @Test(groups = { "Functional" })
+ public void testIndexEncode_nucleotide()
+ {
+ AlignSeq as = new AlignSeq(new Sequence("s1", "TTAG"), new Sequence(
+ "s2", "ACGT"), AlignSeq.DNA);
+ int[] expected = new int[] { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, -1, -1, 10, -1 };
+ String s = "aAcCgGtTuUiIxXrRyYnN .-?";
+ assertArrayEquals(expected, as.indexEncode(s));
+ }
+
+ @Test(groups = { "Functional" })
+ public void testIndexEncode_peptide()
+ {
+ AlignSeq as = new AlignSeq(new Sequence("s1", "PFY"), new Sequence(
+ "s2", "RQW"), AlignSeq.PEP);
+ int[] expected = new int[] { 0, 0, 1, 1, 2, 2, 21, 21, 22, 22, -1, 23,
+ -1, -1, -1 };
+ String s = "aArRnNzZxX *.-?";
+ assertArrayEquals(expected, as.indexEncode(s));
}
}
--- /dev/null
+package jalview.analysis;
+
+import static org.testng.Assert.assertSame;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+
+import java.util.Arrays;
+import java.util.List;
+
+import junit.extensions.PA;
+
+import org.testng.annotations.Test;
+
+public class AlignmentSorterTest
+{
+ @Test(groups = "Functional")
+ public void testSortByFeature_score()
+ {
+ SequenceI seq1 = new Sequence("Seq1", "ABC--D-EFGHIJ");
+ SequenceI seq2 = new Sequence("Seq2", "ABCDEFGHIJ");
+ SequenceI seq3 = new Sequence("Seq3", "ABCDE-FGHIJ");
+ SequenceI seq4 = new Sequence("Seq4", "ABCDEFGHIJ");
+ SequenceI[] seqs = new SequenceI[] { seq1, seq2, seq3, seq4 };
+ AlignmentI al = new Alignment(seqs);
+ al.setDataset(null);
+
+ /*
+ * sort with no score features does nothing
+ */
+ PA.setValue(AlignmentSorter.class, "lastSortByFeatureScore", null);
+
+ AlignmentSorter.sortByFeature((String) null, null, 0, al.getWidth(),
+ al,
+ AlignmentSorter.FEATURE_SCORE);
+ assertSame(al.getSequenceAt(0), seq1);
+ assertSame(al.getSequenceAt(1), seq2);
+ assertSame(al.getSequenceAt(2), seq3);
+ assertSame(al.getSequenceAt(3), seq4);
+
+ /*
+ * add score and non-score features
+ * seq1 Cath(2.0) Pfam(4.0) average 3.0
+ * seq2 Cath(2.5) Metal(NaN) average 2.5
+ * seq3 KD(-4), KD(3.0) average -0.5
+ * seq4 Helix(NaN) - should sort as if largest score
+ */
+ seq1.addSequenceFeature(new SequenceFeature("Cath", "", 2, 3, 2.0f,
+ "g1"));
+ seq1.addSequenceFeature(new SequenceFeature("Pfam", "", 4, 5, 4.0f,
+ "g2"));
+ seq2.addSequenceFeature(new SequenceFeature("Cath", "", 2, 3, 2.5f,
+ "g3"));
+ seq2.addSequenceFeature(new SequenceFeature("Metal", "", 2, 3,
+ Float.NaN, "g4"));
+ seq3.addSequenceFeature(new SequenceFeature("kD", "", 2, 3, -4f, "g5"));
+ seq3.addSequenceFeature(new SequenceFeature("kD", "", 5, 6, 3.0f, "g6"));
+ seq4.addSequenceFeature(new SequenceFeature("Helix", "", 2, 3,
+ Float.NaN, "g7"));
+
+ /*
+ * sort by ascending score, no filter on feature type or group
+ * NB sort order for the same feature set (none) gets toggled, so descending
+ */
+ PA.setValue(AlignmentSorter.class, "sortByFeatureScoreAscending", true);
+ AlignmentSorter.sortByFeature((String) null, null, 0, al.getWidth(),
+ al, AlignmentSorter.FEATURE_SCORE);
+ assertSame(al.getSequenceAt(3), seq3); // -0.5
+ assertSame(al.getSequenceAt(2), seq2); // 2.5
+ assertSame(al.getSequenceAt(1), seq1); // 3.0
+ assertSame(al.getSequenceAt(0), seq4); // maximum 'score'
+
+ /*
+ * repeat sort toggles order - now ascending
+ */
+ AlignmentSorter.sortByFeature((String) null, null, 0, al.getWidth(),
+ al, AlignmentSorter.FEATURE_SCORE);
+ assertSame(al.getSequenceAt(0), seq3); // -0.5
+ assertSame(al.getSequenceAt(1), seq2); // 2.5
+ assertSame(al.getSequenceAt(2), seq1); // 3.0
+ assertSame(al.getSequenceAt(3), seq4);
+
+ /*
+ * specify features, excluding Pfam
+ * seq1 average is now 2.0
+ * next sort is ascending (not toggled) as for a different feature set
+ */
+ List<String> types = Arrays.asList(new String[] { "Cath", "kD" });
+ AlignmentSorter.sortByFeature(types, null, 0, al.getWidth(), al,
+ AlignmentSorter.FEATURE_SCORE);
+ assertSame(al.getSequenceAt(0), seq3); // -0.5
+ assertSame(al.getSequenceAt(1), seq1); // 2.0
+ assertSame(al.getSequenceAt(2), seq2); // 2.5
+ assertSame(al.getSequenceAt(3), seq4);
+
+ /*
+ * specify groups, excluding g5 (kD -4 score)
+ * seq3 average is now 3.0
+ * next sort is ascending (not toggled) as for a different group spec
+ */
+ List<String> groups = Arrays.asList(new String[] { "g1", "g2", "g3",
+ "g6" });
+ AlignmentSorter.sortByFeature(types, groups, 0, al.getWidth(), al,
+ AlignmentSorter.FEATURE_SCORE);
+ assertSame(al.getSequenceAt(0), seq1); // 2.0
+ assertSame(al.getSequenceAt(1), seq2); // 2.5
+ assertSame(al.getSequenceAt(2), seq3); // 3.0
+ assertSame(al.getSequenceAt(3), seq4);
+
+ /*
+ * limit to columns 0-4, excluding 2nd feature of seq1 and seq3
+ * seq1 is now 2.0, seq3 is now -4
+ */
+ // fails because seq1.findPosition(4) returns 4
+ // although residue 4 is in column 5! - JAL-2544
+ AlignmentSorter.sortByFeature((String) null, null, 0, 4, al,
+ AlignmentSorter.FEATURE_SCORE);
+ assertSame(al.getSequenceAt(0), seq3); // -4
+ assertSame(al.getSequenceAt(1), seq1); // 2.0
+ assertSame(al.getSequenceAt(2), seq2); // 2.5
+ assertSame(al.getSequenceAt(3), seq4);
+ }
+
+ @Test(groups = "Functional")
+ public void testSortByFeature_density()
+ {
+ // TODO
+ }
+}
import jalview.datamodel.AlignedCodon;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignViewport;
AlignmentI alf = new FormatAdapter().readFile(
JAL_1312_example_align_fasta, DataSourceType.PASTE,
FileFormat.Fasta);
- ColumnSelection cs = new ColumnSelection();
+ HiddenColumns cs = new HiddenColumns();
AlignViewportI av = new AlignViewport(alf, cs);
Dna dna = new Dna(av, new int[] { 0, alf.getWidth() - 1 });
AlignmentI translated = dna.translateCdna();
int vwidth = 15;
for (int ipos = 0; ipos + vwidth < alf.getWidth(); ipos += vwidth)
{
- ColumnSelection cs = new ColumnSelection();
+ HiddenColumns cs = new HiddenColumns();
if (ipos > 0)
{
cs.hideColumns(0, ipos - 1);
{
AlignmentI alf = new FormatAdapter().readFile(fasta,
DataSourceType.PASTE, FileFormat.Fasta);
- ColumnSelection cs = new ColumnSelection();
+ HiddenColumns cs = new HiddenColumns();
AlignViewportI av = new AlignViewport(alf, cs);
Dna dna = new Dna(av, new int[] { 0, alf.getWidth() - 1 });
AlignmentI translated = dna.translateCdna();
{
AlignmentI alf = new FormatAdapter().readFile(fasta,
DataSourceType.PASTE, FileFormat.Fasta);
- ColumnSelection cs = new ColumnSelection();
+ HiddenColumns cs = new HiddenColumns();
cs.hideColumns(6, 14); // hide codons 3/4/5
cs.hideColumns(24, 35); // hide codons 9-12
cs.hideColumns(177, 191); // hide codons 60-64
*/
AlignmentI cdna = new AlignmentGenerator(true)
.generate(12, 8, 97, 5, 5);
- ColumnSelection cs = new ColumnSelection();
+ HiddenColumns cs = new HiddenColumns();
AlignViewportI av = new AlignViewport(cdna, cs);
Dna dna = new Dna(av, new int[] { 0, cdna.getWidth() - 1 });
AlignmentI translated = dna.translateCdna();
assertEquals(seqDs, al.getSequenceAt(0).getDatasetSequence()
.getSequenceAsString());
- ColumnSelection cs = new ColumnSelection();
+ HiddenColumns cs = new HiddenColumns();
AlignViewportI av = new AlignViewport(al, cs);
Dna testee = new Dna(av, new int[] { 0, al.getWidth() - 1 });
AlignmentI reversed = testee.reverseCdna(false);
};
as.printAlignment(ps);
- String expected = "Score = 320\nLength of alignment = 10\nSequence Seq1 : 3 - 18 (Sequence length = 14)\nSequence Seq1 : 1 - 10 (Sequence length = 10)\n\n"
+ String expected = "Score = 320.0\nLength of alignment = 10\nSequence Seq1 : 3 - 18 (Sequence length = 14)\nSequence Seq1 : 1 - 10 (Sequence length = 10)\n\n"
+ "Seq1 SDFAQQQRRR\n"
+ " ||||||| \n"
+ "Seq1 SDFAQQQSSS\n\n" + "Percentage ID = 70.00\n";
*/
package jalview.analysis.scoremodels;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import jalview.api.analysis.SimilarityParamsI;
+import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
+import jalview.gui.AlignViewport;
import jalview.gui.JvOptionPane;
import jalview.io.DataSourceType;
import jalview.io.FileLoader;
+import jalview.math.MatrixI;
import java.util.Arrays;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
-public class FeatureScoreModelTest
+public class FeatureDistanceModelTest
{
@BeforeClass(alwaysRun = true)
int[] sf3 = new int[] { -1, -1, -1, -1, -1, -1, 76, 77 };
+ /**
+ * <pre>
+ * Load test alignment and add features to sequences:
+ * FER1_MESCR FER1_SPIOL FER3_RAPSA FER1_MAIZE
+ * sf1 X X X
+ * sf2 X X
+ * sf3 X
+ * </pre>
+ *
+ * @return
+ */
public AlignFrame getTestAlignmentFrame()
{
AlignFrame alf = new FileLoader(false).LoadFileWaitTillLoaded(
alf.getFeatureRenderer().findAllFeatures(true);
Assert.assertEquals(alf.getFeatureRenderer().getDisplayedFeatureTypes()
.size(), 3, "Number of feature types");
- Assert.assertTrue(alf.getCurrentView().areFeaturesDisplayed());
+ assertTrue(alf.getCurrentView().areFeaturesDisplayed());
return alf;
}
public void testFeatureScoreModel() throws Exception
{
AlignFrame alf = getTestAlignmentFrame();
- FeatureScoreModel fsm = new FeatureScoreModel();
- Assert.assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
+ FeatureDistanceModel fsm = new FeatureDistanceModel();
+ assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
.getAlignPanel()));
alf.selectAllSequenceMenuItem_actionPerformed(null);
- float[][] dm = fsm.findDistances(alf.getViewport().getAlignmentView(
- true));
- Assert.assertTrue(dm[0][2] == 0f,
+
+ MatrixI dm = fsm.findDistances(
+ alf.getViewport().getAlignmentView(true),
+ SimilarityParams.Jalview);
+ assertEquals(dm.getValue(0, 2), 0d,
"FER1_MESCR (0) should be identical with RAPSA (2)");
- Assert.assertTrue(dm[0][1] > dm[0][2],
+ assertTrue(dm.getValue(0, 1) > dm.getValue(0, 2),
"FER1_MESCR (0) should be further from SPIOL (1) than it is from RAPSA (2)");
}
AlignFrame alf = getTestAlignmentFrame();
// hiding first two columns shouldn't affect the tree
alf.getViewport().hideColumns(0, 1);
- FeatureScoreModel fsm = new FeatureScoreModel();
- Assert.assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
+ FeatureDistanceModel fsm = new FeatureDistanceModel();
+ assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
.getAlignPanel()));
alf.selectAllSequenceMenuItem_actionPerformed(null);
- float[][] dm = fsm.findDistances(alf.getViewport().getAlignmentView(
- true));
- Assert.assertTrue(dm[0][2] == 0f,
+ MatrixI dm = fsm.findDistances(
+ alf.getViewport().getAlignmentView(true),
+ SimilarityParams.Jalview);
+ assertEquals(dm.getValue(0, 2), 0d,
"FER1_MESCR (0) should be identical with RAPSA (2)");
- Assert.assertTrue(dm[0][1] > dm[0][2],
+ assertTrue(dm.getValue(0, 1) > dm.getValue(0, 2),
"FER1_MESCR (0) should be further from SPIOL (1) than it is from RAPSA (2)");
}
// hide columns and check tree changes
alf.getViewport().hideColumns(3, 4);
alf.getViewport().hideColumns(0, 1);
- FeatureScoreModel fsm = new FeatureScoreModel();
- Assert.assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
+ FeatureDistanceModel fsm = new FeatureDistanceModel();
+ assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
.getAlignPanel()));
alf.selectAllSequenceMenuItem_actionPerformed(null);
- float[][] dm = fsm.findDistances(alf.getViewport().getAlignmentView(
- true));
- Assert.assertTrue(
- dm[0][2] == 0f,
+ MatrixI dm = fsm.findDistances(
+ alf.getViewport().getAlignmentView(true),
+ SimilarityParams.Jalview);
+ assertEquals(
+ dm.getValue(0, 2),
+ 0d,
"After hiding last two columns FER1_MESCR (0) should still be identical with RAPSA (2)");
- Assert.assertTrue(
- dm[0][1] == 0f,
+ assertEquals(
+ dm.getValue(0, 1),
+ 0d,
"After hiding last two columns FER1_MESCR (0) should now also be identical with SPIOL (1)");
for (int s = 0; s < 3; s++)
{
- Assert.assertTrue(dm[s][3] > 0f, "After hiding last two columns "
+ assertTrue(dm.getValue(s, 3) > 0d, "After hiding last two columns "
+ alf.getViewport().getAlignment().getSequenceAt(s).getName()
+ "(" + s + ") should still be distinct from FER1_MAIZE (3)");
}
SequenceFeature sf = null;
sf = new SequenceFeature("disulphide bond", "", 2, 5, Float.NaN, "");
aseq.addSequenceFeature(sf);
- Assert.assertTrue(sf.isContactFeature());
+ assertTrue(sf.isContactFeature());
af.refreshFeatureUI(true);
af.getFeatureRenderer().setAllVisible(Arrays.asList("disulphide bond"));
Assert.assertEquals(af.getFeatureRenderer().getDisplayedFeatureTypes()
.size(), 0);
}
+ @Test(groups = { "Functional" })
+ public void testFindDistances() throws Exception
+ {
+ String seqs = ">s1\nABCDE\n>seq2\nABCDE\n";
+ AlignFrame alf = new FileLoader().LoadFileWaitTillLoaded(seqs,
+ DataSourceType.PASTE);
+ SequenceI s1 = alf.getViewport().getAlignment().getSequenceAt(0);
+ SequenceI s2 = alf.getViewport().getAlignment().getSequenceAt(1);
+
+ /*
+ * set domain and variant features thus:
+ * ----5
+ * s1 ddd..
+ * s1 .vvv.
+ * s1 ..vvv
+ * s2 .ddd.
+ * s2 vv..v
+ * The number of unshared feature types per column is
+ * 20120 (two features of the same type doesn't affect score)
+ * giving an average (pairwise distance) of 5/5 or 1.0
+ */
+ s1.addSequenceFeature(new SequenceFeature("domain", null, 1, 3, 0f,
+ null));
+ s1.addSequenceFeature(new SequenceFeature("variant", null, 2, 4, 0f,
+ null));
+ s1.addSequenceFeature(new SequenceFeature("variant", null, 3, 5, 0f,
+ null));
+ s2.addSequenceFeature(new SequenceFeature("domain", null, 2, 4, 0f,
+ null));
+ s2.addSequenceFeature(new SequenceFeature("variant", null, 1, 2, 0f,
+ null));
+ s2.addSequenceFeature(new SequenceFeature("variant", null, 5, 5, 0f,
+ null));
+ alf.setShowSeqFeatures(true);
+ alf.getFeatureRenderer().findAllFeatures(true);
+
+ FeatureDistanceModel fsm = new FeatureDistanceModel();
+ assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
+ .getAlignPanel()));
+ alf.selectAllSequenceMenuItem_actionPerformed(null);
+
+ MatrixI distances = fsm.findDistances(alf.getViewport()
+ .getAlignmentView(true), SimilarityParams.Jalview);
+ assertEquals(distances.width(), 2);
+ assertEquals(distances.height(), 2);
+ assertEquals(distances.getValue(0, 0), 0d);
+ assertEquals(distances.getValue(1, 1), 0d);
+
+ assertEquals(distances.getValue(0, 1), 1d,
+ "expected identical pairs. (check normalisation for similarity score)");
+ assertEquals(distances.getValue(1, 0), 1d);
+ }
+
+ /**
+ * Verify computed distances with varying parameter options
+ */
+ @Test(groups = "Functional")
+ public void testFindDistances_withParams()
+ {
+ AlignFrame af = setupAlignmentView();
+ AlignViewport viewport = af.getViewport();
+ AlignmentView view = viewport.getAlignmentView(false);
+
+ FeatureDistanceModel sm = new FeatureDistanceModel();
+ sm.configureFromAlignmentView(af.alignPanel);
+
+ /*
+ * feature distance model always normalises by region width
+ * gap-gap is always included (but scores zero)
+ * the only variable parameter is 'includeGaps'
+ */
+
+ /*
+ * include gaps
+ * score = 3 + 3 + 0 + 2 + 3 + 2 = 13/6
+ */
+ SimilarityParamsI params = new SimilarityParams(true, true, true, true);
+ MatrixI distances = sm.findDistances(view, params);
+ assertEquals(distances.getValue(0, 0), 0d);
+ assertEquals(distances.getValue(1, 1), 0d);
+ assertEquals(distances.getValue(0, 1), 13d / 6); // should be 13d/6
+ assertEquals(distances.getValue(1, 0), 13d / 6);
+
+ /*
+ * exclude gaps
+ * score = 3 + 3 + 0 + 0 + 0 + 0 = 6/6
+ */
+ params = new SimilarityParams(true, true, false, true);
+ distances = sm.findDistances(view, params);
+ assertEquals(distances.getValue(0, 1), 6d / 6);// should be 6d/6
+ }
+
+ /**
+ * <pre>
+ * Set up
+ * column 1 2 3 4 5 6
+ * seq s1 F R - K - S
+ * seq s2 F S - - L
+ * s1 chain c c c c
+ * s1 domain d d d d
+ * s2 chain c c c
+ * s2 metal m m m
+ * s2 Pfam P P P
+ * scores: 3 3 0 2 3 2
+ * </pre>
+ *
+ * @return
+ */
+ protected AlignFrame setupAlignmentView()
+ {
+ /*
+ * for now, using space for gap to match callers of
+ * AlignmentView.getSequenceStrings()
+ * may change this to '-' (with corresponding change to matrices)
+ */
+ SequenceI s1 = new Sequence("s1", "FR K S");
+ SequenceI s2 = new Sequence("s2", "FS L");
+
+ s1.addSequenceFeature(new SequenceFeature("chain", null, 1, 4, 0f, null));
+ s1.addSequenceFeature(new SequenceFeature("domain", null, 1, 4, 0f,
+ null));
+ s2.addSequenceFeature(new SequenceFeature("chain", null, 1, 3, 0f, null));
+ s2.addSequenceFeature(new SequenceFeature("metal", null, 1, 3, 0f, null));
+ s2.addSequenceFeature(new SequenceFeature("Pfam", null, 1, 3, 0f, null));
+ AlignmentI al = new Alignment(new SequenceI[] { s1, s2 });
+ AlignFrame af = new AlignFrame(al, 300, 300);
+ af.setShowSeqFeatures(true);
+ af.getFeatureRenderer().findAllFeatures(true);
+ return af;
+ }
+
}
--- /dev/null
+package jalview.analysis.scoremodels;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.api.analysis.SimilarityParamsI;
+import jalview.util.Comparison;
+
+import org.testng.annotations.Test;
+
+public class PIDModelTest
+{
+ private static final double DELTA = 0.00001D;
+
+ @Test(groups = "Functional")
+ public void testGetPairwiseScore()
+ {
+ PIDModel sm = new PIDModel();
+ assertEquals(sm.getPairwiseScore('A', 'A'), 1f);
+ assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
+ assertEquals(sm.getPairwiseScore('a', 'A'), 1f);
+ assertEquals(sm.getPairwiseScore('A', 'B'), 0f);
+ assertEquals(sm.getPairwiseScore('A', ' '), 0f);
+ assertEquals(sm.getPairwiseScore(' ', ' '), 0f);
+ assertEquals(sm.getPairwiseScore('.', '.'), 0f);
+ assertEquals(sm.getPairwiseScore('-', '-'), 0f);
+ }
+
+ /**
+ * Regression test to verify that a (suitably configured) PIDModel computes
+ * the same percentage identities as the Comparison.PID method
+ */
+ @Test(groups = "Functional")
+ public void testComputePID_matchesComparisonPID()
+ {
+ SimilarityParamsI params = new SimilarityParams(true, true, true, true);
+
+ /*
+ * same length, no gaps
+ */
+ String s1 = "ARFNQDWSGI";
+ String s2 = "ARKNQDQSGI";
+
+ new PIDModel();
+ double newScore = PIDModel.computePID(s1, s2, params);
+ double oldScore = Comparison.PID(s1, s2);
+ assertEquals(newScore, oldScore, DELTA);
+
+ /*
+ * same length, with gaps
+ */
+ s1 = "-RFNQDWSGI";
+ s2 = "ARKNQ-QSGI";
+ new PIDModel();
+ newScore = PIDModel.computePID(s1, s2, params);
+ oldScore = Comparison.PID(s1, s2);
+ assertEquals(newScore, oldScore, DELTA);
+
+ /*
+ * s2 longer than s1, with gaps
+ */
+ s1 = "ARK-";
+ s2 = "-RFNQ";
+ new PIDModel();
+ newScore = PIDModel.computePID(s1, s2, params);
+ oldScore = Comparison.PID(s1, s2);
+ assertEquals(newScore, oldScore, DELTA);
+
+ /*
+ * s1 longer than s2, with gaps
+ */
+ s1 = "-RFNQ";
+ s2 = "ARK-";
+ new PIDModel();
+ newScore = PIDModel.computePID(s1, s2, params);
+ oldScore = Comparison.PID(s1, s2);
+ assertEquals(newScore, oldScore, DELTA);
+
+ /*
+ * same but now also with gapped columns
+ */
+ s1 = "-R-F-NQ";
+ s2 = "AR-K--";
+ new PIDModel();
+ newScore = PIDModel.computePID(s1, s2, params);
+ oldScore = Comparison.PID(s1, s2);
+ assertEquals(newScore, oldScore, DELTA);
+ }
+
+ /**
+ * Tests for percentage identity variants where only the shorter length of two
+ * sequences is used
+ */
+ @Test(groups = "Functional")
+ public void testComputePID_matchShortestSequence()
+ {
+ String s1 = "FR-K-S";
+ String s2 = "FS--L";
+
+ /*
+ * match gap-gap and gap-char
+ * PID = 4/5 = 80%
+ */
+ SimilarityParamsI params = new SimilarityParams(true, true, true, true);
+ assertEquals(PIDModel.computePID(s1, s2, params), 80d);
+
+ /*
+ * match gap-char but not gap-gap
+ * PID = 3/4 = 75%
+ */
+ params = new SimilarityParams(false, true, true, true);
+ assertEquals(PIDModel.computePID(s1, s2, params), 75d);
+
+ /*
+ * include gaps but don't match them
+ * include gap-gap, counted as identity
+ * PID = 2/5 = 40%
+ */
+ params = new SimilarityParams(true, false, true, true);
+ assertEquals(PIDModel.computePID(s1, s2, params), 40d);
+
+ /*
+ * include gaps but don't match them
+ * exclude gap-gap
+ * PID = 1/4 = 25%
+ */
+ params = new SimilarityParams(false, false, true, true);
+ assertEquals(PIDModel.computePID(s1, s2, params), 25d);
+ }
+
+ /**
+ * Tests for percentage identity variants where the longer length of two
+ * sequences is used
+ */
+ @Test(groups = "Functional")
+ public void testComputePID_matchLongestSequence()
+ {
+ String s1 = "FR-K-S";
+ String s2 = "FS--L";
+
+ /*
+ * match gap-gap and gap-char
+ * shorter sequence treated as if with trailing gaps
+ * PID = 5/6 = 83.333...%
+ */
+ SimilarityParamsI params = new SimilarityParams(true, true, true, false);
+ assertEquals(PIDModel.computePID(s1, s2, params), 500d / 6);
+
+ /*
+ * match gap-char but not gap-gap
+ * PID = 4/5 = 80%
+ */
+ params = new SimilarityParams(false, true, true, false);
+ assertEquals(PIDModel.computePID(s1, s2, params), 80d);
+
+ /*
+ * include gaps but don't match them
+ * include gap-gap, counted as identity
+ * PID = 2/6 = 33.333...%
+ */
+ params = new SimilarityParams(true, false, true, false);
+ assertEquals(PIDModel.computePID(s1, s2, params), 100d / 3);
+
+ /*
+ * include gaps but don't match them
+ * exclude gap-gap
+ * PID = 1/5 = 25%
+ */
+ params = new SimilarityParams(false, false, true, false);
+ assertEquals(PIDModel.computePID(s1, s2, params), 20d);
+
+ /*
+ * no tests for matchGaps=true, includeGaps=false
+ * as it don't make sense
+ */
+ }
+}
--- /dev/null
+package jalview.analysis.scoremodels;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNotSame;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
+
+import jalview.api.analysis.SimilarityParamsI;
+import jalview.io.DataSourceType;
+import jalview.io.FileParse;
+import jalview.io.ScoreMatrixFile;
+import jalview.math.MatrixI;
+import jalview.schemes.ResidueProperties;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Arrays;
+
+import org.testng.annotations.Test;
+
+public class ScoreMatrixTest
+{
+ @Test(groups = "Functional")
+ public void testConstructor()
+ {
+ // note score matrix does not have to be symmetric (though it should be!)
+ float[][] scores = new float[3][];
+ scores[0] = new float[] { 1f, 2f, 3f };
+ scores[1] = new float[] { -4f, 5f, 6f };
+ scores[2] = new float[] { 7f, 8f, 9f };
+ ScoreMatrix sm = new ScoreMatrix("Test", "ABC".toCharArray(), scores);
+ assertEquals(sm.getSize(), 3);
+ assertArrayEquals(scores, sm.getMatrix());
+ assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
+ assertEquals(sm.getPairwiseScore('b', 'c'), 6f);
+ assertEquals(sm.getPairwiseScore('c', 'b'), 8f);
+ assertEquals(sm.getMatrixIndex('c'), 2);
+ assertEquals(sm.getMatrixIndex(' '), -1);
+
+ // substitution to or from unknown symbol gets minimum score
+ assertEquals(sm.getPairwiseScore('A', 'D'), -4f);
+ assertEquals(sm.getPairwiseScore('D', 'A'), -4f);
+ // unknown-to-self gets a score of 1
+ assertEquals(sm.getPairwiseScore('D', 'D'), 1f);
+ }
+
+ @Test(
+ groups = "Functional",
+ expectedExceptions = { IllegalArgumentException.class })
+ public void testConstructor_matrixTooSmall()
+ {
+ float[][] scores = new float[2][];
+ scores[0] = new float[] { 1f, 2f };
+ scores[1] = new float[] { 3f, 4f };
+ new ScoreMatrix("Test", "ABC".toCharArray(), scores);
+ }
+
+ @Test(
+ groups = "Functional",
+ expectedExceptions = { IllegalArgumentException.class })
+ public void testConstructor_matrixTooBig()
+ {
+ float[][] scores = new float[2][];
+ scores[0] = new float[] { 1f, 2f };
+ scores[1] = new float[] { 3f, 4f };
+ new ScoreMatrix("Test", "A".toCharArray(), scores);
+ }
+
+ @Test(
+ groups = "Functional",
+ expectedExceptions = { IllegalArgumentException.class })
+ public void testConstructor_matrixNotSquare()
+ {
+ float[][] scores = new float[2][];
+ scores[0] = new float[] { 1f, 2f };
+ scores[1] = new float[] { 3f };
+ new ScoreMatrix("Test", "AB".toCharArray(), scores);
+ }
+
+ @Test(groups = "Functional")
+ public void testBuildSymbolIndex()
+ {
+ float[][] scores = new float[2][];
+ scores[0] = new float[] { 1f, 2f };
+ scores[1] = new float[] { 3f, 4f };
+ ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '.' },
+ scores);
+ short[] index = sm.buildSymbolIndex("AX-yxYp".toCharArray());
+
+ assertEquals(index.length, 128); // ASCII character set size
+
+ assertEquals(index['A'], 0);
+ assertEquals(index['a'], 0); // lower-case mapping added
+ assertEquals(index['X'], 1);
+ assertEquals(index['-'], 2);
+ assertEquals(index['y'], 3); // lower-case override
+ assertEquals(index['x'], 4); // lower-case override
+ assertEquals(index['Y'], 5);
+ assertEquals(index['p'], 6);
+ assertEquals(index['P'], -1); // lower-case doesn't map upper-case
+
+ /*
+ * check all unmapped symbols have index for unmapped
+ */
+ for (int c = 0; c < index.length; c++)
+ {
+ if (!"AaXx-. Yyp".contains(String.valueOf((char) c)))
+ {
+ assertEquals(index[c], -1);
+ }
+ }
+ }
+
+ /**
+ * check that characters not in the basic ASCII set are simply ignored
+ */
+ @Test(groups = "Functional")
+ public void testBuildSymbolIndex_nonAscii()
+ {
+ float[][] scores = new float[2][];
+ scores[0] = new float[] { 1f, 2f };
+ scores[1] = new float[] { 3f, 4f };
+ ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '.' },
+ scores);
+ char[] weird = new char[] { 128, 245, 'P' };
+ short[] index = sm.buildSymbolIndex(weird);
+ assertEquals(index.length, 128);
+ assertEquals(index['P'], 2);
+ assertEquals(index['p'], 2);
+ for (int c = 0; c < index.length; c++)
+ {
+ if (c != 'P' && c != 'p')
+ {
+ assertEquals(index[c], -1);
+ }
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testGetMatrix()
+ {
+ ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
+ float[][] m = sm.getMatrix();
+ assertEquals(m.length, sm.getSize());
+ assertEquals(m[2][4], -3f);
+ // verify a defensive copy is returned
+ float[][] m2 = sm.getMatrix();
+ assertNotSame(m, m2);
+ assertTrue(Arrays.deepEquals(m, m2));
+ }
+
+ @Test(groups = "Functional")
+ public void testGetMatrixIndex()
+ {
+ ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
+ assertEquals(sm.getMatrixIndex('A'), 0);
+ assertEquals(sm.getMatrixIndex('R'), 1);
+ assertEquals(sm.getMatrixIndex('r'), 1);
+ assertEquals(sm.getMatrixIndex('N'), 2);
+ assertEquals(sm.getMatrixIndex('D'), 3);
+ assertEquals(sm.getMatrixIndex('X'), 22);
+ assertEquals(sm.getMatrixIndex('x'), 22);
+ assertEquals(sm.getMatrixIndex('-'), -1);
+ assertEquals(sm.getMatrixIndex('*'), 23);
+ assertEquals(sm.getMatrixIndex('.'), -1);
+ assertEquals(sm.getMatrixIndex(' '), -1);
+ assertEquals(sm.getMatrixIndex('?'), -1);
+ assertEquals(sm.getMatrixIndex((char) 128), -1);
+ }
+
+ @Test(groups = "Functional")
+ public void testGetSize()
+ {
+ ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
+ assertEquals(sm.getMatrix().length, sm.getSize());
+ }
+
+ @Test(groups = "Functional")
+ public void testComputePairwiseScores()
+ {
+ /*
+ * NB score matrix expects '-' for gap
+ */
+ String[] seqs = new String[] { "FKL", "R-D", "QIA", "GWC" };
+ ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
+
+ MatrixI pairwise = sm.findSimilarities(seqs, SimilarityParams.Jalview);
+
+ /*
+ * should be NxN where N = number of sequences
+ */
+ assertEquals(pairwise.height(), 4);
+ assertEquals(pairwise.width(), 4);
+
+ /*
+ * should be symmetrical (because BLOSUM62 is)
+ */
+ for (int i = 0; i < pairwise.height(); i++)
+ {
+ for (int j = i + 1; j < pairwise.width(); j++)
+ {
+ assertEquals(pairwise.getValue(i, j), pairwise.getValue(j, i),
+ String.format("Not symmetric at [%d, %d]", i, j));
+ }
+ }
+ /*
+ * verify expected BLOSUM dot product scores
+ */
+ // F.F + K.K + L.L = 6 + 5 + 4 = 15
+ assertEquals(pairwise.getValue(0, 0), 15d);
+ // R.R + -.- + D.D = 5 + 1 + 6 = 12
+ assertEquals(pairwise.getValue(1, 1), 12d);
+ // Q.Q + I.I + A.A = 5 + 4 + 4 = 13
+ assertEquals(pairwise.getValue(2, 2), 13d);
+ // G.G + W.W + C.C = 6 + 11 + 9 = 26
+ assertEquals(pairwise.getValue(3, 3), 26d);
+ // F.R + K.- + L.D = -3 + -4 + -4 = -11
+ assertEquals(pairwise.getValue(0, 1), -11d);
+ // F.Q + K.I + L.A = -3 + -3 + -1 = -7
+ assertEquals(pairwise.getValue(0, 2), -7d);
+ // F.G + K.W + L.C = -3 + -3 + -1 = -7
+ assertEquals(pairwise.getValue(0, 3), -7d);
+ // R.Q + -.I + D.A = 1 + -4 + -2 = -5
+ assertEquals(pairwise.getValue(1, 2), -5d);
+ // R.G + -.W + D.C = -2 + -4 + -3 = -9
+ assertEquals(pairwise.getValue(1, 3), -9d);
+ // Q.G + I.W + A.C = -2 + -3 + 0 = -5
+ assertEquals(pairwise.getValue(2, 3), -5d);
+ }
+
+ /**
+ * Test that the result of outputMatrix can be reparsed to give an identical
+ * ScoreMatrix
+ *
+ * @throws IOException
+ * @throws MalformedURLException
+ */
+ @Test(groups = "Functional")
+ public void testOutputMatrix_roundTrip() throws MalformedURLException,
+ IOException
+ {
+ ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
+ String output = sm.outputMatrix(false);
+ FileParse fp = new FileParse(output, DataSourceType.PASTE);
+ ScoreMatrixFile parser = new ScoreMatrixFile(fp);
+ ScoreMatrix sm2 = parser.parseMatrix();
+ assertNotNull(sm2);
+ assertTrue(sm2.equals(sm));
+ }
+
+ @Test(groups = "Functional")
+ public void testEqualsAndHashCode()
+ {
+ ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
+ ScoreMatrix sm2 = new ScoreMatrix(sm.getName(), sm.getSymbols()
+ .toCharArray(), sm.getMatrix());
+ assertTrue(sm.equals(sm2));
+ assertEquals(sm.hashCode(), sm2.hashCode());
+
+ sm2 = ScoreModels.getInstance().getPam250();
+ assertFalse(sm.equals(sm2));
+ assertNotEquals(sm.hashCode(), sm2.hashCode());
+
+ assertFalse(sm.equals("hello"));
+ }
+
+ /**
+ * Tests for scoring options where the longer length of two sequences is used
+ */
+ @Test(groups = "Functional")
+ public void testcomputeSimilarity_matchLongestSequence()
+ {
+ /*
+ * ScoreMatrix expects '-' for gaps
+ */
+ String s1 = "FR-K-S";
+ String s2 = "FS--L";
+ ScoreMatrix blosum = ScoreModels.getInstance().getBlosum62();
+
+ /*
+ * score gap-gap and gap-char
+ * shorter sequence treated as if with trailing gaps
+ * score = F^F + R^S + -^- + K^- + -^L + S^-
+ * = 6 + -1 + 1 + -4 + -4 + -4 = -6
+ */
+ SimilarityParamsI params = new SimilarityParams(true, true, true, false);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), -6d);
+ // matchGap (arg2) is ignored:
+ params = new SimilarityParams(true, false, true, false);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), -6d);
+
+ /*
+ * score gap-char but not gap-gap
+ * score = F^F + R^S + 0 + K^- + -^L + S^-
+ * = 6 + -1 + 0 + -4 + -4 + -4 = -7
+ */
+ params = new SimilarityParams(false, true, true, false);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), -7d);
+ // matchGap (arg2) is ignored:
+ params = new SimilarityParams(false, false, true, false);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), -7d);
+
+ /*
+ * score gap-gap but not gap-char
+ * score = F^F + R^S + -^- + 0 + 0 + 0
+ * = 6 + -1 + 1 = 6
+ */
+ params = new SimilarityParams(true, false, false, false);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
+ // matchGap (arg2) is ignored:
+ params = new SimilarityParams(true, true, false, false);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
+
+ /*
+ * score neither gap-gap nor gap-char
+ * score = F^F + R^S + 0 + 0 + 0 + 0
+ * = 6 + -1 = 5
+ */
+ params = new SimilarityParams(false, false, false, false);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
+ // matchGap (arg2) is ignored:
+ params = new SimilarityParams(false, true, false, false);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
+ }
+
+ /**
+ * Tests for scoring options where only the shorter length of two sequences is
+ * used
+ */
+ @Test(groups = "Functional")
+ public void testcomputeSimilarity_matchShortestSequence()
+ {
+ /*
+ * ScoreMatrix expects '-' for gaps
+ */
+ String s1 = "FR-K-S";
+ String s2 = "FS--L";
+ ScoreMatrix blosum = ScoreModels.getInstance().getBlosum62();
+
+ /*
+ * score gap-gap and gap-char
+ * match shorter sequence only
+ * score = F^F + R^S + -^- + K^- + -^L
+ * = 6 + -1 + 1 + -4 + -4 = -2
+ */
+ SimilarityParamsI params = new SimilarityParams(true, true, true, true);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), -2d);
+ // matchGap (arg2) is ignored:
+ params = new SimilarityParams(true, false, true, true);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), -2d);
+
+ /*
+ * score gap-char but not gap-gap
+ * score = F^F + R^S + 0 + K^- + -^L
+ * = 6 + -1 + 0 + -4 + -4 = -3
+ */
+ params = new SimilarityParams(false, true, true, true);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), -3d);
+ // matchGap (arg2) is ignored:
+ params = new SimilarityParams(false, false, true, true);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), -3d);
+
+ /*
+ * score gap-gap but not gap-char
+ * score = F^F + R^S + -^- + 0 + 0
+ * = 6 + -1 + 1 = 6
+ */
+ params = new SimilarityParams(true, false, false, true);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
+ // matchGap (arg2) is ignored:
+ params = new SimilarityParams(true, true, false, true);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
+
+ /*
+ * score neither gap-gap nor gap-char
+ * score = F^F + R^S + 0 + 0 + 0
+ * = 6 + -1 = 5
+ */
+ params = new SimilarityParams(false, false, false, true);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
+ // matchGap (arg2) is ignored:
+ params = new SimilarityParams(false, true, false, true);
+ assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
+ }
+
+ @Test(groups = "Functional")
+ public void testSymmetric()
+ {
+ verifySymmetric(ScoreModels.getInstance().getBlosum62());
+ verifySymmetric(ScoreModels.getInstance().getPam250());
+ verifySymmetric(ScoreModels.getInstance().getDefaultModel(false)); // dna
+ }
+
+ private void verifySymmetric(ScoreMatrix sm)
+ {
+ float[][] m = sm.getMatrix();
+ int rows = m.length;
+ for (int row = 0; row < rows; row++)
+ {
+ assertEquals(m[row].length, rows);
+ for (int col = 0; col < rows; col++)
+ {
+ assertEquals(m[row][col], m[col][row], String.format("%s [%s, %s]",
+ sm.getName(), ResidueProperties.aa[row],
+ ResidueProperties.aa[col]));
+ }
+ }
+ }
+
+ /**
+ * A test that just asserts the expected values in the Blosum62 score matrix
+ */
+ @Test(groups = "Functional")
+ public void testBlosum62_values()
+ {
+ ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
+
+ assertTrue(sm.isProtein());
+ assertFalse(sm.isDNA());
+ assertNull(sm.getDescription());
+
+ /*
+ * verify expected scores against ARNDCQEGHILKMFPSTWYVBZX
+ * scraped from https://www.ncbi.nlm.nih.gov/Class/FieldGuide/BLOSUM62.txt
+ */
+ verifyValues(sm, 'A', new float[] { 4, -1, -2, -2, 0, -1, -1, 0, -2,
+ -1,
+ -1, -1, -1, -2, -1, 1, 0, -3, -2, 0, -2, -1, 0 });
+ verifyValues(sm, 'R', new float[] { -1, 5, 0, -2, -3, 1, 0, -2, 0, -3,
+ -2, 2, -1, -3, -2, -1, -1, -3, -2, -3, -1, 0, -1 });
+ verifyValues(sm, 'N', new float[] { -2, 0, 6, 1, -3, 0, 0, 0, 1, -3,
+ -3,
+ 0, -2, -3, -2, 1, 0, -4, -2, -3, 3, 0, -1 });
+ verifyValues(sm, 'D', new float[] { -2, -2, 1, 6, -3, 0, 2, -1, -1, -3,
+ -4, -1, -3, -3, -1, 0, -1, -4, -3, -3, 4, 1, -1 });
+ verifyValues(sm, 'C', new float[] { 0, -3, -3, -3, 9, -3, -4, -3, -3,
+ -1,
+ -1, -3, -1, -2, -3, -1, -1, -2, -2, -1, -3, -3, -2 });
+ verifyValues(sm, 'Q', new float[] { -1, 1, 0, 0, -3, 5, 2, -2, 0, -3,
+ -2,
+ 1, 0, -3, -1, 0, -1, -2, -1, -2, 0, 3, -1 });
+ verifyValues(sm, 'E', new float[] { -1, 0, 0, 2, -4, 2, 5, -2, 0, -3,
+ -3,
+ 1, -2, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1 });
+ verifyValues(sm, 'G', new float[] { 0, -2, 0, -1, -3, -2, -2, 6, -2,
+ -4,
+ -4, -2, -3, -3, -2, 0, -2, -2, -3, -3, -1, -2, -1 });
+ verifyValues(sm, 'H', new float[] { -2, 0, 1, -1, -3, 0, 0, -2, 8, -3,
+ -3, -1, -2, -1, -2, -1, -2, -2, 2, -3, 0, 0, -1 });
+ verifyValues(sm, 'I', new float[] { -1, -3, -3, -3, -1, -3, -3, -4, -3,
+ 4, 2, -3, 1, 0, -3, -2, -1, -3, -1, 3, -3, -3, -1 });
+ verifyValues(sm, 'L', new float[] { -1, -2, -3, -4, -1, -2, -3, -4, -3,
+ 2, 4, -2, 2, 0, -3, -2, -1, -2, -1, 1, -4, -3, -1 });
+ verifyValues(sm, 'K', new float[] { -1, 2, 0, -1, -3, 1, 1, -2, -1, -3,
+ -2, 5, -1, -3, -1, 0, -1, -3, -2, -2, 0, 1, -1 });
+ verifyValues(sm, 'M', new float[] { -1, -1, -2, -3, -1, 0, -2, -3, -2,
+ 1,
+ 2, -1, 5, 0, -2, -1, -1, -1, -1, 1, -3, -1, -1 });
+ verifyValues(sm, 'F', new float[] { -2, -3, -3, -3, -2, -3, -3, -3, -1,
+ 0, 0, -3, 0, 6, -4, -2, -2, 1, 3, -1, -3, -3, -1 });
+ verifyValues(sm, 'P', new float[] { -1, -2, -2, -1, -3, -1, -1, -2, -2,
+ -3, -3, -1, -2, -4, 7, -1, -1, -4, -3, -2, -2, -1, -2 });
+ verifyValues(sm, 'S', new float[] { 1, -1, 1, 0, -1, 0, 0, 0, -1, -2,
+ -2,
+ 0, -1, -2, -1, 4, 1, -3, -2, -2, 0, 0, 0 });
+ verifyValues(sm, 'T', new float[] { 0, -1, 0, -1, -1, -1, -1, -2, -2,
+ -1,
+ -1, -1, -1, -2, -1, 1, 5, -2, -2, 0, -1, -1, 0 });
+ verifyValues(sm, 'W', new float[] { -3, -3, -4, -4, -2, -2, -3, -2, -2,
+ -3, -2, -3, -1, 1, -4, -3, -2, 11, 2, -3, -4, -3, -2 });
+ verifyValues(sm, 'Y', new float[] { -2, -2, -2, -3, -2, -1, -2, -3, 2,
+ -1, -1, -2, -1, 3, -3, -2, -2, 2, 7, -1, -3, -2, -1 });
+ verifyValues(sm, 'V', new float[] { 0, -3, -3, -3, -1, -2, -2, -3, -3,
+ 3,
+ 1, -2, 1, -1, -2, -2, 0, -3, -1, 4, -3, -2, -1 });
+ verifyValues(sm, 'B', new float[] { -2, -1, 3, 4, -3, 0, 1, -1, 0, -3,
+ -4, 0, -3, -3, -2, 0, -1, -4, -3, -3, 4, 1, -1 });
+ verifyValues(sm, 'Z', new float[] { -1, 0, 0, 1, -3, 3, 4, -2, 0, -3,
+ -3,
+ 1, -1, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1 });
+ verifyValues(sm, 'X', new float[] { 0, -1, -1, -1, -2, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -2, 0, 0, -2, -1, -1, -1, -1, -1 });
+ }
+
+ /**
+ * Helper method to check pairwise scores for one residue
+ *
+ * @param sm
+ * @param res
+ * @param expected
+ * score values against 'res', in ResidueProperties.aaIndex order
+ */
+ private void verifyValues(ScoreMatrix sm, char res, float[] expected)
+ {
+ for (int j = 0; j < expected.length; j++)
+ {
+ char c2 = ResidueProperties.aa[j].charAt(0);
+ assertEquals(sm.getPairwiseScore(res, c2), expected[j],
+ String.format("%s->%s", res, c2));
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testConstructor_gapDash()
+ {
+ float[][] scores = new float[2][];
+ scores[0] = new float[] { 1f, 2f };
+ scores[1] = new float[] { 4f, 5f };
+ ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '-' },
+ scores);
+ assertEquals(sm.getSize(), 2);
+ assertArrayEquals(scores, sm.getMatrix());
+ assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
+ assertEquals(sm.getPairwiseScore('A', 'A'), 1f);
+ assertEquals(sm.getPairwiseScore('a', '-'), 2f);
+ assertEquals(sm.getPairwiseScore('-', 'A'), 4f);
+ assertEquals(sm.getMatrixIndex('a'), 0);
+ assertEquals(sm.getMatrixIndex('A'), 0);
+ assertEquals(sm.getMatrixIndex('-'), 1);
+ assertEquals(sm.getMatrixIndex(' '), -1);
+ assertEquals(sm.getMatrixIndex('.'), -1);
+ }
+
+ @Test(groups = "Functional")
+ public void testGetPairwiseScore()
+ {
+ float[][] scores = new float[2][];
+ scores[0] = new float[] { 1f, 2f };
+ scores[1] = new float[] { -4f, 5f };
+ ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', 'B' },
+ scores);
+ assertEquals(sm.getPairwiseScore('A', 'A'), 1f);
+ assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
+ assertEquals(sm.getPairwiseScore('A', 'B'), 2f);
+ assertEquals(sm.getPairwiseScore('b', 'a'), -4f);
+ assertEquals(sm.getPairwiseScore('B', 'b'), 5f);
+
+ /*
+ * unknown symbols currently score minimum score
+ * or 1 for identity with self
+ */
+ assertEquals(sm.getPairwiseScore('A', '-'), -4f);
+ assertEquals(sm.getPairwiseScore('-', 'A'), -4f);
+ assertEquals(sm.getPairwiseScore('-', '-'), 1f);
+ assertEquals(sm.getPairwiseScore('Q', 'W'), -4f);
+ assertEquals(sm.getPairwiseScore('Q', 'Q'), 1f);
+
+ /*
+ * symbols not in basic ASCII set score zero
+ */
+ char c = (char) 200;
+ assertEquals(sm.getPairwiseScore('Q', c), 0f);
+ assertEquals(sm.getPairwiseScore(c, 'Q'), 0f);
+ }
+
+ @Test(groups = "Functional")
+ public void testGetMinimumScore()
+ {
+ ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
+ assertEquals(sm.getMinimumScore(), -4f);
+ }
+
+ @Test(groups = "Functional")
+ public void testGetMaximumScore()
+ {
+ ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
+ assertEquals(sm.getMaximumScore(), 11f);
+ }
+
+ @Test(groups = "Functional")
+ public void testOutputMatrix_html()
+ {
+ float[][] scores = new float[2][];
+ scores[0] = new float[] { 1f, 2f };
+ scores[1] = new float[] { 4f, -5.3E-10f };
+ ScoreMatrix sm = new ScoreMatrix("Test", "AB".toCharArray(), scores);
+ String html = sm.outputMatrix(true);
+ String expected = "<table border=\"1\"><tr><th></th><th> A </th><th> B </th></tr>\n"
+ + "<tr><td>A</td><td>1.0</td><td>2.0</td></tr>\n"
+ + "<tr><td>B</td><td>4.0</td><td>-5.3E-10</td></tr>\n"
+ + "</table>";
+ assertEquals(html, expected);
+ }
+}
--- /dev/null
+package jalview.analysis.scoremodels;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import jalview.api.analysis.PairwiseScoreModelI;
+import jalview.api.analysis.ScoreModelI;
+
+import java.util.Iterator;
+
+import org.testng.annotations.Test;
+
+public class ScoreModelsTest
+{
+ /**
+ * Verify that the singleton constructor successfully loads Jalview's built-in
+ * score models
+ */
+ @Test(groups = "Functional")
+ public void testConstructor()
+ {
+ Iterator<ScoreModelI> models = ScoreModels.getInstance().getModels()
+ .iterator();
+ assertTrue(models.hasNext());
+
+ /*
+ * models are served in order of addition
+ */
+ ScoreModelI sm = models.next();
+ assertTrue(sm instanceof SimilarityScoreModel);
+ assertTrue(sm instanceof PairwiseScoreModelI);
+ assertFalse(sm instanceof DistanceScoreModel);
+ assertEquals(sm.getName(), "BLOSUM62");
+ assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('I', 'R'), -3f);
+
+ sm = models.next();
+ assertTrue(sm instanceof SimilarityScoreModel);
+ assertTrue(sm instanceof PairwiseScoreModelI);
+ assertFalse(sm instanceof DistanceScoreModel);
+ assertEquals(sm.getName(), "PAM250");
+ assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('R', 'C'), -4f);
+
+ sm = models.next();
+ assertTrue(sm instanceof SimilarityScoreModel);
+ assertTrue(sm instanceof PairwiseScoreModelI);
+ assertFalse(sm instanceof DistanceScoreModel);
+ assertEquals(sm.getName(), "PID");
+ assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('R', 'C'), 0f);
+ assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('R', 'r'), 1f);
+
+ sm = models.next();
+ assertTrue(sm instanceof SimilarityScoreModel);
+ assertTrue(sm instanceof PairwiseScoreModelI);
+ assertFalse(sm instanceof DistanceScoreModel);
+ assertEquals(sm.getName(), "DNA");
+ assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('c', 'x'), 1f);
+
+ sm = models.next();
+ assertFalse(sm instanceof SimilarityScoreModel);
+ assertFalse(sm instanceof PairwiseScoreModelI);
+ assertTrue(sm instanceof DistanceScoreModel);
+ assertEquals(sm.getName(), "Sequence Feature Similarity");
+ }
+
+ /**
+ * 'Test' that prints out score matrices in tab-delimited format. This test is
+ * intentionally not assigned to any group so would not be run as part of a
+ * suite. It makes no assertions and is just provided as a utility method for
+ * printing out matrices. Relocated here from ScoreMatrixPrinter.
+ */
+ @Test(groups = "none")
+ public void printAllMatrices_tabDelimited()
+ {
+ printAllMatrices(false);
+ }
+
+ /**
+ * 'Test' that prints out score matrices in html format. This test is
+ * intentionally not assigned to any group so would not be run as part of a
+ * suite. It makes no assertions and is just provided as a utility method for
+ * printing out matrices. Relocated here from ScoreMatrixPrinter.
+ */
+ @Test(groups = "none")
+ public void printAllMatrices_asHtml()
+ {
+ printAllMatrices(true);
+ }
+
+ /**
+ * Print all registered ScoreMatrix as plain or html tables
+ *
+ * @param asHtml
+ */
+ protected void printAllMatrices(boolean asHtml)
+ {
+ for (ScoreModelI sm : ScoreModels.getInstance().getModels())
+ {
+ if (sm instanceof ScoreMatrix)
+ {
+ System.out.println(((ScoreMatrix) sm).outputMatrix(asHtml));
+ }
+ }
+ }
+}
import jalview.io.AppletFormatAdapter;
import jalview.io.FileFormat;
+import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
ann.getDefaultRnaHelixSymbol(i));
}
}
+
+ public static Annotation newAnnotation(String ann)
+ {
+ float val = 0f;
+ try
+ {
+ val = Float.parseFloat(ann);
+ } catch (NumberFormatException q)
+ {
+ }
+ ;
+ return new Annotation(ann, ann, '\0', val);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testIsQuantitative()
+ {
+ AlignmentAnnotation ann = null;
+
+ ann = new AlignmentAnnotation("an", "some an", null);
+ Assert.assertFalse(ann.isQuantitative(),
+ "Empty annotation set should not be quantitative.");
+
+ ann = new AlignmentAnnotation("an", "some an", new Annotation[] {
+ newAnnotation("4"), newAnnotation("1"), newAnnotation("1"),
+ newAnnotation("0.1"), newAnnotation("0.3") });
+ Assert.assertTrue(ann.isQuantitative(),
+ "All numbers annotation set should be quantitative.");
+
+ ann = new AlignmentAnnotation("an", "some an", new Annotation[] {
+ newAnnotation("E"), newAnnotation("E"), newAnnotation("E"),
+ newAnnotation("E"), newAnnotation("E") });
+ Assert.assertFalse(ann.isQuantitative(),
+ "All 'E' annotation set should not be quantitative.");
+
+ ann = new AlignmentAnnotation("an", "some an", new Annotation[] {
+ newAnnotation("E"), newAnnotation("1"), newAnnotation("2"),
+ newAnnotation("3"), newAnnotation("E") });
+ Assert.assertTrue(ann.isQuantitative(),
+ "Mixed 'E' annotation set should be quantitative.");
+ }
}
import static org.testng.AssertJUnit.assertSame;
import static org.testng.AssertJUnit.assertTrue;
+import jalview.analysis.AlignmentGenerator;
import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
import jalview.gui.JvOptionPane;
import jalview.io.DataSourceType;
assertFalse(iter.hasNext());
}
+ /**
+ * Test method that returns annotations that match on reference sequence,
+ * label, or calcId.
+ */
+ @Test(groups = { "Functional" })
+ public void testFindAnnotations_bySeqLabelandorCalcId()
+ {
+ // TODO: finish testFindAnnotations_bySeqLabelandorCalcId test
+ /* Note - this is an incomplete test - need to check null or
+ * non-null [ matches, not matches ] behaviour for each of the three
+ * parameters..*/
+
+ // search for a single, unique calcId with wildcards on other params
+ Iterable<AlignmentAnnotation> anns = al.findAnnotations(null,
+ "CalcIdForD.melanogaster.2", null);
+ Iterator<AlignmentAnnotation> iter = anns.iterator();
+ assertTrue(iter.hasNext());
+ AlignmentAnnotation ann = iter.next();
+ assertEquals("D.melanogaster.2", ann.sequenceRef.getName());
+ assertFalse(iter.hasNext());
+
+ // save reference to test sequence reference parameter
+ SequenceI rseq = ann.sequenceRef;
+
+ // search for annotation associated with a single sequence
+ anns = al.findAnnotations(rseq, null, null);
+ iter = anns.iterator();
+ assertTrue(iter.hasNext());
+ ann = iter.next();
+ assertEquals("D.melanogaster.2", ann.sequenceRef.getName());
+ assertFalse(iter.hasNext());
+
+ // search for annotation with a non-existant calcId
+ anns = al.findAnnotations(null, "CalcIdForD.melanogaster.?", null);
+ iter = anns.iterator();
+ assertFalse(iter.hasNext());
+
+ // search for annotation with a particular label - expect three
+ anns = al.findAnnotations(null, null, "Secondary Structure");
+ iter = anns.iterator();
+ assertTrue(iter.hasNext());
+ iter.next();
+ assertTrue(iter.hasNext());
+ iter.next();
+ assertTrue(iter.hasNext());
+ iter.next();
+ // third found.. so
+ assertFalse(iter.hasNext());
+
+ // null on all parameters == find all annotations
+ anns = al.findAnnotations(null, null, null);
+ iter = anns.iterator();
+ int n = al.getAlignmentAnnotation().length;
+ while (iter.hasNext())
+ {
+ n--;
+ iter.next();
+ }
+ assertTrue("Found " + n + " fewer annotations from search.", n == 0);
+ }
+
@Test(groups = { "Functional" })
public void testDeleteAllAnnotations_includingAutocalculated()
{
assertNull(a.findGroup(seq2, 8));
}
+ @Test(groups = { "Functional" })
+ public void testDeleteSequenceByIndex()
+ {
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ AlignmentI a = gen.generate(20, 15, 123, 5, 5);
+
+ // delete sequence 10, alignment reduced by 1
+ int height = a.getAbsoluteHeight();
+ a.deleteSequence(10);
+ assertEquals(a.getAbsoluteHeight(), height - 1);
+
+ // try to delete -ve index, nothing happens
+ a.deleteSequence(-1);
+ assertEquals(a.getAbsoluteHeight(), height - 1);
+
+ // try to delete beyond end of alignment, nothing happens
+ a.deleteSequence(14);
+ assertEquals(a.getAbsoluteHeight(), height - 1);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testDeleteSequenceBySeq()
+ {
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ AlignmentI a = gen.generate(20, 15, 123, 5, 5);
+
+ // delete sequence 10, alignment reduced by 1
+ int height = a.getAbsoluteHeight();
+ SequenceI seq = a.getSequenceAt(10);
+ a.deleteSequence(seq);
+ assertEquals(a.getAbsoluteHeight(), height - 1);
+
+ // try to delete non-existent sequence, nothing happens
+ seq = new Sequence("cds", "GCCTCGGAT");
+ assertEquals(a.getAbsoluteHeight(), height - 1);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testDeleteHiddenSequence()
+ {
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ AlignmentI a = gen.generate(20, 15, 123, 5, 5);
+
+ // delete a sequence which is hidden, check it is NOT removed from hidden
+ // sequences
+ int height = a.getAbsoluteHeight();
+ SequenceI seq = a.getSequenceAt(2);
+ a.getHiddenSequences().hideSequence(seq);
+ assertEquals(a.getHiddenSequences().getSize(), 1);
+ a.deleteSequence(2);
+ assertEquals(a.getAbsoluteHeight(), height - 1);
+ assertEquals(a.getHiddenSequences().getSize(), 1);
+
+ // delete a sequence which is not hidden, check hiddenSequences are not
+ // affected
+ a.deleteSequence(10);
+ assertEquals(a.getAbsoluteHeight(), height - 2);
+ assertEquals(a.getHiddenSequences().getSize(), 1);
+ }
+
+ @Test(
+ groups = "Functional",
+ expectedExceptions = { IllegalArgumentException.class })
+ public void testSetDataset_selfReference()
+ {
+ SequenceI seq = new Sequence("a", "a");
+ AlignmentI alignment = new Alignment(new SequenceI[] { seq });
+ alignment.setDataset(alignment);
+ }
}
import static org.testng.Assert.assertEquals;
+import jalview.gui.AlignFrame;
+import jalview.gui.AlignViewport;
import jalview.gui.JvOptionPane;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
assertEquals(av.getVisibleAlignment('$').getSequenceAt(0)
.getSequenceAsString(), "A$$CDE");
}
+
+ @Test(groups = { "Functional" })
+ public void testGetVisibleContigs()
+ {
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+ ">s1\n0123456789\n", DataSourceType.PASTE);
+ AlignViewport av = af.getViewport();
+ AlignmentView view = av.getAlignmentView(true);
+
+ /*
+ * verify getVisibleContigs returns inclusive [start, end] ranges
+ *
+ * no columns hidden
+ */
+ int[] contigs = view.getVisibleContigs();
+ assertEquals(contigs, new int[] { 0, 9 });
+
+ /*
+ * hide 3 internal columns
+ */
+ av.hideColumns(5, 7);
+ // the old AlignmentView is now stale!
+ contigs = view.getVisibleContigs();
+ assertEquals(contigs, new int[] { 0, 9 });
+ // get a fresh AlignmentView
+ view = av.getAlignmentView(true);
+ contigs = view.getVisibleContigs();
+ assertEquals(contigs, new int[] { 0, 4, 8, 9 });
+
+ // hide first 2 columns
+ av.hideColumns(0, 1);
+ view = av.getAlignmentView(true);
+ contigs = view.getVisibleContigs();
+ assertEquals(contigs, new int[] { 2, 4, 8, 9 });
+
+ // hide last column
+ av.hideColumns(9, 9);
+ view = av.getAlignmentView(true);
+ contigs = view.getVisibleContigs();
+ assertEquals(contigs, new int[] { 2, 4, 8, 8 });
+
+ // unhide columns 5-7
+ av.showColumn(5);
+ view = av.getAlignmentView(true);
+ contigs = view.getVisibleContigs();
+ assertEquals(contigs, new int[] { 2, 8 });
+
+ // hide columns 2-7
+ av.hideColumns(2, 7);
+ view = av.getAlignmentView(true);
+ contigs = view.getVisibleContigs();
+ assertEquals(contigs, new int[] { 8, 8 });
+
+ // hide column 8
+ av.hideColumns(8, 8);
+ view = av.getAlignmentView(true);
+ contigs = view.getVisibleContigs();
+ assertEquals(contigs, new int[] {});
+
+ // unhide all
+ av.showAllHiddenColumns();
+ view = av.getAlignmentView(true);
+ contigs = view.getVisibleContigs();
+ assertEquals(contigs, new int[] { 0, 9 });
+ }
}
--- /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.
+ */
+package jalview.datamodel;
+
+import static org.testng.Assert.assertTrue;
+
+import java.util.NoSuchElementException;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class AllColsIteratorTest
+{
+ HiddenColumns hiddenCols;
+
+ @BeforeClass
+ public void setup()
+ {
+ hiddenCols = new HiddenColumns();
+ hiddenCols.hideColumns(2,4);
+ }
+
+
+ /*
+ * Test iterator iterates through collection correctly
+ */
+ @Test(groups = { "Functional" })
+ public void testHasNextAndNext()
+ {
+ AllColsIterator it = new AllColsIterator(0, 3, hiddenCols);
+ int count = 0;
+ while (it.hasNext())
+ {
+ it.next();
+ count++;
+ }
+ assertTrue(count == 4, "hasNext() is false after 4 iterations");
+ }
+
+ /*
+ * Test iterator throws NoSuchElementException at end of iteration
+ */
+ @Test(
+ groups = { "Functional" },
+ expectedExceptions = { NoSuchElementException.class })
+ public void testLastNext() throws NoSuchElementException
+ {
+ AllColsIterator it = new AllColsIterator(0, 3, hiddenCols);
+ while (it.hasNext())
+ {
+ it.next();
+ }
+ it.next();
+ }
+
+ /*
+ * Test iterator throws UnsupportedOperationException on call to remove
+ */
+ @Test(
+ groups = { "Functional" },
+ expectedExceptions = { UnsupportedOperationException.class })
+ public void testRemove() throws UnsupportedOperationException
+ {
+ AllColsIterator it = new AllColsIterator(0, 3, hiddenCols);
+ it.remove();
+ }
+
+ /*
+ * Test iterator behaves correctly when there is only one element in the collection
+ */
+ @Test(groups = { "Functional" })
+ public void testOneElement()
+ {
+ HiddenColumns hidden = new HiddenColumns();
+ AllColsIterator it = new AllColsIterator(0, 0, hidden);
+ int count = 0;
+ while (it.hasNext())
+ {
+ it.next();
+ count++;
+ }
+ assertTrue(count == 1, "hasNext() is false after 1 iteration");
+ }
+}
--- /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.
+ */
+package jalview.datamodel;
+
+import static org.testng.Assert.assertTrue;
+
+import jalview.analysis.AlignmentGenerator;
+
+import java.util.Hashtable;
+import java.util.NoSuchElementException;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class AllRowsIteratorTest
+{
+ AlignmentI al;
+
+ Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences = new Hashtable<>();
+
+ @BeforeClass
+ public void setup()
+ {
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ al = gen.generate(20, 15, 123, 5, 5);
+ if (!hiddenRepSequences.isEmpty())
+ {
+ al.getHiddenSequences().showAll(hiddenRepSequences);
+ }
+ hideSequences(2, 4);
+ }
+
+ /*
+ * Test iterator iterates through collection correctly
+ */
+ @Test(groups = { "Functional" })
+ public void testHasNextAndNext()
+ {
+ AllRowsIterator it = new AllRowsIterator(0, 3, al);
+ int count = 0;
+ while (it.hasNext())
+ {
+ it.next();
+ count++;
+ }
+ assertTrue(count == 4, "hasNext() is false after 4 iterations");
+ }
+
+ /*
+ * Test iterator throws NoSuchElementException at end of iteration
+ */
+ @Test(
+ groups = { "Functional" },
+ expectedExceptions = { NoSuchElementException.class })
+ public void testLastNext() throws NoSuchElementException
+ {
+ AllRowsIterator it = new AllRowsIterator(0, 3, al);
+ while (it.hasNext())
+ {
+ it.next();
+ }
+ it.next();
+ }
+
+ /*
+ * Test iterator throws UnsupportedOperationException on call to remove
+ */
+ @Test(
+ groups = { "Functional" },
+ expectedExceptions = { UnsupportedOperationException.class })
+ public void testRemove() throws UnsupportedOperationException
+ {
+ AllRowsIterator it = new AllRowsIterator(0, 3, al);
+ it.remove();
+ }
+
+
+ /*
+ * Hide sequences between start and end
+ */
+ private void hideSequences(int start, int end)
+ {
+ SequenceI[] allseqs = al.getSequencesArray();
+ SequenceGroup theseSeqs = new SequenceGroup();
+
+ for (int i = start; i <= end; i++)
+ {
+ theseSeqs.addSequence(allseqs[i], false);
+ al.getHiddenSequences().hideSequence(allseqs[i]);
+ }
+
+ hiddenRepSequences.put(allseqs[start], theseSeqs);
+ }
+
+ /*
+ * Test iterator behaves correctly when there is only one element in the collection
+ */
+ @Test(groups = { "Functional" })
+ public void testOneElement()
+ {
+ AllRowsIterator it = new AllRowsIterator(0, 0, al);
+ int count = 0;
+ while (it.hasNext())
+ {
+ it.next();
+ count++;
+ }
+ assertTrue(count == 1, "hasNext() is false after 1 iteration");
+ }
+
+}
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
-import static org.testng.AssertJUnit.assertSame;
import static org.testng.AssertJUnit.assertTrue;
import static org.testng.AssertJUnit.fail;
+import jalview.analysis.AlignmentGenerator;
import jalview.gui.JvOptionPane;
import java.util.Arrays;
assertEquals("[2, 5, 3]", sel.toString());
}
+ @Test(groups = { "Functional" })
+ public void testSetElementsFrom()
+ {
+ ColumnSelection fromcs = new ColumnSelection();
+ ColumnSelection tocs = new ColumnSelection();
+ HiddenColumns hidden = new HiddenColumns();
+
+ fromcs.addElement(2);
+ fromcs.addElement(3);
+ fromcs.addElement(5);
+
+ tocs.setElementsFrom(fromcs, hidden);
+ assertTrue(tocs.equals(fromcs));
+
+ hidden.hideColumns(4, 6);
+ tocs.setElementsFrom(fromcs, hidden);
+
+ // expect cols 2 and 3 to be selected but not 5
+ ColumnSelection expectcs = new ColumnSelection();
+ expectcs.addElement(2);
+ expectcs.addElement(3);
+ assertTrue(tocs.equals(expectcs));
+ }
+
/**
* Test the remove method - in particular to verify that remove(int i) removes
* the element whose value is i, _NOT_ the i'th element.
}
/**
- * Test the method that finds the visible column position of an alignment
- * column, allowing for hidden columns.
- */
- @Test(groups = { "Functional" })
- public void testFindColumnPosition()
- {
- ColumnSelection cs = new ColumnSelection();
- assertEquals(5, cs.findColumnPosition(5));
-
- // hiding column 6 makes no difference
- cs.hideColumns(6, 6);
- assertEquals(5, cs.findColumnPosition(5));
-
- // hiding column 4 moves column 5 to column 4
- cs.hideColumns(4, 4);
- assertEquals(4, cs.findColumnPosition(5));
-
- // hiding columns 1 and 2 moves column 5 to column 2
- cs.hideColumns(1, 2);
- assertEquals(2, cs.findColumnPosition(5));
- }
-
- /**
- * Test the code used to locate the reference sequence ruler origin
- */
- @Test(groups = { "Functional" })
- public void testLocateVisibleBoundsofSequence()
- {
- ColumnSelection cs = new ColumnSelection();
- SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---");
- assertEquals(2, seq.findIndex(seq.getStart()));
-
- // no hidden columns
- assertEquals(
- Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
- seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
- seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
- seq.findIndex(seq.getEnd()) - 1 }),
- Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
-
- // hidden column on gap after end of sequence - should not affect bounds
- cs.hideColumns(13);
- assertEquals(
- Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
- seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
- seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
- seq.findIndex(seq.getEnd()) - 1 }),
- Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
-
- cs.revealAllHiddenColumns();
- // hidden column on gap before beginning of sequence - should vis bounds by
- // one
- cs.hideColumns(0);
- assertEquals(
- Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 2,
- seq.findIndex(seq.getEnd()) - 2, seq.getStart(),
- seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
- seq.findIndex(seq.getEnd()) - 1 }),
- Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
-
- cs.revealAllHiddenColumns();
- // hide columns around most of sequence - leave one residue remaining
- cs.hideColumns(1, 3);
- cs.hideColumns(6, 11);
- assertEquals("-D",
- cs.getVisibleSequenceStrings(0, 5, new SequenceI[] { seq })[0]);
- assertEquals(
- Arrays.toString(new int[] { 1, 1, 3, 3,
- seq.findIndex(seq.getStart()) - 1,
- seq.findIndex(seq.getEnd()) - 1 }),
- Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
- cs.revealAllHiddenColumns();
-
- // hide whole sequence - should just get location of hidden region
- // containing sequence
- cs.hideColumns(1, 11);
- assertEquals(
- Arrays.toString(new int[] { 0, 1, 0, 0,
- seq.findIndex(seq.getStart()) - 1,
- seq.findIndex(seq.getEnd()) - 1 }),
- Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
-
- }
-
- @Test(groups = { "Functional" })
- public void testLocateVisibleBoundsPathologicals()
- {
- // test some pathological cases we missed
- AlignmentI al = new Alignment(new SequenceI[] { new Sequence(
- "refseqGaptest", "KTDVTI----------NFI-----G----L") });
- ColumnSelection cs = new ColumnSelection();
- cs.hideInsertionsFor(al.getSequenceAt(0));
- assertEquals(
- "G",
- ""
- + al.getSequenceAt(0).getCharAt(
- cs.adjustForHiddenColumns(9)));
-
- }
-
- @Test(groups = { "Functional" })
- public void testHideColumns()
- {
- ColumnSelection cs = new ColumnSelection();
- cs.hideColumns(5);
- List<int[]> hidden = cs.getHiddenColumns();
- assertEquals(1, hidden.size());
- assertEquals("[5, 5]", Arrays.toString(hidden.get(0)));
-
- cs.hideColumns(3);
- assertEquals(2, hidden.size());
- // two hidden ranges, in order:
- assertSame(hidden, cs.getHiddenColumns());
- assertEquals("[3, 3]", Arrays.toString(hidden.get(0)));
- assertEquals("[5, 5]", Arrays.toString(hidden.get(1)));
-
- // hiding column 4 expands [3, 3] to [3, 4]
- // and merges to [5, 5] to make [3, 5]
- cs.hideColumns(4);
- hidden = cs.getHiddenColumns();
- assertEquals(1, hidden.size());
- assertEquals("[3, 5]", Arrays.toString(hidden.get(0)));
-
- // clear hidden columns (note they are added to selected)
- cs.revealAllHiddenColumns();
- // it is now actually null but getter returns an empty list
- assertTrue(cs.getHiddenColumns().isEmpty());
-
- cs.hideColumns(3, 6);
- hidden = cs.getHiddenColumns();
- int[] firstHiddenRange = hidden.get(0);
- assertEquals("[3, 6]", Arrays.toString(firstHiddenRange));
-
- // adding a subrange of already hidden should do nothing
- cs.hideColumns(4, 5);
- assertEquals(1, hidden.size());
- assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
- cs.hideColumns(3, 5);
- assertEquals(1, hidden.size());
- assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
- cs.hideColumns(4, 6);
- assertEquals(1, hidden.size());
- assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
- cs.hideColumns(3, 6);
- assertEquals(1, hidden.size());
- assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
-
- cs.revealAllHiddenColumns();
- cs.hideColumns(2, 4);
- hidden = cs.getHiddenColumns();
- assertEquals(1, hidden.size());
- assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
-
- // extend contiguous with 2 positions overlap
- cs.hideColumns(3, 5);
- assertEquals(1, hidden.size());
- assertEquals("[2, 5]", Arrays.toString(hidden.get(0)));
-
- // extend contiguous with 1 position overlap
- cs.hideColumns(5, 6);
- assertEquals(1, hidden.size());
- assertEquals("[2, 6]", Arrays.toString(hidden.get(0)));
-
- // extend contiguous with overlap both ends:
- cs.hideColumns(1, 7);
- assertEquals(1, hidden.size());
- assertEquals("[1, 7]", Arrays.toString(hidden.get(0)));
- }
-
- /**
* Test the method that hides a specified column including any adjacent
* selected columns. This is a convenience method for the case where multiple
* column regions are selected and then hidden using menu option View | Hide |
@Test(groups = { "Functional" })
public void testHideColumns_withSelection()
{
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ AlignmentI al = gen.generate(50, 20, 123, 5, 5);
+
ColumnSelection cs = new ColumnSelection();
// select columns 4-6
cs.addElement(4);
cs.addElement(5);
cs.addElement(6);
// hide column 5 (and adjacent):
- cs.hideColumns(5);
+ cs.hideSelectedColumns(5, al.getHiddenColumns());
// 4,5,6 now hidden:
- List<int[]> hidden = cs.getHiddenColumns();
+ List<int[]> hidden = al.getHiddenColumns().getHiddenRegions();
assertEquals(1, hidden.size());
assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
// none now selected:
assertTrue(cs.getSelected().isEmpty());
// repeat, hiding column 4 (5 and 6)
+ al = gen.generate(50, 20, 123, 5, 5);
cs = new ColumnSelection();
cs.addElement(4);
cs.addElement(5);
cs.addElement(6);
- cs.hideColumns(4);
- hidden = cs.getHiddenColumns();
+ cs.hideSelectedColumns(4, al.getHiddenColumns());
+ hidden = al.getHiddenColumns().getHiddenRegions();
assertEquals(1, hidden.size());
assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
assertTrue(cs.getSelected().isEmpty());
// repeat, hiding column (4, 5 and) 6
+ al = gen.generate(50, 20, 123, 5, 5);
cs = new ColumnSelection();
cs.addElement(4);
cs.addElement(5);
cs.addElement(6);
- cs.hideColumns(6);
- hidden = cs.getHiddenColumns();
+ cs.hideSelectedColumns(6, al.getHiddenColumns());
+ hidden = al.getHiddenColumns().getHiddenRegions();
assertEquals(1, hidden.size());
assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
assertTrue(cs.getSelected().isEmpty());
// repeat, with _only_ adjacent columns selected
+ al = gen.generate(50, 20, 123, 5, 5);
cs = new ColumnSelection();
cs.addElement(4);
cs.addElement(6);
- cs.hideColumns(5);
- hidden = cs.getHiddenColumns();
+ cs.hideSelectedColumns(5, al.getHiddenColumns());
+ hidden = al.getHiddenColumns().getHiddenRegions();
assertEquals(1, hidden.size());
assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
assertTrue(cs.getSelected().isEmpty());
@Test(groups = { "Functional" })
public void testHideSelectedColumns()
{
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ AlignmentI al = gen.generate(50, 20, 123, 5, 5);
+
ColumnSelection cs = new ColumnSelection();
int[] sel = { 2, 3, 4, 7, 8, 9, 20, 21, 22 };
for (int col : sel)
{
cs.addElement(col);
}
- cs.hideColumns(15, 18);
- cs.hideSelectedColumns();
+ HiddenColumns cols = al.getHiddenColumns();
+ cols.hideColumns(15, 18);
+
+ cs.hideSelectedColumns(al);
assertTrue(cs.getSelected().isEmpty());
- List<int[]> hidden = cs.getHiddenColumns();
+ List<int[]> hidden = cols.getHiddenRegions();
assertEquals(4, hidden.size());
assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
assertEquals("[7, 9]", Arrays.toString(hidden.get(1)));
assertEquals("[0, 4]", Arrays.toString(range.get(0)));
}
- /**
- * Test the method that reveals a range of hidden columns given the start
- * column of the range
- */
- @Test(groups = { "Functional" })
- public void testRevealHiddenColumns()
- {
- ColumnSelection cs = new ColumnSelection();
- cs.hideColumns(5, 8);
- cs.addElement(10);
- cs.revealHiddenColumns(5);
- // hidden columns list now null but getter returns empty list:
- assertTrue(cs.getHiddenColumns().isEmpty());
- // revealed columns are marked as selected (added to selection):
- assertEquals("[10, 5, 6, 7, 8]", cs.getSelected().toString());
-
- // calling with a column other than the range start does nothing:
- cs = new ColumnSelection();
- cs.hideColumns(5, 8);
- List<int[]> hidden = cs.getHiddenColumns();
- cs.revealHiddenColumns(6);
- assertSame(hidden, cs.getHiddenColumns());
- assertTrue(cs.getSelected().isEmpty());
- }
-
- @Test(groups = { "Functional" })
- public void testRevealAllHiddenColumns()
- {
- ColumnSelection cs = new ColumnSelection();
- cs.hideColumns(5, 8);
- cs.hideColumns(2, 3);
- cs.addElement(11);
- cs.addElement(1);
- cs.revealAllHiddenColumns();
-
- /*
- * revealing hidden columns adds them (in order) to the (unordered)
- * selection list
- */
- assertTrue(cs.getHiddenColumns().isEmpty());
- assertEquals("[11, 1, 2, 3, 5, 6, 7, 8]", cs.getSelected().toString());
- }
-
- @Test(groups = { "Functional" })
- public void testIsVisible()
- {
- ColumnSelection cs = new ColumnSelection();
- cs.hideColumns(2, 4);
- cs.hideColumns(6, 7);
- assertTrue(cs.isVisible(0));
- assertTrue(cs.isVisible(-99));
- assertTrue(cs.isVisible(1));
- assertFalse(cs.isVisible(2));
- assertFalse(cs.isVisible(3));
- assertFalse(cs.isVisible(4));
- assertTrue(cs.isVisible(5));
- assertFalse(cs.isVisible(6));
- assertFalse(cs.isVisible(7));
- }
-
- @Test(groups = { "Functional" })
- public void testGetVisibleContigs()
- {
- ColumnSelection cs = new ColumnSelection();
- cs.hideColumns(3, 6);
- cs.hideColumns(8, 9);
- cs.hideColumns(12, 12);
-
- // start position is inclusive, end position exclusive:
- int[] visible = cs.getVisibleContigs(1, 13);
- assertEquals("[1, 2, 7, 7, 10, 11]", Arrays.toString(visible));
-
- visible = cs.getVisibleContigs(4, 14);
- assertEquals("[7, 7, 10, 11, 13, 13]", Arrays.toString(visible));
-
- visible = cs.getVisibleContigs(3, 10);
- assertEquals("[7, 7]", Arrays.toString(visible));
-
- visible = cs.getVisibleContigs(4, 6);
- assertEquals("[]", Arrays.toString(visible));
- }
-
@Test(groups = { "Functional" })
public void testInvertColumnSelection()
{
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ AlignmentI al = gen.generate(50, 20, 123, 5, 5);
+
ColumnSelection cs = new ColumnSelection();
cs.addElement(4);
cs.addElement(6);
cs.addElement(8);
- cs.hideColumns(3, 3);
- cs.hideColumns(6, 6);
+
+ HiddenColumns cols = al.getHiddenColumns();
+ cols.hideColumns(3, 3);
+ cols.hideColumns(6, 6);
// invert selection from start (inclusive) to end (exclusive)
- // hidden columns are _not_ changed
- cs.invertColumnSelection(2, 9);
+ cs.invertColumnSelection(2, 9, al);
assertEquals("[2, 5, 7]", cs.getSelected().toString());
- cs.invertColumnSelection(1, 9);
+ cs.invertColumnSelection(1, 9, al);
assertEquals("[1, 4, 8]", cs.getSelected().toString());
}
cs.addElement(0);
cs.addElement(513);
cs.addElement(1);
- cs.hideColumns(3);
- cs.hideColumns(7);
- cs.hideColumns(5, 9);
// same selections added in a different order
ColumnSelection cs2 = new ColumnSelection();
cs2.addElement(513);
cs2.addElement(0);
- // with no hidden columns
- assertFalse(cs.equals(cs2));
- assertFalse(cs2.equals(cs));
-
- // with hidden columns added in a different order
- cs2.hideColumns(6, 9);
- cs2.hideColumns(5, 8);
- cs2.hideColumns(3);
-
assertTrue(cs.equals(cs2));
assertTrue(cs.equals(cs));
assertTrue(cs2.equals(cs));
cs2.removeElement(12);
assertTrue(cs.equals(cs2));
-
- cs2.hideColumns(88);
- assertFalse(cs.equals(cs2));
- /*
- * unhiding a column adds it to selection!
- */
- cs2.revealHiddenColumns(88);
- assertFalse(cs.equals(cs2));
- cs.addElement(88);
- assertTrue(cs.equals(cs2));
}
+ /*
+ cs2.hideSelectedColumns(88);
+ assertFalse(cs.equals(cs2));
+ /*
+ * unhiding a column adds it to selection!
+ */
+ /* cs2.revealHiddenColumns(88);
+ assertFalse(cs.equals(cs2));
+ cs.addElement(88);
+ assertTrue(cs.equals(cs2));
+ */
+
/**
* Test the method that returns selected columns, in the order in which they
* were added
ColumnSelection cs = new ColumnSelection();
cs.addElement(3);
cs.addElement(1);
- cs.hideColumns(10, 11);
- cs.hideColumns(5, 7);
- assertEquals("[5, 7]", Arrays.toString(cs.getHiddenColumns().get(0)));
ColumnSelection cs2 = new ColumnSelection(cs);
assertTrue(cs2.hasSelectedColumns());
- assertTrue(cs2.hasHiddenColumns());
+
// order of column selection is preserved
assertEquals("[3, 1]", cs2.getSelected().toString());
- assertEquals(2, cs2.getHiddenColumns().size());
- // hidden columns are held in column order
- assertEquals("[5, 7]", Arrays.toString(cs2.getHiddenColumns().get(0)));
- assertEquals("[10, 11]", Arrays.toString(cs2.getHiddenColumns().get(1)));
}
- /**
- * Test for the case when a hidden range encloses more one already hidden
- * range
- */
- @Test(groups = { "Functional" })
- public void testHideColumns_subsumingHidden()
- {
- /*
- * JAL-2370 bug scenario:
- * two hidden ranges subsumed by a third
- */
- ColumnSelection cs = new ColumnSelection();
- cs.hideColumns(49, 59);
- cs.hideColumns(69, 79);
- List<int[]> hidden = cs.getHiddenColumns();
- assertEquals(2, hidden.size());
- assertEquals("[49, 59]", Arrays.toString(hidden.get(0)));
- assertEquals("[69, 79]", Arrays.toString(hidden.get(1)));
-
- cs.hideColumns(48, 80);
- hidden = cs.getHiddenColumns();
- assertEquals(1, hidden.size());
- assertEquals("[48, 80]", Arrays.toString(hidden.get(0)));
-
- /*
- * another...joining hidden ranges
- */
- cs = new ColumnSelection();
- cs.hideColumns(10, 20);
- cs.hideColumns(30, 40);
- cs.hideColumns(50, 60);
- // hiding 21-49 should merge to one range
- cs.hideColumns(21, 49);
- hidden = cs.getHiddenColumns();
- assertEquals(1, hidden.size());
- assertEquals("[10, 60]", Arrays.toString(hidden.get(0)));
-
- /*
- * another...lef overlap, subsumption, right overlap,
- * no overlap of existing hidden ranges
- */
- cs = new ColumnSelection();
- cs.hideColumns(10, 20);
- cs.hideColumns(10, 20);
- cs.hideColumns(30, 35);
- cs.hideColumns(40, 50);
- cs.hideColumns(60, 70);
-
- cs.hideColumns(15, 45);
- hidden = cs.getHiddenColumns();
- assertEquals(2, hidden.size());
- assertEquals("[10, 50]", Arrays.toString(hidden.get(0)));
- assertEquals("[60, 70]", Arrays.toString(hidden.get(1)));
- }
@Test(groups = { "Functional" })
public void testStretchGroup_expand()
--- /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.
+ */
+package jalview.datamodel;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertSame;
+import static org.testng.AssertJUnit.assertTrue;
+
+import jalview.analysis.AlignmentGenerator;
+import jalview.gui.JvOptionPane;
+
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.List;
+import java.util.Random;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class HiddenColumnsTest
+{
+
+ @BeforeClass(alwaysRun = true)
+ public void setUpJvOptionPane()
+ {
+ JvOptionPane.setInteractiveMode(false);
+ JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+ }
+
+ /**
+ * Test the method which counts the number of hidden columns
+ */
+ @Test(groups = { "Functional" })
+ public void testGetSize()
+ {
+ HiddenColumns hidden = new HiddenColumns();
+ assertEquals(0, hidden.getSize());
+
+ hidden.hideColumns(3, 5);
+ assertEquals(3, hidden.getSize());
+
+ hidden.hideColumns(8, 8);
+ assertEquals(4, hidden.getSize());
+
+ hidden.hideColumns(9, 14);
+ assertEquals(10, hidden.getSize());
+
+ ColumnSelection cs = new ColumnSelection();
+ hidden.revealAllHiddenColumns(cs);
+ assertEquals(0, hidden.getSize());
+ }
+
+ /**
+ * Test the method that finds the visible column position of an alignment
+ * column, allowing for hidden columns.
+ */
+ @Test(groups = { "Functional" })
+ public void testFindColumnPosition()
+ {
+ HiddenColumns cs = new HiddenColumns();
+ assertEquals(5, cs.findColumnPosition(5));
+
+ // hiding column 6 makes no difference
+ cs.hideColumns(6, 6);
+ assertEquals(5, cs.findColumnPosition(5));
+
+ // hiding column 4 moves column 5 to column 4
+ cs.hideColumns(4, 4);
+ assertEquals(4, cs.findColumnPosition(5));
+
+ // hiding column 4 moves column 4 to position 3
+ assertEquals(3, cs.findColumnPosition(4));
+
+ // hiding columns 1 and 2 moves column 5 to column 2
+ cs.hideColumns(1, 2);
+ assertEquals(2, cs.findColumnPosition(5));
+
+ // check with > 1 hidden column regions
+ // where some columns are in the hidden regions
+ HiddenColumns cs2 = new HiddenColumns();
+ cs2.hideColumns(5, 10);
+ cs2.hideColumns(20, 27);
+ cs2.hideColumns(40, 44);
+
+ // hiding columns 5-10 and 20-27 moves column 8 to column 4
+ assertEquals(4, cs2.findColumnPosition(8));
+
+ // and moves column 24 to 13
+ assertEquals(13, cs2.findColumnPosition(24));
+
+ // and moves column 28 to 14
+ assertEquals(14, cs2.findColumnPosition(28));
+
+ // and moves column 40 to 25
+ assertEquals(25, cs2.findColumnPosition(40));
+
+ // check when hidden columns start at 0 that the visible column
+ // is returned as 0
+ HiddenColumns cs3 = new HiddenColumns();
+ cs3.hideColumns(0, 4);
+ assertEquals(0, cs3.findColumnPosition(2));
+
+ }
+
+ /**
+ * Test the method that finds the visible column position a given distance
+ * before another column
+ */
+ @Test(groups = { "Functional" })
+ public void testFindColumnNToLeft()
+ {
+ HiddenColumns cs = new HiddenColumns();
+
+ // test that without hidden columns, findColumnNToLeft returns
+ // position n to left of provided position
+ int pos = cs.subtractVisibleColumns(3, 10);
+ assertEquals(7, pos);
+
+ // 0 returns same position
+ pos = cs.subtractVisibleColumns(0, 10);
+ assertEquals(10, pos);
+
+ // overflow to left returns negative number
+ pos = cs.subtractVisibleColumns(3, 0);
+ assertEquals(-3, pos);
+
+ // test that with hidden columns to left of result column
+ // behaviour is the same as above
+ cs.hideColumns(1, 3);
+
+ // position n to left of provided position
+ pos = cs.subtractVisibleColumns(3, 10);
+ assertEquals(7, pos);
+
+ // 0 returns same position
+ pos = cs.subtractVisibleColumns(0, 10);
+ assertEquals(10, pos);
+
+ // test with one set of hidden columns between start and required position
+ cs.hideColumns(12, 15);
+ pos = cs.subtractVisibleColumns(8, 17);
+ assertEquals(5, pos);
+
+ // test with two sets of hidden columns between start and required position
+ cs.hideColumns(20, 21);
+ pos = cs.subtractVisibleColumns(8, 23);
+ assertEquals(9, pos);
+
+ // repeat last 2 tests with no hidden columns to left of required position
+ ColumnSelection colsel = new ColumnSelection();
+ cs.revealAllHiddenColumns(colsel);
+
+ // test with one set of hidden columns between start and required position
+ cs.hideColumns(12, 15);
+ pos = cs.subtractVisibleColumns(8, 17);
+ assertEquals(5, pos);
+
+ // test with two sets of hidden columns between start and required position
+ cs.hideColumns(20, 21);
+ pos = cs.subtractVisibleColumns(8, 23);
+ assertEquals(9, pos);
+
+ }
+
+ @Test(groups = { "Functional" })
+ public void testGetVisibleContigs()
+ {
+ HiddenColumns cs = new HiddenColumns();
+ cs.hideColumns(3, 6);
+ cs.hideColumns(8, 9);
+ cs.hideColumns(12, 12);
+
+ // start position is inclusive, end position exclusive:
+ int[] visible = cs.getVisibleContigs(1, 13);
+ assertEquals("[1, 2, 7, 7, 10, 11]", Arrays.toString(visible));
+
+ visible = cs.getVisibleContigs(4, 14);
+ assertEquals("[7, 7, 10, 11, 13, 13]", Arrays.toString(visible));
+
+ visible = cs.getVisibleContigs(3, 10);
+ assertEquals("[7, 7]", Arrays.toString(visible));
+
+ visible = cs.getVisibleContigs(4, 6);
+ assertEquals("[]", Arrays.toString(visible));
+ }
+
+ @Test(groups = { "Functional" })
+ public void testEquals()
+ {
+ HiddenColumns cs = new HiddenColumns();
+ cs.hideColumns(5, 9);
+
+ // a different set of hidden columns
+ HiddenColumns cs2 = new HiddenColumns();
+
+ // with no hidden columns
+ assertFalse(cs.equals(cs2));
+ assertFalse(cs2.equals(cs));
+
+ // with hidden columns added in a different order
+ cs2.hideColumns(6, 9);
+ cs2.hideColumns(5, 8);
+
+ assertTrue(cs.equals(cs2));
+ assertTrue(cs.equals(cs));
+ assertTrue(cs2.equals(cs));
+ assertTrue(cs2.equals(cs2));
+ }
+
+ @Test(groups = "Functional")
+ public void testCopyConstructor()
+ {
+ HiddenColumns cs = new HiddenColumns();
+ cs.hideColumns(10, 11);
+ cs.hideColumns(5, 7);
+ assertEquals("[5, 7]", Arrays.toString(cs.getHiddenRegions().get(0)));
+
+ HiddenColumns cs2 = new HiddenColumns(cs);
+ assertTrue(cs2.hasHiddenColumns());
+ assertEquals(2, cs2.getHiddenRegions().size());
+ // hidden columns are held in column order
+ assertEquals("[5, 7]", Arrays.toString(cs2.getHiddenRegions().get(0)));
+ assertEquals("[10, 11]", Arrays.toString(cs2.getHiddenRegions().get(1)));
+ }
+
+ /**
+ * Test the code used to locate the reference sequence ruler origin
+ */
+ @Test(groups = { "Functional" })
+ public void testLocateVisibleBoundsofSequence()
+ {
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ AlignmentI al = gen.generate(50, 20, 123, 5, 5);
+
+ HiddenColumns cs = al.getHiddenColumns();
+ ColumnSelection colsel = new ColumnSelection();
+
+ SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---");
+ assertEquals(2, seq.findIndex(seq.getStart()));
+
+ // no hidden columns
+ assertEquals(
+ Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
+ seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
+ seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
+ seq.findIndex(seq.getEnd()) - 1 }),
+ Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+ // hidden column on gap after end of sequence - should not affect bounds
+ colsel.hideSelectedColumns(13, al.getHiddenColumns());
+ assertEquals(
+ Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
+ seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
+ seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
+ seq.findIndex(seq.getEnd()) - 1 }),
+ Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+ cs.revealAllHiddenColumns(colsel);
+ // hidden column on gap before beginning of sequence - should vis bounds by
+ // one
+ colsel.hideSelectedColumns(0, al.getHiddenColumns());
+ assertEquals(
+ Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 2,
+ seq.findIndex(seq.getEnd()) - 2, seq.getStart(),
+ seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
+ seq.findIndex(seq.getEnd()) - 1 }),
+ Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+ cs.revealAllHiddenColumns(colsel);
+ // hide columns around most of sequence - leave one residue remaining
+ cs.hideColumns(1, 3);
+ cs.hideColumns(6, 11);
+ assertEquals("-D",
+ cs.getVisibleSequenceStrings(0, 5, new SequenceI[] { seq })[0]);
+ assertEquals(
+ Arrays.toString(new int[] { 1, 1, 3, 3,
+ seq.findIndex(seq.getStart()) - 1,
+ seq.findIndex(seq.getEnd()) - 1 }),
+ Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+ cs.revealAllHiddenColumns(colsel);
+
+ // hide whole sequence - should just get location of hidden region
+ // containing sequence
+ cs.hideColumns(1, 11);
+ assertEquals(
+ Arrays.toString(new int[] { 0, 1, 0, 0,
+ seq.findIndex(seq.getStart()) - 1,
+ seq.findIndex(seq.getEnd()) - 1 }),
+ Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+ }
+
+ @Test(groups = { "Functional" })
+ public void testLocateVisibleBoundsPathologicals()
+ {
+ // test some pathological cases we missed
+ AlignmentI al = new Alignment(new SequenceI[] { new Sequence(
+ "refseqGaptest", "KTDVTI----------NFI-----G----L") });
+ HiddenColumns cs = new HiddenColumns();
+ cs.hideInsertionsFor(al.getSequenceAt(0));
+ assertEquals(
+ "G",
+ ""
+ + al.getSequenceAt(0).getCharAt(
+ cs.adjustForHiddenColumns(9)));
+
+ }
+
+ @Test(groups = { "Functional" })
+ public void testHideColumns()
+ {
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ AlignmentI al = gen.generate(50, 20, 123, 5, 5);
+
+ ColumnSelection colsel = new ColumnSelection();
+ HiddenColumns cs = al.getHiddenColumns();
+ colsel.hideSelectedColumns(5, al.getHiddenColumns());
+ List<int[]> hidden = cs.getHiddenRegions();
+ assertEquals(1, hidden.size());
+ assertEquals("[5, 5]", Arrays.toString(hidden.get(0)));
+
+ colsel.hideSelectedColumns(3, al.getHiddenColumns());
+ assertEquals(2, hidden.size());
+ // two hidden ranges, in order:
+ assertSame(hidden, cs.getHiddenRegions());
+ assertEquals("[3, 3]", Arrays.toString(hidden.get(0)));
+ assertEquals("[5, 5]", Arrays.toString(hidden.get(1)));
+
+ // hiding column 4 expands [3, 3] to [3, 4]
+ // and merges to [5, 5] to make [3, 5]
+ colsel.hideSelectedColumns(4, al.getHiddenColumns());
+ hidden = cs.getHiddenRegions();
+ assertEquals(1, hidden.size());
+ assertEquals("[3, 5]", Arrays.toString(hidden.get(0)));
+
+ // clear hidden columns (note they are added to selected)
+ cs.revealAllHiddenColumns(colsel);
+ // it is now actually null but getter returns an empty list
+ assertTrue(cs.getHiddenRegions().isEmpty());
+
+ cs.hideColumns(3, 6);
+ hidden = cs.getHiddenRegions();
+ int[] firstHiddenRange = hidden.get(0);
+ assertEquals("[3, 6]", Arrays.toString(firstHiddenRange));
+
+ // adding a subrange of already hidden should do nothing
+ cs.hideColumns(4, 5);
+ assertEquals(1, hidden.size());
+ assertSame(firstHiddenRange, cs.getHiddenRegions().get(0));
+ cs.hideColumns(3, 5);
+ assertEquals(1, hidden.size());
+ assertSame(firstHiddenRange, cs.getHiddenRegions().get(0));
+ cs.hideColumns(4, 6);
+ assertEquals(1, hidden.size());
+ assertSame(firstHiddenRange, cs.getHiddenRegions().get(0));
+ cs.hideColumns(3, 6);
+ assertEquals(1, hidden.size());
+ assertSame(firstHiddenRange, cs.getHiddenRegions().get(0));
+
+ cs.revealAllHiddenColumns(colsel);
+ cs.hideColumns(2, 4);
+ hidden = cs.getHiddenRegions();
+ assertEquals(1, hidden.size());
+ assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
+
+ // extend contiguous with 2 positions overlap
+ cs.hideColumns(3, 5);
+ assertEquals(1, hidden.size());
+ assertEquals("[2, 5]", Arrays.toString(hidden.get(0)));
+
+ // extend contiguous with 1 position overlap
+ cs.hideColumns(5, 6);
+ assertEquals(1, hidden.size());
+ assertEquals("[2, 6]", Arrays.toString(hidden.get(0)));
+
+ // extend contiguous with overlap both ends:
+ cs.hideColumns(1, 7);
+ assertEquals(1, hidden.size());
+ assertEquals("[1, 7]", Arrays.toString(hidden.get(0)));
+ }
+
+ /**
+ * Test the method that reveals a range of hidden columns given the start
+ * column of the range
+ */
+ @Test(groups = { "Functional" })
+ public void testRevealHiddenColumns()
+ {
+ ColumnSelection colsel = new ColumnSelection();
+ HiddenColumns cs = new HiddenColumns();
+ cs.hideColumns(5, 8);
+ colsel.addElement(10);
+ cs.revealHiddenColumns(5, colsel);
+ // hidden columns list now null but getter returns empty list:
+ assertTrue(cs.getHiddenRegions().isEmpty());
+ // revealed columns are marked as selected (added to selection):
+ assertEquals("[10, 5, 6, 7, 8]", colsel.getSelected().toString());
+
+ // calling with a column other than the range start does nothing:
+ colsel = new ColumnSelection();
+ cs = new HiddenColumns();
+ cs.hideColumns(5, 8);
+ List<int[]> hidden = cs.getHiddenRegions();
+ cs.revealHiddenColumns(6, colsel);
+ assertSame(hidden, cs.getHiddenRegions());
+ assertTrue(colsel.getSelected().isEmpty());
+ }
+
+ @Test(groups = { "Functional" })
+ public void testRevealAllHiddenColumns()
+ {
+ HiddenColumns cs = new HiddenColumns();
+ ColumnSelection colsel = new ColumnSelection();
+ cs.hideColumns(5, 8);
+ cs.hideColumns(2, 3);
+ colsel.addElement(11);
+ colsel.addElement(1);
+ cs.revealAllHiddenColumns(colsel);
+
+ /*
+ * revealing hidden columns adds them (in order) to the (unordered)
+ * selection list
+ */
+ assertTrue(cs.getHiddenRegions().isEmpty());
+ assertEquals("[11, 1, 2, 3, 5, 6, 7, 8]", colsel.getSelected()
+ .toString());
+ }
+
+ @Test(groups = { "Functional" })
+ public void testIsVisible()
+ {
+ HiddenColumns cs = new HiddenColumns();
+ cs.hideColumns(2, 4);
+ cs.hideColumns(6, 7);
+ assertTrue(cs.isVisible(0));
+ assertTrue(cs.isVisible(-99));
+ assertTrue(cs.isVisible(1));
+ assertFalse(cs.isVisible(2));
+ assertFalse(cs.isVisible(3));
+ assertFalse(cs.isVisible(4));
+ assertTrue(cs.isVisible(5));
+ assertFalse(cs.isVisible(6));
+ assertFalse(cs.isVisible(7));
+ }
+
+ /**
+ * Test for the case when a hidden range encloses more one already hidden
+ * range
+ */
+ @Test(groups = { "Functional" })
+ public void testHideColumns_subsumingHidden()
+ {
+ /*
+ * JAL-2370 bug scenario:
+ * two hidden ranges subsumed by a third
+ */
+ HiddenColumns cs = new HiddenColumns();
+ cs.hideColumns(49, 59);
+ cs.hideColumns(69, 79);
+ List<int[]> hidden = cs.getHiddenRegions();
+ assertEquals(2, hidden.size());
+ assertEquals("[49, 59]", Arrays.toString(hidden.get(0)));
+ assertEquals("[69, 79]", Arrays.toString(hidden.get(1)));
+
+ cs.hideColumns(48, 80);
+ hidden = cs.getHiddenRegions();
+ assertEquals(1, hidden.size());
+ assertEquals("[48, 80]", Arrays.toString(hidden.get(0)));
+
+ /*
+ * another...joining hidden ranges
+ */
+ cs = new HiddenColumns();
+ cs.hideColumns(10, 20);
+ cs.hideColumns(30, 40);
+ cs.hideColumns(50, 60);
+ // hiding 21-49 should merge to one range
+ cs.hideColumns(21, 49);
+ hidden = cs.getHiddenRegions();
+ assertEquals(1, hidden.size());
+ assertEquals("[10, 60]", Arrays.toString(hidden.get(0)));
+
+ /*
+ * another...left overlap, subsumption, right overlap,
+ * no overlap of existing hidden ranges
+ */
+ cs = new HiddenColumns();
+ cs.hideColumns(10, 20);
+ cs.hideColumns(10, 20);
+ cs.hideColumns(30, 35);
+ cs.hideColumns(40, 50);
+ cs.hideColumns(60, 70);
+
+ cs.hideColumns(15, 45);
+ hidden = cs.getHiddenRegions();
+ assertEquals(2, hidden.size());
+ assertEquals("[10, 50]", Arrays.toString(hidden.get(0)));
+ assertEquals("[60, 70]", Arrays.toString(hidden.get(1)));
+ }
+
+ @Test(groups = { "Functional" })
+ public void testHideBitset()
+ {
+ HiddenColumns cs;
+
+ BitSet one = new BitSet();
+
+ // one hidden range
+ one.set(1);
+ cs = new HiddenColumns();
+ cs.hideMarkedBits(one);
+ assertEquals(1, cs.getHiddenRegions().size());
+
+ one.set(2);
+ cs = new HiddenColumns();
+ cs.hideMarkedBits(one);
+ assertEquals(1, cs.getHiddenRegions().size());
+
+ one.set(3);
+ cs = new HiddenColumns();
+ cs.hideMarkedBits(one);
+ assertEquals(1, cs.getHiddenRegions().size());
+
+ // split
+ one.clear(2);
+ cs = new HiddenColumns();
+ cs.hideMarkedBits(one);
+ assertEquals(2, cs.getHiddenRegions().size());
+
+ assertEquals(0, cs.adjustForHiddenColumns(0));
+ assertEquals(2, cs.adjustForHiddenColumns(1));
+ assertEquals(4, cs.adjustForHiddenColumns(2));
+
+ // one again
+ one.clear(1);
+ cs = new HiddenColumns();
+ cs.hideMarkedBits(one);
+
+ assertEquals(1, cs.getHiddenRegions().size());
+
+ assertEquals(0, cs.adjustForHiddenColumns(0));
+ assertEquals(1, cs.adjustForHiddenColumns(1));
+ assertEquals(2, cs.adjustForHiddenColumns(2));
+ assertEquals(4, cs.adjustForHiddenColumns(3));
+ }
+
+ @Test(groups = { "Functional" })
+ public void testGetBitset()
+ {
+ BitSet toMark, fromMark;
+ long seed = -3241532;
+ Random number = new Random(seed);
+ for (int n = 0; n < 1000; n++)
+ {
+ // create a random bitfield
+ toMark = BitSet.valueOf(new long[] { number.nextLong(),
+ number.nextLong(), number.nextLong() });
+ toMark.set(n * number.nextInt(10), n * (25 + number.nextInt(25)));
+ HiddenColumns hc = new HiddenColumns();
+ hc.hideMarkedBits(toMark);
+
+ // see if we can recover bitfield
+ hc.markHiddenRegions(fromMark = new BitSet());
+ assertEquals(toMark, fromMark);
+ }
+ }
+}
JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
}
- static int SEQ_COUNT = 10;
+ static int SEQ_COUNT = 25;
SequenceI[] seqs;
seqs = new SequenceI[SEQ_COUNT];
for (int i = 0; i < SEQ_COUNT; i++)
{
- // sequence lengths are 1, 2, ... 10
- seqs[i] = new Sequence("Seq" + i, "abcdefghijk".substring(0, i + 1));
+ // sequence lengths are 1, 2, ... 25
+ seqs[i] = new Sequence("Seq" + i,
+ "abcdefghijklmnopqrstuvwxy".substring(0, i + 1));
}
}
/*
* alignment is now seq0/2/3/4/7/8/9
*/
- assertEquals(7, al.getHeight());
+ assertEquals(SEQ_COUNT - 3, al.getHeight());
assertEquals(0, hs.adjustForHiddenSeqs(0));
assertEquals(2, hs.adjustForHiddenSeqs(1));
assertEquals(3, hs.adjustForHiddenSeqs(2));
/*
* alignment is now seq0/2/3/4/7/8/9
*/
- assertEquals(7, al.getHeight());
+ assertEquals(SEQ_COUNT - 3, al.getHeight());
assertEquals(0, hs.findIndexWithoutHiddenSeqs(0));
assertEquals(0, hs.findIndexWithoutHiddenSeqs(1));
assertEquals(1, hs.findIndexWithoutHiddenSeqs(2));
}
/**
+ * Test the method that finds the visible row position a given distance before
+ * another row
+ */
+ @Test(groups = { "Functional" })
+ public void testFindIndexNFromRow()
+ {
+ AlignmentI al = new Alignment(seqs);
+ HiddenSequences hs = new HiddenSequences(al);
+
+ // test that without hidden rows, findIndexNFromRow returns
+ // position n above provided position
+ int pos = hs.subtractVisibleRows(3, 10);
+ assertEquals(7, pos);
+
+ // 0 returns same position
+ pos = hs.subtractVisibleRows(0, 10);
+ assertEquals(10, pos);
+
+ // overflow to top returns negative number
+ pos = hs.subtractVisibleRows(3, 0);
+ assertEquals(-3, pos);
+
+ // test that with hidden rows above result row
+ // behaviour is the same as above
+ hs.hideSequence(seqs[1]);
+ hs.hideSequence(seqs[2]);
+ hs.hideSequence(seqs[3]);
+
+ // position n above provided position
+ pos = hs.subtractVisibleRows(3, 10);
+ assertEquals(7, pos);
+
+ // 0 returns same position
+ pos = hs.subtractVisibleRows(0, 10);
+ assertEquals(10, pos);
+
+ // test with one set of hidden rows between start and required position
+ hs.hideSequence(seqs[12]);
+ hs.hideSequence(seqs[13]);
+ hs.hideSequence(seqs[14]);
+ hs.hideSequence(seqs[15]);
+ pos = hs.subtractVisibleRows(8, 17);
+ assertEquals(5, pos);
+
+ // test with two sets of hidden rows between start and required position
+ hs.hideSequence(seqs[20]);
+ hs.hideSequence(seqs[21]);
+ pos = hs.subtractVisibleRows(8, 23);
+ assertEquals(9, pos);
+
+ // repeat last 2 tests with no hidden columns to left of required position
+ hs.showAll(null);
+
+ // test with one set of hidden rows between start and required position
+ hs.hideSequence(seqs[12]);
+ hs.hideSequence(seqs[13]);
+ hs.hideSequence(seqs[14]);
+ hs.hideSequence(seqs[15]);
+ pos = hs.subtractVisibleRows(8, 17);
+ assertEquals(5, pos);
+
+ // test with two sets of hidden rows between start and required position
+ hs.hideSequence(seqs[20]);
+ hs.hideSequence(seqs[21]);
+ pos = hs.subtractVisibleRows(8, 23);
+ assertEquals(9, pos);
+
+ }
+
+ /**
* Test the method that reconstructs (sort of) the full alignment including
* hidden sequences
*/
assertTrue(al.getSequences().contains(seqs[1]));
HiddenSequences hs = al.getHiddenSequences();
assertEquals(0, hs.getSize());
- assertEquals(10, al.getHeight());
+ assertEquals(SEQ_COUNT, al.getHeight());
/*
* hide the second sequence in the alignment
assertTrue(hs.isHidden(seqs[1]));
assertFalse(al.getSequences().contains(seqs[1]));
assertEquals(1, hs.getSize());
- assertEquals(9, al.getHeight());
+ assertEquals(SEQ_COUNT - 1, al.getHeight());
assertSame(seqs[2], al.getSequenceAt(1));
/*
assertFalse(al.getSequences().contains(seqs[1]));
assertFalse(al.getSequences().contains(seqs[2]));
assertEquals(2, hs.getSize());
- assertEquals(8, al.getHeight());
+ assertEquals(SEQ_COUNT - 2, al.getHeight());
/*
* perform 'reveal' on what is now the second sequence in the alignment
assertTrue(revealed.contains(seqs[1]));
assertTrue(revealed.contains(seqs[2]));
assertEquals(0, hs.getSize());
- assertEquals(10, al.getHeight());
+ assertEquals(SEQ_COUNT, al.getHeight());
+ }
+
+ /**
+ * Test the method that adds a sequence to the hidden sequences and deletes it
+ * from the alignment, and its converse, where the first hidden sequences are
+ * at the bottom of the alignment (JAL-2437)
+ */
+ @Test(groups = "Functional")
+ public void testHideShowLastSequences()
+ {
+ AlignmentI al = new Alignment(seqs);
+ assertTrue(al.getSequences().contains(seqs[1]));
+ HiddenSequences hs = al.getHiddenSequences();
+ assertEquals(0, hs.getSize());
+ assertEquals(SEQ_COUNT, al.getHeight());
+
+ /*
+ * hide the last sequence in the alignment
+ */
+ hs.hideSequence(seqs[SEQ_COUNT - 1]);
+ assertFalse(hs.isHidden(seqs[SEQ_COUNT - 2]));
+ assertTrue(hs.isHidden(seqs[SEQ_COUNT - 1]));
+ assertFalse(al.getSequences().contains(seqs[SEQ_COUNT - 1]));
+ assertEquals(1, hs.getSize());
+ assertEquals(SEQ_COUNT - 1, al.getHeight());
+
+ /*
+ * hide the third last sequence in the alignment
+ */
+ hs.hideSequence(seqs[SEQ_COUNT - 3]);
+ assertFalse(hs.isHidden(seqs[SEQ_COUNT - 2]));
+ assertTrue(hs.isHidden(seqs[SEQ_COUNT - 3]));
+ assertFalse(al.getSequences().contains(seqs[SEQ_COUNT - 3]));
+ assertEquals(2, hs.getSize());
+ assertEquals(SEQ_COUNT - 2, al.getHeight());
+
+ /*
+ * reveal all the sequences, which should be reinstated in the same order as they started in
+ */
+ hs.showAll(null);
+ assertFalse(hs.isHidden(seqs[SEQ_COUNT - 3]));
+ assertFalse(hs.isHidden(seqs[SEQ_COUNT - 1]));
+ assertEquals(seqs[SEQ_COUNT - 3], al.getSequences().get(SEQ_COUNT - 3));
+ assertEquals(seqs[SEQ_COUNT - 2], al.getSequences().get(SEQ_COUNT - 2));
+ assertEquals(seqs[SEQ_COUNT - 1], al.getSequences().get(SEQ_COUNT - 1));
+ assertEquals(0, hs.getSize());
+ assertEquals(SEQ_COUNT, al.getHeight());
}
@Test(groups = "Functional")
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNotSame;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import jalview.schemes.NucleotideColourScheme;
+import jalview.schemes.PIDColourScheme;
+
+import java.awt.Color;
+
+import junit.extensions.PA;
import org.testng.annotations.Test;
public class SequenceGroupTest
{
- @Test
+ @Test(groups={"Functional"})
public void testAddSequence()
{
SequenceGroup sg = new SequenceGroup();
assertTrue(sg.getSequences().contains(seq3));
}
- @Test
+ @Test(groups={"Functional"})
public void testAddOrRemove()
{
SequenceGroup sg = new SequenceGroup();
assertFalse(sg.getSequences().contains(seq1));
}
- @Test
+ @Test(groups={"Functional"})
public void testGetColourScheme()
{
SequenceGroup sg = new SequenceGroup();
assertSame(scheme, sg.getColourScheme());
}
- @Test
+ @Test(groups={"Functional"})
public void testSetContext()
{
SequenceGroup sg1 = new SequenceGroup();
// expected
assertNull(sg3.getContext());
}
+
+ /*
+ * use PrivilegedAccessor to 'force' a SequenceGroup with
+ * a circular context reference
+ */
+ PA.setValue(sg2, "context", sg2);
+ try
+ {
+ sg3.setContext(sg2, false); // circular reference in sg2
+ fail("Expected exception");
+ } catch (IllegalArgumentException e)
+ {
+ // expected
+ assertNull(sg3.getContext());
+ }
+
+ // test isDefined setting behaviour
+ sg2 = new SequenceGroup();
+ sg1.setContext(null, false);
+ assertFalse(sg1.isDefined());
+
+ sg1.setContext(sg2, false);
+ assertFalse(sg1.isDefined());
+
+ sg1.setContext(sg2, true);
+ assertTrue(sg1.isDefined());
+
+ // setContext without defined parameter does not change isDefined
+ sg1.setContext(null);
+ assertTrue(sg1.isDefined());
+
+ sg1.setContext(null, false);
+ sg1.setContext(sg2);
+ assertFalse(sg1.isDefined());
+ }
+
+ @Test(groups = { "Functional" })
+ public void testContains()
+ {
+ /*
+ * essentially the same tests as AlignmentI.findGroup
+ * but from a particular group's perspective
+ */
+
+ SequenceI seq1 = new Sequence("seq1", "ABCDEF---GHI");
+ SequenceI seq2 = new Sequence("seq2", "---JKLMNO---");
+ AlignmentI a = new Alignment(new SequenceI[] { seq1, seq2 });
+ /*
+ * add a group consisting of just "DEF"
+ */
+ SequenceGroup sg1 = new SequenceGroup();
+ sg1.addSequence(seq1, false);
+ sg1.setStartRes(3);
+ sg1.setEndRes(5);
+
+ /*
+ * test sequence membership
+ */
+ assertTrue(sg1.contains(seq1));
+ assertFalse(sg1.contains(seq2));
+
+ /*
+ * test sequence+position
+ */
+
+ assertFalse(sg1.contains(seq1, 2)); // position not in group
+ assertFalse(sg1.contains(seq1, 6)); // position not in group
+ assertFalse(sg1.contains(seq2, 5)); // sequence not in group
+ assertTrue(sg1.contains(seq1, 3)); // yes
+ assertTrue(sg1.contains(seq1, 4));
+ assertTrue(sg1.contains(seq1, 5));
+
+ /*
+ * add a group consisting of
+ * EF--
+ * KLMN
+ */
+ SequenceGroup sg2 = new SequenceGroup();
+ sg2.addSequence(seq1, false);
+ sg2.addSequence(seq2, false);
+ sg2.setStartRes(4);
+ sg2.setEndRes(7);
+ a.addGroup(sg2);
+
+ /*
+ * if a residue is in more than one group, method returns
+ * the first found (in order groups were added)
+ */
+ assertTrue(sg2.contains(seq1, 4));
+ assertTrue(sg2.contains(seq1, 5));
+
+ /*
+ * seq2 only belongs to the second group
+ */
+ assertTrue(sg2.contains(seq2, 4));
+ assertTrue(sg2.contains(seq2, 5));
+ assertTrue(sg2.contains(seq2, 6));
+ assertTrue(sg2.contains(seq2, 7));
+ assertFalse(sg2.contains(seq2, 3));
+ assertFalse(sg2.contains(seq2, 8));
+ sg2.setEndRes(8);
+ assertTrue(sg2.contains(seq2, 8));
+ sg2.deleteSequence(seq2, false);
+ assertFalse(sg2.contains(seq2));
+ }
+
+ @Test(groups = { "Functional" })
+ public void testCopyConstructor()
+ {
+ SequenceI seq = new Sequence("seq", "ABC");
+ SequenceGroup sg = new SequenceGroup();
+ sg.addSequence(seq, false);
+ sg.setName("g1");
+ sg.setDescription("desc");
+ sg.setColourScheme(new PIDColourScheme());
+ sg.setDisplayBoxes(false);
+ sg.setDisplayText(false);
+ sg.setColourText(true);
+ sg.isDefined = true;
+ sg.setShowNonconserved(true);
+ sg.setOutlineColour(Color.red);
+ sg.setIdColour(Color.blue);
+ sg.thresholdTextColour = 1;
+ sg.textColour = Color.orange;
+ sg.textColour2 = Color.yellow;
+ sg.setIgnoreGapsConsensus(false);
+ sg.setshowSequenceLogo(true);
+ sg.setNormaliseSequenceLogo(true);
+ sg.setHidereps(true);
+ sg.setHideCols(true);
+ sg.setShowConsensusHistogram(true);
+ sg.setContext(new SequenceGroup());
+
+ SequenceGroup sg2 = new SequenceGroup(sg);
+ assertEquals(sg2.getName(), sg.getName());
+ assertEquals(sg2.getDescription(), sg.getDescription());
+ assertNotSame(sg2.getGroupColourScheme(), sg.getGroupColourScheme());
+ assertSame(sg2.getColourScheme(), sg.getColourScheme());
+ assertEquals(sg2.getDisplayBoxes(), sg.getDisplayBoxes());
+ assertEquals(sg2.getDisplayText(), sg.getDisplayText());
+ assertEquals(sg2.getColourText(), sg.getColourText());
+ assertEquals(sg2.getShowNonconserved(), sg.getShowNonconserved());
+ assertEquals(sg2.getOutlineColour(), sg.getOutlineColour());
+ assertEquals(sg2.getIdColour(), sg.getIdColour());
+ assertEquals(sg2.thresholdTextColour, sg.thresholdTextColour);
+ assertEquals(sg2.textColour, sg.textColour);
+ assertEquals(sg2.textColour2, sg.textColour2);
+ assertEquals(sg2.getIgnoreGapsConsensus(), sg.getIgnoreGapsConsensus());
+ assertEquals(sg2.isShowSequenceLogo(), sg.isShowSequenceLogo());
+ assertEquals(sg2.isNormaliseSequenceLogo(),
+ sg.isNormaliseSequenceLogo());
+ assertEquals(sg2.isHidereps(), sg.isHidereps());
+ assertEquals(sg2.isHideCols(), sg.isHideCols());
+ assertEquals(sg2.isShowConsensusHistogram(),
+ sg.isShowConsensusHistogram());
+
+ /*
+ * copy of sequences
+ */
+ assertNotSame(sg2.getSequences(), sg.getSequences());
+ assertEquals(sg2.getSequences(), sg.getSequences());
+
+ /*
+ * isDefined should only be set true when a new group is added to
+ * an alignment, not in the copy constructor
+ */
+ assertFalse(sg2.isDefined());
+
+ /*
+ * context should be set explicitly, not by copy
+ */
+ assertNull(sg2.getContext());
}
}
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.List;
import java.util.Vector;
assertEquals("Gap interval 1 end wrong", 4, gapInt.get(0)[1]);
assertEquals("Gap interval 2 start wrong", 6, gapInt.get(1)[0]);
assertEquals("Gap interval 2 end wrong", 8, gapInt.get(1)[1]);
+
+ BitSet gapfield = aseq.getInsertionsAsBits();
+ BitSet expectedgaps = new BitSet();
+ expectedgaps.set(2, 5);
+ expectedgaps.set(6, 9);
+
+ assertEquals(6, expectedgaps.cardinality());
+
+ assertEquals("getInsertionsAsBits didn't mark expected number of gaps",
+ 6, gapfield.cardinality());
+
+ assertEquals("getInsertionsAsBits not correct.", expectedgaps, gapfield);
}
@Test(groups = ("Functional"))
--- /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.
+ */
+package jalview.datamodel;
+
+import static org.testng.Assert.assertTrue;
+
+import java.util.NoSuchElementException;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class VisibleColsIteratorTest
+{
+ HiddenColumns hiddenCols;
+
+ HiddenColumns hiddenColsAtStart;
+
+ @BeforeClass(groups = { "Functional" })
+ public void setup()
+ {
+ hiddenCols = new HiddenColumns();
+ hiddenCols.hideColumns(2, 4);
+
+ hiddenColsAtStart = new HiddenColumns();
+ hiddenColsAtStart.hideColumns(0, 2);
+ }
+
+ /*
+ * Test iterator iterates correctly through the columns
+ * when alignment has hidden cols
+ */
+ @Test(groups = { "Functional" })
+ public void testHasNextAndNextWithHidden()
+ {
+ VisibleColsIterator it = new VisibleColsIterator(0, 6, hiddenCols);
+ int count = 0;
+ while (it.hasNext())
+ {
+ it.next();
+ count++;
+ }
+ assertTrue(count == 4, "hasNext() is false after 4 iterations");
+ }
+
+ /*
+ * Test iterator iterates correctly through the columns
+ * when alignment has no hidden cols
+ */
+ @Test(groups = { "Functional" })
+ public void testHasNextAndNextNoHidden()
+ {
+ VisibleColsIterator it2 = new VisibleColsIterator(0, 3,
+ new HiddenColumns());
+ int count = 0;
+ while (it2.hasNext())
+ {
+ it2.next();
+ count++;
+ }
+ assertTrue(count == 4, "hasNext() is false after 4 iterations");
+ }
+
+ /*
+ * Test iterator iterates correctly through the columns
+ * when alignment has hidden cols at start
+ */
+ @Test(groups = { "Functional" })
+ public void testHasNextAndNextStartHidden()
+ {
+ VisibleColsIterator it3 = new VisibleColsIterator(0, 6,
+ hiddenColsAtStart);
+ int count = 0;
+ while (it3.hasNext())
+ {
+ it3.next();
+ count++;
+ }
+ assertTrue(count == 4, "hasNext() is false after 4 iterations");
+ }
+
+ /*
+ * Test iterator iterates correctly through the columns
+ * when alignment has hidden cols at end
+ */
+ @Test(groups = { "Functional" })
+ public void testHasNextAndNextEndHidden()
+ {
+ VisibleColsIterator it4 = new VisibleColsIterator(0, 4, hiddenCols);
+ int count = 0;
+ while (it4.hasNext())
+ {
+ it4.next();
+ count++;
+ }
+ assertTrue(count == 2, "hasNext() is false after 2 iterations");
+
+ }
+
+ /*
+ * Test iterator always throws NoSuchElementException at end of iteration
+ * when alignment has hidden cols
+ */
+ @Test(
+ groups = { "Functional" },
+ expectedExceptions = { NoSuchElementException.class })
+ public void testLastNextWithHidden() throws NoSuchElementException
+ {
+ VisibleColsIterator it = new VisibleColsIterator(0, 3, hiddenCols);
+ while (it.hasNext())
+ {
+ it.next();
+ }
+ it.next();
+ }
+
+ /*
+ * Test iterator always throws NoSuchElementException at end of iteration
+ * when alignment has no hidden cols
+ */
+ @Test(
+ groups = { "Functional" },
+ expectedExceptions = { NoSuchElementException.class })
+ public void testLastNextNoHidden() throws NoSuchElementException
+ {
+ VisibleColsIterator it2 = new VisibleColsIterator(0, 3,
+ new HiddenColumns());
+ while (it2.hasNext())
+ {
+ it2.next();
+ }
+ it2.next();
+ }
+
+ /*
+ * Test iterator always throws NoSuchElementException at end of iteration
+ * when alignment has hidden cols at start
+ */
+ @Test(
+ groups = { "Functional" },
+ expectedExceptions = { NoSuchElementException.class })
+ public void testLastNextStartHidden() throws NoSuchElementException
+ {
+ VisibleColsIterator it3 = new VisibleColsIterator(0, 6,
+ hiddenColsAtStart);
+ while (it3.hasNext())
+ {
+ it3.next();
+ }
+ it3.next();
+ }
+
+ /*
+ * Test iterator always throws NoSuchElementException at end of iteration
+ * when alignment has hidden cols at end
+ */
+ @Test(
+ groups = { "Functional" },
+ expectedExceptions = { NoSuchElementException.class })
+ public void testLastNextEndHidden() throws NoSuchElementException
+ {
+ VisibleColsIterator it4 = new VisibleColsIterator(0, 4, hiddenCols);
+ while (it4.hasNext())
+ {
+ it4.next();
+ }
+ it4.next();
+ }
+
+ /*
+ * Test calls to remove throw UnsupportedOperationException
+ */
+ @Test(
+ groups = { "Functional" },
+ expectedExceptions = { UnsupportedOperationException.class })
+ public void testRemove() throws UnsupportedOperationException
+ {
+ VisibleColsIterator it = new VisibleColsIterator(0, 3, hiddenCols);
+ it.remove();
+ }
+}
--- /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.
+ */
+package jalview.datamodel;
+
+import static org.testng.Assert.assertTrue;
+
+import jalview.analysis.AlignmentGenerator;
+
+import java.util.Hashtable;
+import java.util.NoSuchElementException;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class VisibleRowsIteratorTest
+{
+ AlignmentI al;
+
+ AlignmentI al2;
+
+ AlignmentI al3;
+
+ Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences = new Hashtable<SequenceI, SequenceCollectionI>();
+
+ Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences2 = new Hashtable<SequenceI, SequenceCollectionI>();
+
+ @BeforeClass(groups = { "Functional" })
+ public void setup()
+ {
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ al = gen.generate(20, 15, 123, 5, 5);
+ if (!hiddenRepSequences.isEmpty())
+ {
+ al.getHiddenSequences().showAll(hiddenRepSequences);
+ }
+ hideSequences(al, hiddenRepSequences, 2, 4);
+
+ al2 = gen.generate(20, 15, 123, 5, 5);
+ if (!hiddenRepSequences2.isEmpty())
+ {
+ al2.getHiddenSequences().showAll(hiddenRepSequences2);
+ }
+ hideSequences(al2, hiddenRepSequences2, 0, 2);
+
+ al3 = gen.generate(20, 15, 123, 5, 5);
+ }
+
+ /*
+ * Test iterator iterates correctly through the rows
+ * when alignment has hidden rows
+ */
+ @Test(groups = { "Functional" })
+ public void testHasNextAndNextWithHidden()
+ {
+ VisibleRowsIterator it = new VisibleRowsIterator(0, 6, al);
+ int count = 0;
+ while (it.hasNext())
+ {
+ it.next();
+ count++;
+ }
+ assertTrue(count == 4, "hasNext() is false after 4 iterations");
+ }
+
+ /*
+ * Test iterator iterates correctly through the rows
+ * when alignment has no hidden rows
+ */
+ @Test(groups = { "Functional" })
+ public void testHasNextAndNextNoHidden()
+ {
+ VisibleRowsIterator it = new VisibleRowsIterator(0, 3, al3);
+ int count = 0;
+ while (it.hasNext())
+ {
+ it.next();
+ count++;
+ }
+ assertTrue(count == 4, "hasNext() is false after 4 iterations");
+ }
+
+ /*
+ * Test iterator iterates correctly through the rows
+ * when alignment has hidden rows at start
+ */
+ @Test(groups = { "Functional" })
+ public void testHasNextAndNextStartHidden()
+ {
+ VisibleRowsIterator it = new VisibleRowsIterator(0, 6, al2);
+ int count = 0;
+ while (it.hasNext())
+ {
+ it.next();
+ count++;
+ }
+ assertTrue(count == 4, "hasNext() is false after 4 iterations");
+ }
+
+ /*
+ * Test iterator iterates correctly through the rows
+ * when alignment has hidden rows at end
+ */
+ @Test(groups = { "Functional" })
+ public void testHasNextAndNextEndHidden()
+ {
+ VisibleRowsIterator it = new VisibleRowsIterator(0, 4, al);
+ int count = 0;
+ while (it.hasNext())
+ {
+ it.next();
+ count++;
+ }
+ assertTrue(count == 2, "hasNext() is false after 2 iterations");
+ }
+
+ /*
+ * Test iterator always throws NoSuchElementException at end of iteration
+ * when alignment has hidden rows
+ */
+ @Test(
+ groups = { "Functional" },
+ expectedExceptions = { NoSuchElementException.class })
+ public void testLastNextWithHidden() throws NoSuchElementException
+ {
+ VisibleRowsIterator it = new VisibleRowsIterator(0, 3, al);
+ while (it.hasNext())
+ {
+ it.next();
+ }
+ it.next();
+ }
+
+ /*
+ * Test iterator always throws NoSuchElementException at end of iteration
+ * when alignment has no hidden rows
+ */
+ @Test(
+ groups = { "Functional" },
+ expectedExceptions = { NoSuchElementException.class })
+ public void testLastNextNoHidden() throws NoSuchElementException
+ {
+ VisibleRowsIterator it = new VisibleRowsIterator(0, 3, al3);
+ while (it.hasNext())
+ {
+ it.next();
+ }
+ it.next();
+ }
+
+ /*
+ * Test iterator always throws NoSuchElementException at end of iteration
+ * when alignment has hidden rows at start
+ */
+ @Test(
+ groups = { "Functional" },
+ expectedExceptions = { NoSuchElementException.class })
+ public void testLastNextStartHidden() throws NoSuchElementException
+ {
+ VisibleRowsIterator it = new VisibleRowsIterator(0, 3, al2);
+ while (it.hasNext())
+ {
+ it.next();
+ }
+ it.next();
+ }
+
+ /*
+ * Test iterator always throws NoSuchElementException at end of iteration
+ * when alignment has hidden rows at end
+ */
+ @Test(
+ groups = { "Functional" },
+ expectedExceptions = { NoSuchElementException.class })
+ public void testLastNextEndHidden() throws NoSuchElementException
+ {
+ VisibleRowsIterator it = new VisibleRowsIterator(0, 4, al);
+ while (it.hasNext())
+ {
+ it.next();
+ }
+ it.next();
+ }
+
+ /*
+ * Test calls to remove throw UnsupportedOperationException
+ */
+ @Test(
+ groups = { "Functional" },
+ expectedExceptions = { UnsupportedOperationException.class })
+ public void testRemove() throws UnsupportedOperationException
+ {
+ VisibleRowsIterator it = new VisibleRowsIterator(0, 3, al);
+ it.remove();
+ }
+
+ /*
+ * Hide sequences between start and end
+ */
+ private void hideSequences(AlignmentI alignment,
+ Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences,
+ int start, int end)
+ {
+ SequenceI[] allseqs = alignment.getSequencesArray();
+ SequenceGroup theseSeqs = new SequenceGroup();
+
+ for (int i = start; i <= end; i++)
+ {
+ theseSeqs.addSequence(allseqs[i], false);
+ alignment.getHiddenSequences().hideSequence(allseqs[i]);
+ }
+
+ hiddenRepSequences.put(allseqs[start], theseSeqs);
+ }
+}
--- /dev/null
+package jalview.ext.android;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+public class SparseDoubleArrayTest
+{
+
+ @Test
+ public void testConstructor()
+ {
+ double[] d = new double[] { 0d, 0d, 1.2d, 0d, 0d, 3.4d };
+ SparseDoubleArray s = new SparseDoubleArray(d);
+ for (int i = 0; i < d.length; i++)
+ {
+ assertEquals(s.get(i), d[i], "At [" + i + "]");
+ }
+ }
+
+ @Test
+ public void testAdd()
+ {
+ double[] d = new double[] { 0d, 0d, 1.2d, 0d, 0d, 3.4d };
+ SparseDoubleArray s = new SparseDoubleArray(d);
+ // add to zero (absent)
+ s.add(0, 3.2d);
+ assertEquals(s.get(0), 3.2d);
+ // add to non-zero
+ s.add(0, 2.5d);
+ assertEquals(s.get(0), 5.7d);
+ // add negative value
+ s.add(2, -5.3d);
+ assertEquals(s.get(2), -4.1d);
+ // add to unset value
+ s.add(12, 9.8d);
+ assertEquals(s.get(12), 9.8d);
+ }
+
+ @Test
+ public void testDivide()
+ {
+ double delta = 1.0e-10;
+ double[] d = new double[] { 0d, 2.4d, 1.2d, 0d, -4.8d, -3.6d };
+ SparseDoubleArray s = new SparseDoubleArray(d);
+ assertEquals(s.divide(0, 1d), 0d); // no such entry
+ assertEquals(s.divide(2, 0d), 0d); // zero divisor
+ assertEquals(s.divide(1, 2d), 1.2d, delta); // + / +
+ assertEquals(s.divide(2, -2d), -0.6d, delta); // + / -
+ assertEquals(s.divide(4, 3d), -1.6d, delta); // - / +
+ assertEquals(s.divide(5, -3d), 1.2d, delta); // - / -
+ }
+}
*/
package jalview.ext.jmol;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
import jalview.gui.JvOptionPane;
import jalview.gui.SequenceRenderer;
+import jalview.schemes.JalviewColourScheme;
+import jalview.structure.StructureMapping;
import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
+import java.util.HashMap;
+
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
// need some mappings!
StructureMappingcommandSet[] commands = JmolCommands
- .getColourBySequenceCommand(ssm, files, seqs, sr, null, al);
+ .getColourBySequenceCommand(ssm, files, seqs, sr, af.alignPanel);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testGetColourBySequenceCommands_hiddenColumns()
+ {
+ /*
+ * load these sequences, coloured by Strand propensity,
+ * with columns 2-4 hidden
+ */
+ SequenceI seq1 = new Sequence("seq1", "MHRSQSSSGG");
+ SequenceI seq2 = new Sequence("seq2", "MVRSNGGSSS");
+ AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
+ AlignFrame af = new AlignFrame(al, 800, 500);
+ af.changeColour_actionPerformed(JalviewColourScheme.Strand.toString());
+ ColumnSelection cs = new ColumnSelection();
+ cs.addElement(2);
+ cs.addElement(3);
+ cs.addElement(4);
+ af.getViewport().setColumnSelection(cs);
+ af.hideSelColumns_actionPerformed(null);
+ SequenceRenderer sr = new SequenceRenderer(af.getViewport());
+ SequenceI[][] seqs = new SequenceI[][] { { seq1 }, { seq2 } };
+ String[] files = new String[] { "seq1.pdb", "seq2.pdb" };
+ StructureSelectionManager ssm = new StructureSelectionManager();
+
+ /*
+ * map residues 1-10 to residues 21-30 (atoms 105-150) in structures
+ */
+ HashMap<Integer, int[]> map = new HashMap<Integer, int[]>();
+ for (int pos = 1; pos <= seq1.getLength(); pos++)
+ {
+ map.put(pos, new int[] { 20 + pos, 5 * (20 + pos) });
+ }
+ StructureMapping sm1 = new StructureMapping(seq1, "seq1.pdb", "pdb1",
+ "A", map, null);
+ ssm.addStructureMapping(sm1);
+ StructureMapping sm2 = new StructureMapping(seq2, "seq2.pdb", "pdb2",
+ "B", map, null);
+ ssm.addStructureMapping(sm2);
+
+ StructureMappingcommandSet[] commands = JmolCommands
+ .getColourBySequenceCommand(ssm, files, seqs, sr, af.alignPanel);
+ assertEquals(commands.length, 2);
+ assertEquals(commands[0].commands.length, 1);
+
+ String chainACommand = commands[0].commands[0];
+ // M colour is #82827d == (130, 130, 125) (see strand.html help page)
+ assertTrue(chainACommand
+ .contains(";select 21:A/1.1;color[130,130,125]"));
+ // H colour is #60609f == (96, 96, 159)
+ assertTrue(chainACommand.contains(";select 22:A/1.1;color[96,96,159]"));
+ // hidden columns are Gray (128, 128, 128)
+ assertTrue(chainACommand
+ .contains(";select 23-25:A/1.1;color[128,128,128]"));
+ // S and G are both coloured #4949b6 == (73, 73, 182)
+ assertTrue(chainACommand
+ .contains(";select 26-30:A/1.1;color[73,73,182]"));
+
+ String chainBCommand = commands[1].commands[0];
+ // M colour is #82827d == (130, 130, 125)
+ assertTrue(chainBCommand
+ .contains(";select 21:B/2.1;color[130,130,125]"));
+ // V colour is #ffff00 == (255, 255, 0)
+ assertTrue(chainBCommand
+.contains(";select 22:B/2.1;color[255,255,0]"));
+ // hidden columns are Gray (128, 128, 128)
+ assertTrue(chainBCommand
+ .contains(";select 23-25:B/2.1;color[128,128,128]"));
+ // S and G are both coloured #4949b6 == (73, 73, 182)
+ assertTrue(chainBCommand
+ .contains(";select 26-30:B/2.1;color[73,73,182]"));
}
}
* local structure files should yield a false ID based on the filename
*/
assertNotNull(structureData.getId());
- assertEquals(structureData.getId(), "localstruct.pdb");
+ assertEquals(structureData.getId(), "localstruct");
assertNotNull(structureData.getSeqs());
/*
* the ID is also the group for features derived from structure data
assertNotNull(structureData.getSeqs().get(0).getSequenceFeatures()[0].featureGroup);
assertEquals(
structureData.getSeqs().get(0).getSequenceFeatures()[0].featureGroup,
- "localstruct.pdb");
+ "localstruct");
}
}
import jalview.api.structures.JalviewStructureDisplayI;
import jalview.bin.Cache;
+import jalview.bin.Jalview;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
import jalview.gui.JvOptionPane;
@BeforeClass(alwaysRun = true)
public static void setUpBeforeClass() throws Exception
{
- jalview.bin.Jalview.main(new String[] {
- "-noquestionnaire -nonews -props",
+ Jalview.main(new String[] { "-noquestionnaire", "-nonews", "-props",
"test/jalview/ext/rbvi/chimera/testProps.jvprops" });
}
}
}
}
+
+
}
--- /dev/null
+HEADER ELECTRON TRANSPORT 26-APR-15 4ZHO
+TITLE THE CRYSTAL STRUCTURE OF ARABIDOPSIS FERREDOXIN 2 WITH 2FE-2S CLUSTER
+COMPND MOL_ID: 1;
+COMPND 2 MOLECULE: FERREDOXIN-2, CHLOROPLASTIC;
+COMPND 3 CHAIN: A, B;
+COMPND 4 SYNONYM: ATFD2;
+COMPND 5 ENGINEERED: YES
+SOURCE MOL_ID: 1;
+SOURCE 2 ORGANISM_SCIENTIFIC: ARABIDOPSIS THALIANA;
+SOURCE 3 ORGANISM_COMMON: MOUSE-EAR CRESS;
+SOURCE 4 ORGANISM_TAXID: 3702;
+SOURCE 5 GENE: FD2, PETF, PETF1, AT1G60950, T7P1.9;
+SOURCE 6 EXPRESSION_SYSTEM: ESCHERICHIA COLI BL21(DE3);
+SOURCE 7 EXPRESSION_SYSTEM_TAXID: 469008
+KEYWDS FERREDOXIN 2FE-2S CLUSTER ELECTRON TRANSFER CHLOROPLAST, ELECTRON
+KEYWDS 2 TRANSPORT
+EXPDTA X-RAY DIFFRACTION
+AUTHOR R.GRINTER,I.JOSTS,A.W.ROSZAK,R.J.COGDELL,D.WALKER
+REVDAT 2 09-NOV-16 4ZHO 1 JRNL
+REVDAT 1 31-AUG-16 4ZHO 0
+JRNL AUTH R.GRINTER,I.JOSTS,K.MOSBAHI,A.W.ROSZAK,R.J.COGDELL,
+JRNL AUTH 2 A.M.BONVIN,J.J.MILNER,S.M.KELLY,O.BYRON,B.O.SMITH,D.WALKER
+JRNL TITL STRUCTURE OF THE BACTERIAL PLANT-FERREDOXIN RECEPTOR FUSA.
+JRNL REF NAT COMMUN V. 7 13308 2016
+JRNL REFN ESSN 2041-1723
+JRNL PMID 27796364
+JRNL DOI 10.1038/NCOMMS13308
+REMARK 2
+REMARK 2 RESOLUTION. 2.34 ANGSTROMS.
+REMARK 3
+REMARK 3 REFINEMENT.
+REMARK 3 PROGRAM : REFMAC 5.8.0049
+REMARK 3 AUTHORS : MURSHUDOV,VAGIN,DODSON
+REMARK 3
+REMARK 3 REFINEMENT TARGET : MAXIMUM LIKELIHOOD
+REMARK 3
+REMARK 3 DATA USED IN REFINEMENT.
+REMARK 3 RESOLUTION RANGE HIGH (ANGSTROMS) : 2.34
+REMARK 3 RESOLUTION RANGE LOW (ANGSTROMS) : 60.73
+REMARK 3 DATA CUTOFF (SIGMA(F)) : NULL
+REMARK 3 COMPLETENESS FOR RANGE (%) : 99.5
+REMARK 3 NUMBER OF REFLECTIONS : 12221
+REMARK 3
+REMARK 3 FIT TO DATA USED IN REFINEMENT.
+REMARK 3 CROSS-VALIDATION METHOD : THROUGHOUT
+REMARK 3 FREE R VALUE TEST SET SELECTION : RANDOM
+REMARK 3 R VALUE (WORKING + TEST SET) : 0.198
+REMARK 3 R VALUE (WORKING SET) : 0.197
+REMARK 3 FREE R VALUE : 0.216
+REMARK 3 FREE R VALUE TEST SET SIZE (%) : 4.900
+REMARK 3 FREE R VALUE TEST SET COUNT : 627
+REMARK 3
+REMARK 3 FIT IN THE HIGHEST RESOLUTION BIN.
+REMARK 3 TOTAL NUMBER OF BINS USED : 20
+REMARK 3 BIN RESOLUTION RANGE HIGH (A) : 2.34
+REMARK 3 BIN RESOLUTION RANGE LOW (A) : 2.40
+REMARK 3 REFLECTION IN BIN (WORKING SET) : 864
+REMARK 3 BIN COMPLETENESS (WORKING+TEST) (%) : 98.58
+REMARK 3 BIN R VALUE (WORKING SET) : 0.2390
+REMARK 3 BIN FREE R VALUE SET COUNT : 39
+REMARK 3 BIN FREE R VALUE : 0.3090
+REMARK 3
+REMARK 3 NUMBER OF NON-HYDROGEN ATOMS USED IN REFINEMENT.
+REMARK 3 PROTEIN ATOMS : 1440
+REMARK 3 NUCLEIC ACID ATOMS : 0
+REMARK 3 HETEROGEN ATOMS : 10
+REMARK 3 SOLVENT ATOMS : 38
+REMARK 3
+REMARK 3 B VALUES.
+REMARK 3 FROM WILSON PLOT (A**2) : NULL
+REMARK 3 MEAN B VALUE (OVERALL, A**2) : 59.55
+REMARK 3 OVERALL ANISOTROPIC B VALUE.
+REMARK 3 B11 (A**2) : 2.75000
+REMARK 3 B22 (A**2) : 2.75000
+REMARK 3 B33 (A**2) : -5.50000
+REMARK 3 B12 (A**2) : 0.00000
+REMARK 3 B13 (A**2) : 0.00000
+REMARK 3 B23 (A**2) : 0.00000
+REMARK 3
+REMARK 3 ESTIMATED OVERALL COORDINATE ERROR.
+REMARK 3 ESU BASED ON R VALUE (A): 0.229
+REMARK 3 ESU BASED ON FREE R VALUE (A): 0.180
+REMARK 3 ESU BASED ON MAXIMUM LIKELIHOOD (A): 0.136
+REMARK 3 ESU FOR B VALUES BASED ON MAXIMUM LIKELIHOOD (A**2): 12.808
+REMARK 3
+REMARK 3 CORRELATION COEFFICIENTS.
+REMARK 3 CORRELATION COEFFICIENT FO-FC : 0.949
+REMARK 3 CORRELATION COEFFICIENT FO-FC FREE : 0.952
+REMARK 3
+REMARK 3 RMS DEVIATIONS FROM IDEAL VALUES COUNT RMS WEIGHT
+REMARK 3 BOND LENGTHS REFINED ATOMS (A): 1468 ; 0.017 ; 0.019
+REMARK 3 BOND LENGTHS OTHERS (A): 1296 ; 0.001 ; 0.020
+REMARK 3 BOND ANGLES REFINED ATOMS (DEGREES): 1990 ; 1.933 ; 1.975
+REMARK 3 BOND ANGLES OTHERS (DEGREES): 3026 ; 0.912 ; 3.000
+REMARK 3 TORSION ANGLES, PERIOD 1 (DEGREES): 192 ; 7.288 ; 5.000
+REMARK 3 TORSION ANGLES, PERIOD 2 (DEGREES): 66 ;34.298 ;26.970
+REMARK 3 TORSION ANGLES, PERIOD 3 (DEGREES): 234 ;14.918 ;15.000
+REMARK 3 TORSION ANGLES, PERIOD 4 (DEGREES): 2 ; 5.922 ;15.000
+REMARK 3 CHIRAL-CENTER RESTRAINTS (A**3): 230 ; 0.115 ; 0.200
+REMARK 3 GENERAL PLANES REFINED ATOMS (A): 1682 ; 0.007 ; 0.020
+REMARK 3 GENERAL PLANES OTHERS (A): 276 ; 0.001 ; 0.020
+REMARK 3 NON-BONDED CONTACTS REFINED ATOMS (A): NULL ; NULL ; NULL
+REMARK 3 NON-BONDED CONTACTS OTHERS (A): NULL ; NULL ; NULL
+REMARK 3 NON-BONDED TORSION REFINED ATOMS (A): NULL ; NULL ; NULL
+REMARK 3 NON-BONDED TORSION OTHERS (A): NULL ; NULL ; NULL
+REMARK 3 H-BOND (X...Y) REFINED ATOMS (A): NULL ; NULL ; NULL
+REMARK 3 H-BOND (X...Y) OTHERS (A): NULL ; NULL ; NULL
+REMARK 3 POTENTIAL METAL-ION REFINED ATOMS (A): NULL ; NULL ; NULL
+REMARK 3 POTENTIAL METAL-ION OTHERS (A): NULL ; NULL ; NULL
+REMARK 3 SYMMETRY VDW REFINED ATOMS (A): NULL ; NULL ; NULL
+REMARK 3 SYMMETRY VDW OTHERS (A): NULL ; NULL ; NULL
+REMARK 3 SYMMETRY H-BOND REFINED ATOMS (A): NULL ; NULL ; NULL
+REMARK 3 SYMMETRY H-BOND OTHERS (A): NULL ; NULL ; NULL
+REMARK 3 SYMMETRY METAL-ION REFINED ATOMS (A): NULL ; NULL ; NULL
+REMARK 3 SYMMETRY METAL-ION OTHERS (A): NULL ; NULL ; NULL
+REMARK 3
+REMARK 3 ISOTROPIC THERMAL FACTOR RESTRAINTS. COUNT RMS WEIGHT
+REMARK 3 MAIN-CHAIN BOND REFINED ATOMS (A**2): 774 ; 3.602 ; 4.642
+REMARK 3 MAIN-CHAIN BOND OTHER ATOMS (A**2): 773 ; 3.584 ; 4.636
+REMARK 3 MAIN-CHAIN ANGLE REFINED ATOMS (A**2): 964 ; 4.741 ; 6.949
+REMARK 3 MAIN-CHAIN ANGLE OTHER ATOMS (A**2): 965 ; 4.738 ; 6.957
+REMARK 3 SIDE-CHAIN BOND REFINED ATOMS (A**2): 694 ; 5.685 ; 5.263
+REMARK 3 SIDE-CHAIN BOND OTHER ATOMS (A**2): 691 ; 5.624 ; 5.277
+REMARK 3 SIDE-CHAIN ANGLE REFINED ATOMS (A**2): NULL ; NULL ; NULL
+REMARK 3 SIDE-CHAIN ANGLE OTHER ATOMS (A**2): 1021 ; 8.298 ; 7.648
+REMARK 3 LONG RANGE B REFINED ATOMS (A**2): 1582 ; 9.824 ;37.488
+REMARK 3 LONG RANGE B OTHER ATOMS (A**2): 1580 ; 9.825 ;37.492
+REMARK 3
+REMARK 3 ANISOTROPIC THERMAL FACTOR RESTRAINTS. COUNT RMS WEIGHT
+REMARK 3 RIGID-BOND RESTRAINTS (A**2): NULL ; NULL ; NULL
+REMARK 3 SPHERICITY; FREE ATOMS (A**2): NULL ; NULL ; NULL
+REMARK 3 SPHERICITY; BONDED ATOMS (A**2): NULL ; NULL ; NULL
+REMARK 3
+REMARK 3 NCS RESTRAINTS STATISTICS
+REMARK 3 NUMBER OF DIFFERENT NCS GROUPS : NULL
+REMARK 3
+REMARK 3 TLS DETAILS
+REMARK 3 NUMBER OF TLS GROUPS : 2
+REMARK 3
+REMARK 3 TLS GROUP : 1
+REMARK 3 NUMBER OF COMPONENTS GROUP : 1
+REMARK 3 COMPONENTS C SSSEQI TO C SSSEQI
+REMARK 3 RESIDUE RANGE : A 2 A 118
+REMARK 3 ORIGIN FOR THE GROUP (A): -11.9068 -7.9134 -35.1151
+REMARK 3 T TENSOR
+REMARK 3 T11: 0.0724 T22: 0.0486
+REMARK 3 T33: 0.0466 T12: -0.0255
+REMARK 3 T13: 0.0362 T23: -0.0257
+REMARK 3 L TENSOR
+REMARK 3 L11: 3.9618 L22: 2.5662
+REMARK 3 L33: 3.5301 L12: -0.2237
+REMARK 3 L13: -2.4244 L23: -0.7777
+REMARK 3 S TENSOR
+REMARK 3 S11: -0.1452 S12: 0.2312 S13: 0.0678
+REMARK 3 S21: 0.1082 S22: 0.0201 S23: 0.1702
+REMARK 3 S31: 0.1983 S32: -0.3971 S33: 0.1251
+REMARK 3
+REMARK 3 TLS GROUP : 2
+REMARK 3 NUMBER OF COMPONENTS GROUP : 1
+REMARK 3 COMPONENTS C SSSEQI TO C SSSEQI
+REMARK 3 RESIDUE RANGE : B 2 B 122
+REMARK 3 ORIGIN FOR THE GROUP (A): -27.4515 -16.6414 -12.3927
+REMARK 3 T TENSOR
+REMARK 3 T11: 0.0153 T22: 0.0305
+REMARK 3 T33: 0.0110 T12: 0.0014
+REMARK 3 T13: 0.0124 T23: -0.0038
+REMARK 3 L TENSOR
+REMARK 3 L11: 2.2921 L22: 2.7795
+REMARK 3 L33: 6.4597 L12: 0.0122
+REMARK 3 L13: 0.2226 L23: -0.5396
+REMARK 3 S TENSOR
+REMARK 3 S11: 0.0678 S12: -0.2191 S13: 0.0982
+REMARK 3 S21: 0.1361 S22: 0.0490 S23: 0.0984
+REMARK 3 S31: -0.1717 S32: -0.0459 S33: -0.1168
+REMARK 3
+REMARK 3 BULK SOLVENT MODELLING.
+REMARK 3 METHOD USED : MASK
+REMARK 3 PARAMETERS FOR MASK CALCULATION
+REMARK 3 VDW PROBE RADIUS : 1.20
+REMARK 3 ION PROBE RADIUS : 0.80
+REMARK 3 SHRINKAGE RADIUS : 0.80
+REMARK 3
+REMARK 3 OTHER REFINEMENT REMARKS: HYDROGENS HAVE BEEN ADDED IN THE RIDING
+REMARK 3 POSITIONS
+REMARK 4
+REMARK 4 4ZHO COMPLIES WITH FORMAT V. 3.30, 13-JUL-11
+REMARK 100
+REMARK 100 THIS ENTRY HAS BEEN PROCESSED BY PDBE ON 27-APR-15.
+REMARK 100 THE DEPOSITION ID IS D_1000209256.
+REMARK 200
+REMARK 200 EXPERIMENTAL DETAILS
+REMARK 200 EXPERIMENT TYPE : X-RAY DIFFRACTION
+REMARK 200 DATE OF DATA COLLECTION : 21-JUL-14
+REMARK 200 TEMPERATURE (KELVIN) : 100
+REMARK 200 PH : 8.5
+REMARK 200 NUMBER OF CRYSTALS USED : NULL
+REMARK 200
+REMARK 200 SYNCHROTRON (Y/N) : Y
+REMARK 200 RADIATION SOURCE : DIAMOND
+REMARK 200 BEAMLINE : I02
+REMARK 200 X-RAY GENERATOR MODEL : NULL
+REMARK 200 MONOCHROMATIC OR LAUE (M/L) : M
+REMARK 200 WAVELENGTH OR RANGE (A) : 1.74
+REMARK 200 MONOCHROMATOR : SILICON CRYSTAL
+REMARK 200 OPTICS : NULL
+REMARK 200
+REMARK 200 DETECTOR TYPE : PIXEL
+REMARK 200 DETECTOR MANUFACTURER : PSI PILATUS 6M
+REMARK 200 INTENSITY-INTEGRATION SOFTWARE : XDS
+REMARK 200 DATA SCALING SOFTWARE : AIMLESS
+REMARK 200
+REMARK 200 NUMBER OF UNIQUE REFLECTIONS : 12894
+REMARK 200 RESOLUTION RANGE HIGH (A) : 2.340
+REMARK 200 RESOLUTION RANGE LOW (A) : 60.730
+REMARK 200 REJECTION CRITERIA (SIGMA(I)) : NULL
+REMARK 200
+REMARK 200 OVERALL.
+REMARK 200 COMPLETENESS FOR RANGE (%) : 99.4
+REMARK 200 DATA REDUNDANCY : 12.30
+REMARK 200 R MERGE (I) : 0.06600
+REMARK 200 R SYM (I) : NULL
+REMARK 200 <I/SIGMA(I)> FOR THE DATA SET : 23.2000
+REMARK 200
+REMARK 200 IN THE HIGHEST RESOLUTION SHELL.
+REMARK 200 HIGHEST RESOLUTION SHELL, RANGE HIGH (A) : 2.34
+REMARK 200 HIGHEST RESOLUTION SHELL, RANGE LOW (A) : 2.40
+REMARK 200 COMPLETENESS FOR SHELL (%) : 98.4
+REMARK 200 DATA REDUNDANCY IN SHELL : 11.80
+REMARK 200 R MERGE FOR SHELL (I) : 0.59800
+REMARK 200 R SYM FOR SHELL (I) : NULL
+REMARK 200 <I/SIGMA(I)> FOR SHELL : 4.200
+REMARK 200
+REMARK 200 DIFFRACTION PROTOCOL: SINGLE WAVELENGTH
+REMARK 200 METHOD USED TO DETERMINE THE STRUCTURE: NULL
+REMARK 200 SOFTWARE USED: PHASER
+REMARK 200 STARTING MODEL: NULL
+REMARK 200
+REMARK 200 REMARK: THIN PLATES, DEEP RED BROWN COLOUR DUE TO 2FE-2S IRON
+REMARK 200 SULPHUR CLUSTER
+REMARK 280
+REMARK 280 CRYSTAL
+REMARK 280 SOLVENT CONTENT, VS (%): 64.33
+REMARK 280 MATTHEWS COEFFICIENT, VM (ANGSTROMS**3/DA): 3.45
+REMARK 280
+REMARK 280 CRYSTALLIZATION CONDITIONS: 0.2 M MGCL2, 0.1 M TRIS, 20 % PEG
+REMARK 280 8000, PH 8.5, VAPOR DIFFUSION, SITTING DROP, TEMPERATURE 294K
+REMARK 290
+REMARK 290 CRYSTALLOGRAPHIC SYMMETRY
+REMARK 290 SYMMETRY OPERATORS FOR SPACE GROUP: P 42 21 2
+REMARK 290
+REMARK 290 SYMOP SYMMETRY
+REMARK 290 NNNMMM OPERATOR
+REMARK 290 1555 X,Y,Z
+REMARK 290 2555 -X,-Y,Z
+REMARK 290 3555 -Y+1/2,X+1/2,Z+1/2
+REMARK 290 4555 Y+1/2,-X+1/2,Z+1/2
+REMARK 290 5555 -X+1/2,Y+1/2,-Z+1/2
+REMARK 290 6555 X+1/2,-Y+1/2,-Z+1/2
+REMARK 290 7555 Y,X,-Z
+REMARK 290 8555 -Y,-X,-Z
+REMARK 290
+REMARK 290 WHERE NNN -> OPERATOR NUMBER
+REMARK 290 MMM -> TRANSLATION VECTOR
+REMARK 290
+REMARK 290 CRYSTALLOGRAPHIC SYMMETRY TRANSFORMATIONS
+REMARK 290 THE FOLLOWING TRANSFORMATIONS OPERATE ON THE ATOM/HETATM
+REMARK 290 RECORDS IN THIS ENTRY TO PRODUCE CRYSTALLOGRAPHICALLY
+REMARK 290 RELATED MOLECULES.
+REMARK 290 SMTRY1 1 1.000000 0.000000 0.000000 0.00000
+REMARK 290 SMTRY2 1 0.000000 1.000000 0.000000 0.00000
+REMARK 290 SMTRY3 1 0.000000 0.000000 1.000000 0.00000
+REMARK 290 SMTRY1 2 -1.000000 0.000000 0.000000 0.00000
+REMARK 290 SMTRY2 2 0.000000 -1.000000 0.000000 0.00000
+REMARK 290 SMTRY3 2 0.000000 0.000000 1.000000 0.00000
+REMARK 290 SMTRY1 3 0.000000 -1.000000 0.000000 30.36500
+REMARK 290 SMTRY2 3 1.000000 0.000000 0.000000 30.36500
+REMARK 290 SMTRY3 3 0.000000 0.000000 1.000000 77.36500
+REMARK 290 SMTRY1 4 0.000000 1.000000 0.000000 30.36500
+REMARK 290 SMTRY2 4 -1.000000 0.000000 0.000000 30.36500
+REMARK 290 SMTRY3 4 0.000000 0.000000 1.000000 77.36500
+REMARK 290 SMTRY1 5 -1.000000 0.000000 0.000000 30.36500
+REMARK 290 SMTRY2 5 0.000000 1.000000 0.000000 30.36500
+REMARK 290 SMTRY3 5 0.000000 0.000000 -1.000000 77.36500
+REMARK 290 SMTRY1 6 1.000000 0.000000 0.000000 30.36500
+REMARK 290 SMTRY2 6 0.000000 -1.000000 0.000000 30.36500
+REMARK 290 SMTRY3 6 0.000000 0.000000 -1.000000 77.36500
+REMARK 290 SMTRY1 7 0.000000 1.000000 0.000000 0.00000
+REMARK 290 SMTRY2 7 1.000000 0.000000 0.000000 0.00000
+REMARK 290 SMTRY3 7 0.000000 0.000000 -1.000000 0.00000
+REMARK 290 SMTRY1 8 0.000000 -1.000000 0.000000 0.00000
+REMARK 290 SMTRY2 8 -1.000000 0.000000 0.000000 0.00000
+REMARK 290 SMTRY3 8 0.000000 0.000000 -1.000000 0.00000
+REMARK 290
+REMARK 290 REMARK: NULL
+REMARK 300
+REMARK 300 BIOMOLECULE: 1, 2
+REMARK 300 SEE REMARK 350 FOR THE AUTHOR PROVIDED AND/OR PROGRAM
+REMARK 300 GENERATED ASSEMBLY INFORMATION FOR THE STRUCTURE IN
+REMARK 300 THIS ENTRY. THE REMARK MAY ALSO PROVIDE INFORMATION ON
+REMARK 300 BURIED SURFACE AREA.
+REMARK 350
+REMARK 350 COORDINATES FOR A COMPLETE MULTIMER REPRESENTING THE KNOWN
+REMARK 350 BIOLOGICALLY SIGNIFICANT OLIGOMERIZATION STATE OF THE
+REMARK 350 MOLECULE CAN BE GENERATED BY APPLYING BIOMT TRANSFORMATIONS
+REMARK 350 GIVEN BELOW. BOTH NON-CRYSTALLOGRAPHIC AND
+REMARK 350 CRYSTALLOGRAPHIC OPERATIONS ARE GIVEN.
+REMARK 350
+REMARK 350 BIOMOLECULE: 1
+REMARK 350 AUTHOR DETERMINED BIOLOGICAL UNIT: MONOMERIC
+REMARK 350 APPLY THE FOLLOWING TO CHAINS: A
+REMARK 350 BIOMT1 1 1.000000 0.000000 0.000000 0.00000
+REMARK 350 BIOMT2 1 0.000000 1.000000 0.000000 0.00000
+REMARK 350 BIOMT3 1 0.000000 0.000000 1.000000 0.00000
+REMARK 350
+REMARK 350 BIOMOLECULE: 2
+REMARK 350 AUTHOR DETERMINED BIOLOGICAL UNIT: MONOMERIC
+REMARK 350 APPLY THE FOLLOWING TO CHAINS: B
+REMARK 350 BIOMT1 1 1.000000 0.000000 0.000000 0.00000
+REMARK 350 BIOMT2 1 0.000000 1.000000 0.000000 0.00000
+REMARK 350 BIOMT3 1 0.000000 0.000000 1.000000 0.00000
+REMARK 375
+REMARK 375 SPECIAL POSITION
+REMARK 375 THE FOLLOWING ATOMS ARE FOUND TO BE WITHIN 0.15 ANGSTROMS
+REMARK 375 OF A SYMMETRY RELATED ATOM AND ARE ASSUMED TO BE ON SPECIAL
+REMARK 375 POSITIONS.
+REMARK 375
+REMARK 375 ATOM RES CSSEQI
+REMARK 375 HOH B 319 LIES ON A SPECIAL POSITION.
+REMARK 465
+REMARK 465 MISSING RESIDUES
+REMARK 465 THE FOLLOWING RESIDUES WERE NOT LOCATED IN THE
+REMARK 465 EXPERIMENT. (M=MODEL NUMBER; RES=RESIDUE NAME; C=CHAIN
+REMARK 465 IDENTIFIER; SSSEQ=SEQUENCE NUMBER; I=INSERTION CODE.)
+REMARK 465
+REMARK 465 M RES C SSSEQI
+REMARK 465 MET A 1
+REMARK 465 GLU A 99
+REMARK 465 HIS A 100
+REMARK 465 HIS A 101
+REMARK 465 HIS A 102
+REMARK 465 HIS A 103
+REMARK 465 HIS A 104
+REMARK 465 HIS A 105
+REMARK 465 MET B 1
+REMARK 465 GLU B 99
+REMARK 465 HIS B 100
+REMARK 465 HIS B 101
+REMARK 465 HIS B 102
+REMARK 465 HIS B 103
+REMARK 465 HIS B 104
+REMARK 465 HIS B 105
+REMARK 470
+REMARK 470 MISSING ATOM
+REMARK 470 THE FOLLOWING RESIDUES HAVE MISSING ATOMS (M=MODEL NUMBER;
+REMARK 470 RES=RESIDUE NAME; C=CHAIN IDENTIFIER; SSEQ=SEQUENCE NUMBER;
+REMARK 470 I=INSERTION CODE):
+REMARK 470 M RES CSSEQI ATOMS
+REMARK 470 LEU A 98 CG CD1 CD2
+REMARK 470 LEU B 98 CG CD1 CD2
+REMARK 500
+REMARK 500 GEOMETRY AND STEREOCHEMISTRY
+REMARK 500 SUBTOPIC: TORSION ANGLES
+REMARK 500
+REMARK 500 TORSION ANGLES OUTSIDE THE EXPECTED RAMACHANDRAN REGIONS:
+REMARK 500 (M=MODEL NUMBER; RES=RESIDUE NAME; C=CHAIN IDENTIFIER;
+REMARK 500 SSEQ=SEQUENCE NUMBER; I=INSERTION CODE).
+REMARK 500
+REMARK 500 STANDARD TABLE:
+REMARK 500 FORMAT:(10X,I3,1X,A3,1X,A1,I4,A1,4X,F7.2,3X,F7.2)
+REMARK 500
+REMARK 500 EXPECTED VALUES: GJ KLEYWEGT AND TA JONES (1996). PHI/PSI-
+REMARK 500 CHOLOGY: RAMACHANDRAN REVISITED. STRUCTURE 4, 1395 - 1400
+REMARK 500
+REMARK 500 M RES CSSEQI PSI PHI
+REMARK 500 SER A 39 -64.23 -146.55
+REMARK 500 MET A 97 -67.17 -99.01
+REMARK 500 SER B 39 -78.49 -140.11
+REMARK 500 SER B 63 -12.80 -148.10
+REMARK 500
+REMARK 500 REMARK: NULL
+REMARK 620
+REMARK 620 METAL COORDINATION
+REMARK 620 (M=MODEL NUMBER; RES=RESIDUE NAME; C=CHAIN IDENTIFIER;
+REMARK 620 SSEQ=SEQUENCE NUMBER; I=INSERTION CODE):
+REMARK 620
+REMARK 620 COORDINATION ANGLES FOR: M RES CSSEQI METAL
+REMARK 620 FES A 201 FE1
+REMARK 620 N RES CSSEQI ATOM
+REMARK 620 1 CYS A 40 SG
+REMARK 620 2 FES A 201 S1 124.8
+REMARK 620 3 FES A 201 S2 100.1 99.4
+REMARK 620 4 CYS A 45 SG 105.3 110.0 117.8
+REMARK 620 N 1 2 3
+REMARK 620
+REMARK 620 COORDINATION ANGLES FOR: M RES CSSEQI METAL
+REMARK 620 FES A 201 FE2
+REMARK 620 N RES CSSEQI ATOM
+REMARK 620 1 CYS A 48 SG
+REMARK 620 2 FES A 201 S1 114.4
+REMARK 620 3 FES A 201 S2 108.9 101.7
+REMARK 620 4 CYS A 78 SG 105.9 122.0 102.7
+REMARK 620 N 1 2 3
+REMARK 620
+REMARK 620 COORDINATION ANGLES FOR: M RES CSSEQI METAL
+REMARK 620 FES B 201 FE1
+REMARK 620 N RES CSSEQI ATOM
+REMARK 620 1 CYS B 40 SG
+REMARK 620 2 FES B 201 S1 119.9
+REMARK 620 3 FES B 201 S2 102.0 97.8
+REMARK 620 4 CYS B 45 SG 109.5 108.1 119.7
+REMARK 620 N 1 2 3
+REMARK 620
+REMARK 620 COORDINATION ANGLES FOR: M RES CSSEQI METAL
+REMARK 620 FES B 201 FE2
+REMARK 620 N RES CSSEQI ATOM
+REMARK 620 1 CYS B 48 SG
+REMARK 620 2 FES B 201 S1 111.1
+REMARK 620 3 FES B 201 S2 115.5 99.1
+REMARK 620 4 CYS B 78 SG 110.9 117.2 102.5
+REMARK 620 N 1 2 3
+REMARK 800
+REMARK 800 SITE
+REMARK 800 SITE_IDENTIFIER: AC1
+REMARK 800 EVIDENCE_CODE: SOFTWARE
+REMARK 800 SITE_DESCRIPTION: binding site for residue FES A 201
+REMARK 800
+REMARK 800 SITE_IDENTIFIER: AC2
+REMARK 800 EVIDENCE_CODE: SOFTWARE
+REMARK 800 SITE_DESCRIPTION: binding site for residue CL A 202
+REMARK 800
+REMARK 800 SITE_IDENTIFIER: AC3
+REMARK 800 EVIDENCE_CODE: SOFTWARE
+REMARK 800 SITE_DESCRIPTION: binding site for residue FES B 201
+REMARK 800
+REMARK 800 SITE_IDENTIFIER: AC4
+REMARK 800 EVIDENCE_CODE: SOFTWARE
+REMARK 800 SITE_DESCRIPTION: binding site for residue CL B 202
+DBREF 4ZHO A 1 94 UNP P16972 FER2_ARATH 52 145
+DBREF 4ZHO B 1 94 UNP P16972 FER2_ARATH 52 145
+SEQADV 4ZHO ALA A 95 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO ILE A 96 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO MET A 97 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO LEU A 98 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO GLU A 99 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS A 100 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS A 101 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS A 102 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS A 103 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS A 104 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS A 105 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO ALA B 95 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO ILE B 96 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO MET B 97 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO LEU B 98 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO GLU B 99 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS B 100 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS B 101 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS B 102 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS B 103 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS B 104 UNP P16972 EXPRESSION TAG
+SEQADV 4ZHO HIS B 105 UNP P16972 EXPRESSION TAG
+SEQRES 1 A 105 MET ALA THR TYR LYS VAL LYS PHE ILE THR PRO GLU GLY
+SEQRES 2 A 105 GLU LEU GLU VAL GLU CYS ASP ASP ASP VAL TYR VAL LEU
+SEQRES 3 A 105 ASP ALA ALA GLU GLU ALA GLY ILE ASP LEU PRO TYR SER
+SEQRES 4 A 105 CYS ARG ALA GLY SER CYS SER SER CYS ALA GLY LYS VAL
+SEQRES 5 A 105 VAL SER GLY SER VAL ASP GLN SER ASP GLN SER PHE LEU
+SEQRES 6 A 105 ASP ASP GLU GLN ILE GLY GLU GLY PHE VAL LEU THR CYS
+SEQRES 7 A 105 ALA ALA TYR PRO THR SER ASP VAL THR ILE GLU THR HIS
+SEQRES 8 A 105 LYS GLU GLU ALA ILE MET LEU GLU HIS HIS HIS HIS HIS
+SEQRES 9 A 105 HIS
+SEQRES 1 B 105 MET ALA THR TYR LYS VAL LYS PHE ILE THR PRO GLU GLY
+SEQRES 2 B 105 GLU LEU GLU VAL GLU CYS ASP ASP ASP VAL TYR VAL LEU
+SEQRES 3 B 105 ASP ALA ALA GLU GLU ALA GLY ILE ASP LEU PRO TYR SER
+SEQRES 4 B 105 CYS ARG ALA GLY SER CYS SER SER CYS ALA GLY LYS VAL
+SEQRES 5 B 105 VAL SER GLY SER VAL ASP GLN SER ASP GLN SER PHE LEU
+SEQRES 6 B 105 ASP ASP GLU GLN ILE GLY GLU GLY PHE VAL LEU THR CYS
+SEQRES 7 B 105 ALA ALA TYR PRO THR SER ASP VAL THR ILE GLU THR HIS
+SEQRES 8 B 105 LYS GLU GLU ALA ILE MET LEU GLU HIS HIS HIS HIS HIS
+SEQRES 9 B 105 HIS
+HET FES A 201 4
+HET CL A 202 1
+HET FES B 201 4
+HET CL B 202 1
+HETNAM FES FE2/S2 (INORGANIC) CLUSTER
+HETNAM CL CHLORIDE ION
+FORMUL 3 FES 2(FE2 S2)
+FORMUL 4 CL 2(CL 1-)
+FORMUL 7 HOH *38(H2 O)
+HELIX 1 AA1 TYR A 24 ALA A 32 1 9
+HELIX 2 AA2 ASP A 66 GLU A 72 1 7
+HELIX 3 AA3 CYS A 78 ALA A 80 5 3
+HELIX 4 AA5 TYR B 24 ALA B 32 1 9
+HELIX 5 AA6 ASP B 66 GLU B 72 1 7
+HELIX 6 AA7 CYS B 78 ALA B 80 5 3
+HELIX 7 AA8 LYS B 92 MET B 97 5 6
+SHEET 1 AA1 5 GLU A 14 ASP A 20 0
+SHEET 2 AA1 5 THR A 3 ILE A 9 -1 N PHE A 8 O LEU A 15
+SHEET 3 AA1 5 VAL A 86 GLU A 89 1 O ILE A 88 N LYS A 7
+SHEET 4 AA1 5 ALA A 49 SER A 54 -1 N SER A 54 O THR A 87
+SHEET 5 AA1 5 PHE A 74 LEU A 76 -1 O VAL A 75 N GLY A 50
+SHEET 1 AA2 2 VAL A 57 ASP A 58 0
+SHEET 2 AA2 2 TYR A 81 PRO A 82 -1 O TYR A 81 N ASP A 58
+SHEET 1 AA3 5 GLY B 13 ASP B 20 0
+SHEET 2 AA3 5 THR B 3 THR B 10 -1 N PHE B 8 O LEU B 15
+SHEET 3 AA3 5 VAL B 86 GLU B 89 1 O ILE B 88 N LYS B 7
+SHEET 4 AA3 5 ALA B 49 SER B 54 -1 N LYS B 51 O GLU B 89
+SHEET 5 AA3 5 PHE B 74 LEU B 76 -1 O VAL B 75 N GLY B 50
+SHEET 1 AA4 2 VAL B 57 ASP B 58 0
+SHEET 2 AA4 2 TYR B 81 PRO B 82 -1 O TYR B 81 N ASP B 58
+LINK SG CYS A 40 FE1 FES A 201 1555 1555 2.33
+LINK SG CYS A 45 FE1 FES A 201 1555 1555 2.28
+LINK SG CYS A 48 FE2 FES A 201 1555 1555 2.28
+LINK SG CYS A 78 FE2 FES A 201 1555 1555 2.34
+LINK SG CYS B 40 FE1 FES B 201 1555 1555 2.22
+LINK SG CYS B 45 FE1 FES B 201 1555 1555 2.25
+LINK SG CYS B 48 FE2 FES B 201 1555 1555 2.18
+LINK SG CYS B 78 FE2 FES B 201 1555 1555 2.36
+SITE 1 AC1 8 SER A 39 CYS A 40 ARG A 41 GLY A 43
+SITE 2 AC1 8 SER A 44 CYS A 45 CYS A 48 CYS A 78
+SITE 1 AC2 2 SER A 84 ASP A 85
+SITE 1 AC3 8 SER B 39 CYS B 40 ARG B 41 GLY B 43
+SITE 2 AC3 8 SER B 44 CYS B 45 CYS B 48 CYS B 78
+SITE 1 AC4 2 SER B 84 ASP B 85
+CRYST1 60.730 60.730 154.730 90.00 90.00 90.00 P 42 21 2 16
+ORIGX1 1.000000 0.000000 0.000000 0.00000
+ORIGX2 0.000000 1.000000 0.000000 0.00000
+ORIGX3 0.000000 0.000000 1.000000 0.00000
+SCALE1 0.016466 0.000000 0.000000 0.00000
+SCALE2 0.000000 0.016466 0.000000 0.00000
+SCALE3 0.000000 0.000000 0.006463 0.00000
+ATOM 1 N ALA A 2 -1.257 -15.807 -48.124 1.00 50.77 N
+ANISOU 1 N ALA A 2 7787 5804 5698 -219 1819 -481 N
+ATOM 2 CA ALA A 2 -1.523 -14.339 -48.197 1.00 50.70 C
+ANISOU 2 CA ALA A 2 7568 6034 5660 -183 1548 -344 C
+ATOM 3 C ALA A 2 -1.438 -13.722 -46.830 1.00 45.70 C
+ANISOU 3 C ALA A 2 6785 5347 5230 -97 1396 -189 C
+ATOM 4 O ALA A 2 -1.809 -14.345 -45.825 1.00 44.98 O
+ANISOU 4 O ALA A 2 6732 5134 5221 -136 1414 -240 O
+ATOM 5 CB ALA A 2 -2.903 -14.040 -48.848 1.00 48.96 C
+ANISOU 5 CB ALA A 2 7316 6077 5207 -370 1390 -508 C
+ATOM 6 N THR A 3 -1.069 -12.455 -46.833 1.00 45.54 N
+ANISOU 6 N THR A 3 6600 5431 5271 -1 1249 -16 N
+ATOM 7 CA THR A 3 -0.949 -11.641 -45.631 1.00 47.35 C
+ANISOU 7 CA THR A 3 6681 5636 5674 60 1092 109 C
+ATOM 8 C THR A 3 -1.689 -10.384 -45.941 1.00 43.11 C
+ANISOU 8 C THR A 3 6022 5274 5083 31 915 145 C
+ATOM 9 O THR A 3 -1.531 -9.803 -47.012 1.00 41.92 O
+ANISOU 9 O THR A 3 5843 5236 4848 63 924 210 O
+ATOM 10 CB THR A 3 0.543 -11.321 -45.328 1.00 50.05 C
+ANISOU 10 CB THR A 3 6935 5888 6195 216 1141 301 C
+ATOM 11 OG1 THR A 3 1.229 -12.551 -45.036 1.00 50.95 O
+ANISOU 11 OG1 THR A 3 7151 5846 6362 283 1328 306 O
+ATOM 12 CG2 THR A 3 0.673 -10.438 -44.115 1.00 54.46 C
+ANISOU 12 CG2 THR A 3 7341 6448 6902 242 968 390 C
+ATOM 13 N TYR A 4 -2.484 -9.944 -44.989 1.00 46.99 N
+ANISOU 13 N TYR A 4 6443 5784 5625 -9 776 123 N
+ATOM 14 CA TYR A 4 -3.347 -8.768 -45.177 1.00 48.43 C
+ANISOU 14 CA TYR A 4 6510 6116 5775 -19 632 167 C
+ATOM 15 C TYR A 4 -3.023 -7.694 -44.144 1.00 47.22 C
+ANISOU 15 C TYR A 4 6246 5881 5813 46 540 272 C
+ATOM 16 O TYR A 4 -2.521 -7.988 -43.069 1.00 48.33 O
+ANISOU 16 O TYR A 4 6396 5904 6063 58 537 263 O
+ATOM 17 CB TYR A 4 -4.801 -9.196 -45.059 1.00 47.01 C
+ANISOU 17 CB TYR A 4 6341 6049 5468 -146 570 20 C
+ATOM 18 CG TYR A 4 -5.208 -10.134 -46.157 1.00 43.84 C
+ANISOU 18 CG TYR A 4 6035 5763 4857 -258 645 -122 C
+ATOM 19 CD1 TYR A 4 -5.280 -9.700 -47.461 1.00 48.21 C
+ANISOU 19 CD1 TYR A 4 6559 6515 5243 -243 630 -80 C
+ATOM 20 CD2 TYR A 4 -5.473 -11.470 -45.898 1.00 48.38 C
+ANISOU 20 CD2 TYR A 4 6743 6241 5397 -383 752 -303 C
+ATOM 21 CE1 TYR A 4 -5.629 -10.561 -48.480 1.00 48.93 C
+ANISOU 21 CE1 TYR A 4 6746 6739 5104 -368 694 -244 C
+ATOM 22 CE2 TYR A 4 -5.802 -12.362 -46.923 1.00 48.52 C
+ANISOU 22 CE2 TYR A 4 6868 6342 5221 -522 844 -480 C
+ATOM 23 CZ TYR A 4 -5.914 -11.892 -48.199 1.00 48.26 C
+ANISOU 23 CZ TYR A 4 6798 6543 4992 -526 799 -466 C
+ATOM 24 OH TYR A 4 -6.226 -12.778 -49.220 1.00 52.35 O
+ANISOU 24 OH TYR A 4 7434 7172 5284 -686 885 -675 O
+ATOM 25 N LYS A 5 -3.307 -6.453 -44.489 1.00 47.90 N
+ANISOU 25 N LYS A 5 6234 6036 5930 90 478 373 N
+ATOM 26 CA LYS A 5 -3.126 -5.320 -43.582 1.00 49.46 C
+ANISOU 26 CA LYS A 5 6343 6138 6309 126 414 439 C
+ATOM 27 C LYS A 5 -4.415 -5.114 -42.819 1.00 44.72 C
+ANISOU 27 C LYS A 5 5725 5576 5688 87 334 362 C
+ATOM 28 O LYS A 5 -5.464 -4.904 -43.423 1.00 45.76 O
+ANISOU 28 O LYS A 5 5820 5852 5714 87 308 374 O
+ATOM 29 CB LYS A 5 -2.776 -4.038 -44.357 1.00 51.93 C
+ANISOU 29 CB LYS A 5 6573 6454 6702 205 443 602 C
+ATOM 30 CG LYS A 5 -1.497 -4.126 -45.113 1.00 62.94 C
+ANISOU 30 CG LYS A 5 7967 7811 8137 249 542 698 C
+ATOM 31 CD LYS A 5 -0.351 -4.665 -44.240 1.00 71.74 C
+ANISOU 31 CD LYS A 5 9078 8803 9377 228 553 662 C
+ATOM 32 CE LYS A 5 -0.083 -3.798 -43.025 1.00 78.38 C
+ANISOU 32 CE LYS A 5 9836 9541 10403 192 473 648 C
+ATOM 33 NZ LYS A 5 0.491 -2.513 -43.496 1.00 87.36 N
+ANISOU 33 NZ LYS A 5 10881 10609 11701 215 524 774 N
+ATOM 34 N VAL A 6 -4.356 -5.236 -41.505 1.00 40.33 N
+ANISOU 34 N VAL A 6 5186 4922 5213 58 297 290 N
+ATOM 35 CA VAL A 6 -5.506 -4.978 -40.686 1.00 43.48 C
+ANISOU 35 CA VAL A 6 5572 5340 5608 33 246 224 C
+ATOM 36 C VAL A 6 -5.286 -3.624 -40.015 1.00 44.26 C
+ANISOU 36 C VAL A 6 5616 5334 5865 73 225 265 C
+ATOM 37 O VAL A 6 -4.317 -3.413 -39.286 1.00 45.54 O
+ANISOU 37 O VAL A 6 5782 5395 6125 57 211 245 O
+ATOM 38 CB VAL A 6 -5.704 -6.072 -39.614 1.00 47.03 C
+ANISOU 38 CB VAL A 6 6100 5753 6016 -24 246 110 C
+ATOM 39 CG1 VAL A 6 -6.982 -5.808 -38.849 1.00 45.34 C
+ANISOU 39 CG1 VAL A 6 5866 5571 5789 -46 216 50 C
+ATOM 40 CG2 VAL A 6 -5.764 -7.451 -40.254 1.00 46.02 C
+ANISOU 40 CG2 VAL A 6 6052 5664 5769 -78 315 53 C
+ATOM 41 N LYS A 7 -6.163 -2.682 -40.330 1.00 45.38 N
+ANISOU 41 N LYS A 7 5700 5508 6034 123 235 327 N
+ATOM 42 CA LYS A 7 -6.143 -1.373 -39.740 1.00 45.98 C
+ANISOU 42 CA LYS A 7 5748 5450 6273 160 263 351 C
+ATOM 43 C LYS A 7 -7.143 -1.363 -38.592 1.00 47.81 C
+ANISOU 43 C LYS A 7 6003 5668 6491 143 248 245 C
+ATOM 44 O LYS A 7 -8.347 -1.536 -38.787 1.00 51.78 O
+ANISOU 44 O LYS A 7 6468 6287 6918 173 249 263 O
+ATOM 45 CB LYS A 7 -6.506 -0.347 -40.788 1.00 48.29 C
+ANISOU 45 CB LYS A 7 5968 5763 6617 264 329 520 C
+ATOM 46 CG LYS A 7 -6.637 1.070 -40.268 1.00 58.39 C
+ANISOU 46 CG LYS A 7 7234 6859 8090 316 413 556 C
+ATOM 47 CD LYS A 7 -6.631 2.026 -41.447 1.00 68.64 C
+ANISOU 47 CD LYS A 7 8467 8148 9461 441 515 776 C
+ATOM 48 CE LYS A 7 -6.930 3.448 -41.018 1.00 82.52 C
+ANISOU 48 CE LYS A 7 10225 9693 11435 515 651 833 C
+ATOM 49 NZ LYS A 7 -6.213 4.399 -41.926 1.00 90.34 N
+ANISOU 49 NZ LYS A 7 11188 10561 12575 587 785 1022 N
+ATOM 50 N PHE A 8 -6.640 -1.148 -37.392 1.00 43.94 N
+ANISOU 50 N PHE A 8 5567 5061 6068 93 233 136 N
+ATOM 51 CA PHE A 8 -7.513 -1.002 -36.238 1.00 50.30 C
+ANISOU 51 CA PHE A 8 6412 5840 6859 87 244 34 C
+ATOM 52 C PHE A 8 -7.808 0.440 -35.906 1.00 44.05 C
+ANISOU 52 C PHE A 8 5618 4900 6218 131 331 33 C
+ATOM 53 O PHE A 8 -6.905 1.228 -35.663 1.00 48.85 O
+ANISOU 53 O PHE A 8 6245 5366 6948 88 353 -5 O
+ATOM 54 CB PHE A 8 -6.843 -1.646 -35.018 1.00 45.89 C
+ANISOU 54 CB PHE A 8 5927 5267 6239 10 184 -93 C
+ATOM 55 CG PHE A 8 -6.679 -3.122 -35.144 1.00 46.40 C
+ANISOU 55 CG PHE A 8 6019 5437 6174 -10 148 -85 C
+ATOM 56 CD1 PHE A 8 -7.769 -3.967 -35.038 1.00 48.26 C
+ANISOU 56 CD1 PHE A 8 6277 5749 6311 -14 173 -106 C
+ATOM 57 CD2 PHE A 8 -5.438 -3.668 -35.354 1.00 44.91 C
+ANISOU 57 CD2 PHE A 8 5828 5253 5981 -27 113 -54 C
+ATOM 58 CE1 PHE A 8 -7.601 -5.339 -35.131 1.00 47.89 C
+ANISOU 58 CE1 PHE A 8 6276 5748 6170 -46 182 -111 C
+ATOM 59 CE2 PHE A 8 -5.279 -5.027 -35.445 1.00 45.32 C
+ANISOU 59 CE2 PHE A 8 5923 5360 5935 -28 125 -39 C
+ATOM 60 CZ PHE A 8 -6.356 -5.857 -35.342 1.00 47.01 C
+ANISOU 60 CZ PHE A 8 6184 5615 6059 -43 168 -74 C
+ATOM 61 N ILE A 9 -9.069 0.763 -35.795 1.00 45.19 N
+ANISOU 61 N ILE A 9 5739 5067 6363 208 395 63 N
+ATOM 62 CA ILE A 9 -9.459 2.100 -35.309 1.00 51.68 C
+ANISOU 62 CA ILE A 9 6584 5712 7339 270 525 51 C
+ATOM 63 C ILE A 9 -9.826 1.880 -33.879 1.00 50.92 C
+ANISOU 63 C ILE A 9 6580 5587 7179 217 529 -126 C
+ATOM 64 O ILE A 9 -10.824 1.229 -33.599 1.00 53.51 O
+ANISOU 64 O ILE A 9 6889 6036 7407 248 527 -124 O
+ATOM 65 CB ILE A 9 -10.635 2.697 -36.124 1.00 55.53 C
+ANISOU 65 CB ILE A 9 6967 6250 7879 433 624 240 C
+ATOM 66 CG1 ILE A 9 -10.204 2.918 -37.592 1.00 55.29 C
+ANISOU 66 CG1 ILE A 9 6852 6282 7873 497 619 438 C
+ATOM 67 CG2 ILE A 9 -11.137 4.018 -35.502 1.00 55.96 C
+ANISOU 67 CG2 ILE A 9 7065 6086 8109 523 808 232 C
+ATOM 68 CD1 ILE A 9 -11.385 2.981 -38.527 1.00 58.25 C
+ANISOU 68 CD1 ILE A 9 7085 6859 8188 645 639 641 C
+ATOM 69 N THR A 10 -8.967 2.329 -32.980 1.00 50.67 N
+ANISOU 69 N THR A 10 6641 5425 7186 121 526 -284 N
+ATOM 70 CA THR A 10 -9.185 2.107 -31.561 1.00 51.69 C
+ANISOU 70 CA THR A 10 6873 5558 7208 65 520 -464 C
+ATOM 71 C THR A 10 -9.612 3.432 -30.915 1.00 50.65 C
+ANISOU 71 C THR A 10 6822 5218 7204 89 689 -568 C
+ATOM 72 O THR A 10 -9.544 4.466 -31.525 1.00 57.26 O
+ANISOU 72 O THR A 10 7639 5887 8228 134 806 -501 O
+ATOM 73 CB THR A 10 -7.930 1.531 -30.864 1.00 50.80 C
+ANISOU 73 CB THR A 10 6804 5512 6986 -68 378 -588 C
+ATOM 74 OG1 THR A 10 -6.968 2.554 -30.671 1.00 53.43 O
+ANISOU 74 OG1 THR A 10 7157 5704 7440 -168 390 -696 O
+ATOM 75 CG2 THR A 10 -7.278 0.462 -31.693 1.00 50.38 C
+ANISOU 75 CG2 THR A 10 6674 5593 6874 -73 264 -466 C
+ATOM 76 N PRO A 11 -10.106 3.393 -29.679 1.00 56.03 N
+ANISOU 76 N PRO A 11 7607 5897 7785 72 733 -722 N
+ATOM 77 CA PRO A 11 -10.427 4.652 -28.979 1.00 58.93 C
+ANISOU 77 CA PRO A 11 8085 6039 8264 79 922 -863 C
+ATOM 78 C PRO A 11 -9.259 5.590 -28.772 1.00 63.22 C
+ANISOU 78 C PRO A 11 8697 6403 8918 -73 935 -1031 C
+ATOM 79 O PRO A 11 -9.508 6.756 -28.521 1.00 69.60 O
+ANISOU 79 O PRO A 11 9594 6966 9884 -65 1137 -1123 O
+ATOM 80 CB PRO A 11 -10.886 4.178 -27.593 1.00 59.38 C
+ANISOU 80 CB PRO A 11 8256 6185 8120 51 924 -1030 C
+ATOM 81 CG PRO A 11 -11.306 2.750 -27.777 1.00 55.35 C
+ANISOU 81 CG PRO A 11 7663 5915 7451 96 802 -896 C
+ATOM 82 CD PRO A 11 -10.443 2.207 -28.868 1.00 52.67 C
+ANISOU 82 CD PRO A 11 7215 5657 7140 56 649 -769 C
+ATOM 83 N GLU A 12 -8.030 5.041 -28.776 1.00 70.08 N
+ANISOU 83 N GLU A 12 9526 7398 9704 -217 738 -1080 N
+ATOM 84 CA GLU A 12 -6.732 5.771 -28.699 1.00 69.59 C
+ANISOU 84 CA GLU A 12 9470 7225 9747 -402 705 -1227 C
+ATOM 85 C GLU A 12 -6.252 6.249 -30.096 1.00 71.32 C
+ANISOU 85 C GLU A 12 9578 7319 10199 -369 757 -1033 C
+ATOM 86 O GLU A 12 -5.575 7.279 -30.200 1.00 82.47 O
+ANISOU 86 O GLU A 12 11009 8520 11805 -484 854 -1123 O
+ATOM 87 CB GLU A 12 -5.618 4.877 -28.105 1.00 80.51 C
+ANISOU 87 CB GLU A 12 10809 8855 10925 -546 460 -1320 C
+ATOM 88 CG GLU A 12 -5.569 4.624 -26.578 1.00 89.15 C
+ANISOU 88 CG GLU A 12 12010 10093 11769 -643 381 -1555 C
+ATOM 89 CD GLU A 12 -4.271 3.871 -26.137 1.00 96.47 C
+ANISOU 89 CD GLU A 12 12846 11289 12519 -771 133 -1597 C
+ATOM 90 OE1 GLU A 12 -3.440 4.458 -25.401 1.00 86.42 O
+ANISOU 90 OE1 GLU A 12 11584 10049 11202 -968 64 -1827 O
+ATOM 91 OE2 GLU A 12 -4.044 2.692 -26.542 1.00 87.89 O
+ANISOU 91 OE2 GLU A 12 11665 10388 11340 -678 12 -1398 O
+ATOM 92 N GLY A 13 -6.566 5.500 -31.160 1.00 63.49 N
+ANISOU 92 N GLY A 13 8479 6460 9184 -227 703 -780 N
+ATOM 93 CA GLY A 13 -6.219 5.913 -32.504 1.00 59.26 C
+ANISOU 93 CA GLY A 13 7850 5841 8826 -167 764 -575 C
+ATOM 94 C GLY A 13 -6.111 4.770 -33.479 1.00 56.21 C
+ANISOU 94 C GLY A 13 7353 5681 8322 -92 628 -378 C
+ATOM 95 O GLY A 13 -6.534 3.652 -33.197 1.00 53.58 O
+ANISOU 95 O GLY A 13 7018 5544 7795 -65 517 -379 O
+ATOM 96 N GLU A 14 -5.519 5.057 -34.631 1.00 54.33 N
+ANISOU 96 N GLU A 14 7036 5399 8206 -65 661 -215 N
+ATOM 97 CA GLU A 14 -5.492 4.115 -35.751 1.00 60.06 C
+ANISOU 97 CA GLU A 14 7674 6319 8826 19 577 -23 C
+ATOM 98 C GLU A 14 -4.126 3.540 -35.940 1.00 51.22 C
+ANISOU 98 C GLU A 14 6504 5271 7684 -88 464 -38 C
+ATOM 99 O GLU A 14 -3.198 4.277 -36.050 1.00 52.79 O
+ANISOU 99 O GLU A 14 6674 5338 8045 -172 512 -55 O
+ATOM 100 CB GLU A 14 -5.953 4.814 -37.053 1.00 67.15 C
+ANISOU 100 CB GLU A 14 8513 7162 9837 174 715 218 C
+ATOM 101 CG GLU A 14 -7.367 5.360 -36.842 1.00 82.24 C
+ANISOU 101 CG GLU A 14 10442 9031 11772 314 834 268 C
+ATOM 102 CD GLU A 14 -7.938 6.250 -37.944 1.00 92.51 C
+ANISOU 102 CD GLU A 14 11677 10275 13196 506 998 534 C
+ATOM 103 OE1 GLU A 14 -7.274 6.424 -38.992 1.00104.38 O
+ANISOU 103 OE1 GLU A 14 13129 11783 14748 536 1022 696 O
+ATOM 104 OE2 GLU A 14 -9.080 6.772 -37.742 1.00 86.19 O
+ANISOU 104 OE2 GLU A 14 10870 9437 12438 645 1116 601 O
+ATOM 105 N LEU A 15 -4.066 2.220 -36.076 1.00 51.18 N
+ANISOU 105 N LEU A 15 6481 5467 7497 -72 343 -11 N
+ATOM 106 CA LEU A 15 -2.856 1.402 -36.095 1.00 54.47 C
+ANISOU 106 CA LEU A 15 6850 5982 7861 -141 239 -15 C
+ATOM 107 C LEU A 15 -3.099 0.276 -37.078 1.00 53.30 C
+ANISOU 107 C LEU A 15 6690 5980 7581 -52 221 115 C
+ATOM 108 O LEU A 15 -4.183 -0.290 -37.098 1.00 48.80 O
+ANISOU 108 O LEU A 15 6160 5493 6889 1 217 115 O
+ATOM 109 CB LEU A 15 -2.708 0.632 -34.773 1.00 53.82 C
+ANISOU 109 CB LEU A 15 6808 6004 7634 -208 122 -164 C
+ATOM 110 CG LEU A 15 -2.570 1.415 -33.509 1.00 64.22 C
+ANISOU 110 CG LEU A 15 8165 7251 8981 -319 102 -355 C
+ATOM 111 CD1 LEU A 15 -2.755 0.471 -32.348 1.00 68.91 C
+ANISOU 111 CD1 LEU A 15 8813 8000 9367 -328 0 -448 C
+ATOM 112 CD2 LEU A 15 -1.203 2.057 -33.474 1.00 66.88 C
+ANISOU 112 CD2 LEU A 15 8412 7542 9455 -454 71 -403 C
+ATOM 113 N GLU A 16 -2.062 -0.144 -37.776 1.00 49.83 N
+ANISOU 113 N GLU A 16 6195 5579 7157 -55 214 200 N
+ATOM 114 CA GLU A 16 -2.191 -1.180 -38.784 1.00 52.00 C
+ANISOU 114 CA GLU A 16 6480 5971 7306 14 227 299 C
+ATOM 115 C GLU A 16 -1.165 -2.260 -38.528 1.00 44.99 C
+ANISOU 115 C GLU A 16 5581 5146 6365 -5 183 291 C
+ATOM 116 O GLU A 16 -0.027 -1.953 -38.247 1.00 41.15 O
+ANISOU 116 O GLU A 16 5017 4632 5983 -49 162 300 O
+ATOM 117 CB GLU A 16 -1.924 -0.519 -40.111 1.00 56.47 C
+ANISOU 117 CB GLU A 16 6996 6506 7952 73 320 454 C
+ATOM 118 CG GLU A 16 -2.598 -1.111 -41.299 1.00 64.79 C
+ANISOU 118 CG GLU A 16 8072 7693 8851 152 352 546 C
+ATOM 119 CD GLU A 16 -2.299 -0.276 -42.542 1.00 77.28 C
+ANISOU 119 CD GLU A 16 9604 9258 10500 229 453 725 C
+ATOM 120 OE1 GLU A 16 -1.932 -0.864 -43.609 1.00 78.06 O
+ANISOU 120 OE1 GLU A 16 9708 9456 10491 269 492 807 O
+ATOM 121 OE2 GLU A 16 -2.392 0.977 -42.427 1.00 67.17 O
+ANISOU 121 OE2 GLU A 16 8290 7846 9385 251 517 784 O
+ATOM 122 N VAL A 17 -1.538 -3.520 -38.672 1.00 44.95 N
+ANISOU 122 N VAL A 17 5642 5223 6212 27 187 284 N
+ATOM 123 CA VAL A 17 -0.578 -4.609 -38.466 1.00 43.94 C
+ANISOU 123 CA VAL A 17 5513 5132 6048 46 189 310 C
+ATOM 124 C VAL A 17 -0.754 -5.509 -39.643 1.00 44.55 C
+ANISOU 124 C VAL A 17 5652 5239 6033 92 285 360 C
+ATOM 125 O VAL A 17 -1.732 -5.387 -40.374 1.00 43.66 O
+ANISOU 125 O VAL A 17 5577 5162 5847 87 308 346 O
+ATOM 126 CB VAL A 17 -0.860 -5.372 -37.157 1.00 48.00 C
+ANISOU 126 CB VAL A 17 6081 5682 6472 37 134 232 C
+ATOM 127 CG1 VAL A 17 -0.799 -4.395 -35.985 1.00 48.79 C
+ANISOU 127 CG1 VAL A 17 6138 5776 6622 -25 37 146 C
+ATOM 128 CG2 VAL A 17 -2.229 -6.014 -37.217 1.00 46.07 C
+ANISOU 128 CG2 VAL A 17 5942 5449 6111 34 172 170 C
+ATOM 129 N GLU A 18 0.203 -6.379 -39.858 1.00 39.17 N
+ANISOU 129 N GLU A 18 4974 4558 5351 139 347 420 N
+ATOM 130 CA GLU A 18 0.027 -7.446 -40.834 1.00 45.65 C
+ANISOU 130 CA GLU A 18 5895 5385 6065 169 468 423 C
+ATOM 131 C GLU A 18 -0.549 -8.660 -40.120 1.00 42.91 C
+ANISOU 131 C GLU A 18 5658 5017 5628 157 500 342 C
+ATOM 132 O GLU A 18 -0.225 -8.908 -38.983 1.00 50.61 O
+ANISOU 132 O GLU A 18 6614 5981 6632 182 459 356 O
+ATOM 133 CB GLU A 18 1.373 -7.869 -41.404 1.00 49.05 C
+ANISOU 133 CB GLU A 18 6290 5791 6555 246 574 536 C
+ATOM 134 CG GLU A 18 1.849 -7.008 -42.535 1.00 63.96 C
+ANISOU 134 CG GLU A 18 8110 7691 8497 264 618 626 C
+ATOM 135 CD GLU A 18 3.316 -7.261 -42.867 1.00 75.06 C
+ANISOU 135 CD GLU A 18 9436 9075 10006 344 719 757 C
+ATOM 136 OE1 GLU A 18 3.833 -8.337 -42.508 1.00 68.87 O
+ANISOU 136 OE1 GLU A 18 8682 8270 9214 408 790 779 O
+ATOM 137 OE2 GLU A 18 3.953 -6.347 -43.437 1.00 86.26 O
+ANISOU 137 OE2 GLU A 18 10749 10492 11532 351 741 855 O
+ATOM 138 N CYS A 19 -1.403 -9.397 -40.824 1.00 42.18 N
+ANISOU 138 N CYS A 19 5675 4930 5420 110 580 258 N
+ATOM 139 CA CYS A 19 -2.100 -10.522 -40.319 1.00 42.40 C
+ANISOU 139 CA CYS A 19 5816 4913 5379 67 646 167 C
+ATOM 140 C CYS A 19 -2.196 -11.521 -41.439 1.00 43.87 C
+ANISOU 140 C CYS A 19 6123 5068 5477 29 804 99 C
+ATOM 141 O CYS A 19 -2.743 -11.212 -42.516 1.00 43.45 O
+ANISOU 141 O CYS A 19 6070 5112 5326 -37 790 39 O
+ATOM 142 CB CYS A 19 -3.524 -10.140 -39.826 1.00 45.74 C
+ANISOU 142 CB CYS A 19 6229 5397 5751 -23 551 67 C
+ATOM 143 SG CYS A 19 -4.342 -11.539 -39.028 1.00 48.02 S
+ANISOU 143 SG CYS A 19 6646 5607 5990 -86 658 -31 S
+ATOM 144 N ASP A 20 -1.642 -12.721 -41.204 1.00 45.23 N
+ANISOU 144 N ASP A 20 6401 5109 5674 79 970 112 N
+ATOM 145 CA ASP A 20 -1.719 -13.795 -42.164 1.00 47.07 C
+ANISOU 145 CA ASP A 20 6786 5262 5833 28 1168 13 C
+ATOM 146 C ASP A 20 -3.181 -14.220 -42.331 1.00 49.54 C
+ANISOU 146 C ASP A 20 7175 5613 6035 -157 1166 -185 C
+ATOM 147 O ASP A 20 -4.027 -14.046 -41.400 1.00 46.05 O
+ANISOU 147 O ASP A 20 6690 5197 5609 -209 1069 -212 O
+ATOM 148 CB ASP A 20 -0.895 -14.979 -41.694 1.00 49.71 C
+ANISOU 148 CB ASP A 20 7224 5411 6252 141 1380 87 C
+ATOM 149 CG ASP A 20 0.620 -14.723 -41.766 1.00 64.33 C
+ANISOU 149 CG ASP A 20 8980 7254 8207 325 1414 288 C
+ATOM 150 OD1 ASP A 20 1.122 -14.017 -42.690 1.00 70.08 O
+ANISOU 150 OD1 ASP A 20 9639 8062 8926 341 1382 324 O
+ATOM 151 OD2 ASP A 20 1.349 -15.271 -40.906 1.00 70.59 O
+ANISOU 151 OD2 ASP A 20 9755 7971 9092 465 1489 432 O
+ATOM 152 N ASP A 21 -3.481 -14.806 -43.487 1.00 48.95 N
+ANISOU 152 N ASP A 21 7206 5550 5840 -269 1280 -332 N
+ATOM 153 CA ASP A 21 -4.886 -15.213 -43.792 1.00 52.07 C
+ANISOU 153 CA ASP A 21 7641 6029 6111 -489 1264 -547 C
+ATOM 154 C ASP A 21 -5.466 -16.364 -42.961 1.00 52.45 C
+ANISOU 154 C ASP A 21 7805 5898 6224 -586 1412 -652 C
+ATOM 155 O ASP A 21 -6.664 -16.621 -43.076 1.00 52.58 O
+ANISOU 155 O ASP A 21 7815 5996 6165 -785 1384 -823 O
+ATOM 156 CB ASP A 21 -5.080 -15.591 -45.251 1.00 52.20 C
+ANISOU 156 CB ASP A 21 7744 6142 5948 -620 1342 -716 C
+ATOM 157 CG ASP A 21 -4.192 -16.744 -45.675 1.00 54.79 C
+ANISOU 157 CG ASP A 21 8277 6240 6300 -591 1630 -772 C
+ATOM 158 OD1 ASP A 21 -3.555 -17.399 -44.833 1.00 60.00 O
+ANISOU 158 OD1 ASP A 21 9012 6660 7124 -475 1787 -678 O
+ATOM 159 OD2 ASP A 21 -4.087 -16.978 -46.873 1.00 66.22 O
+ANISOU 159 OD2 ASP A 21 9812 7754 7595 -664 1713 -895 O
+ATOM 160 N ASP A 22 -4.630 -17.059 -42.198 1.00 51.20 N
+ANISOU 160 N ASP A 22 7738 5513 6200 -447 1580 -538 N
+ATOM 161 CA ASP A 22 -5.098 -18.073 -41.256 1.00 62.00 C
+ANISOU 161 CA ASP A 22 9213 6691 7651 -492 1741 -573 C
+ATOM 162 C ASP A 22 -4.625 -17.744 -39.835 1.00 59.08 C
+ANISOU 162 C ASP A 22 8764 6294 7388 -296 1668 -346 C
+ATOM 163 O ASP A 22 -4.377 -18.629 -39.062 1.00 56.04 O
+ANISOU 163 O ASP A 22 8478 5724 7088 -214 1851 -264 O
+ATOM 164 CB ASP A 22 -4.624 -19.475 -41.714 1.00 71.33 C
+ANISOU 164 CB ASP A 22 10621 7602 8879 -509 2084 -652 C
+ATOM 165 CG ASP A 22 -3.093 -19.576 -41.838 1.00 78.00 C
+ANISOU 165 CG ASP A 22 11493 8340 9802 -254 2204 -448 C
+ATOM 166 OD1 ASP A 22 -2.396 -18.536 -41.681 1.00 74.86 O
+ANISOU 166 OD1 ASP A 22 10926 8102 9414 -102 2002 -272 O
+ATOM 167 OD2 ASP A 22 -2.585 -20.697 -42.122 1.00 91.53 O
+ANISOU 167 OD2 ASP A 22 13392 9804 11580 -212 2520 -469 O
+ATOM 168 N VAL A 23 -4.476 -16.441 -39.535 1.00 58.45 N
+ANISOU 168 N VAL A 23 8509 6406 7294 -222 1411 -246 N
+ATOM 169 CA VAL A 23 -4.282 -15.937 -38.191 1.00 51.17 C
+ANISOU 169 CA VAL A 23 7497 5521 6421 -98 1292 -96 C
+ATOM 170 C VAL A 23 -5.446 -15.027 -37.852 1.00 51.90 C
+ANISOU 170 C VAL A 23 7486 5767 6465 -205 1102 -177 C
+ATOM 171 O VAL A 23 -5.900 -14.243 -38.695 1.00 52.44 O
+ANISOU 171 O VAL A 23 7471 5973 6479 -287 979 -252 O
+ATOM 172 CB VAL A 23 -2.914 -15.295 -38.008 1.00 53.75 C
+ANISOU 172 CB VAL A 23 7721 5902 6798 84 1203 86 C
+ATOM 173 CG1 VAL A 23 -2.782 -14.588 -36.643 1.00 51.64 C
+ANISOU 173 CG1 VAL A 23 7345 5733 6542 168 1034 192 C
+ATOM 174 CG2 VAL A 23 -1.872 -16.402 -38.166 1.00 52.89 C
+ANISOU 174 CG2 VAL A 23 7712 5629 6754 219 1438 196 C
+ATOM 175 N TYR A 24 -6.020 -15.271 -36.669 1.00 49.92 N
+ANISOU 175 N TYR A 24 7252 5485 6229 -201 1118 -157 N
+ATOM 176 CA TYR A 24 -7.105 -14.448 -36.120 1.00 49.53 C
+ANISOU 176 CA TYR A 24 7107 5561 6149 -269 973 -210 C
+ATOM 177 C TYR A 24 -6.598 -13.062 -35.859 1.00 47.90 C
+ANISOU 177 C TYR A 24 6775 5477 5946 -174 771 -133 C
+ATOM 178 O TYR A 24 -5.530 -12.835 -35.330 1.00 50.41 O
+ANISOU 178 O TYR A 24 7074 5788 6289 -48 730 -19 O
+ATOM 179 CB TYR A 24 -7.664 -14.995 -34.792 1.00 53.15 C
+ANISOU 179 CB TYR A 24 7622 5953 6617 -252 1058 -177 C
+ATOM 180 CG TYR A 24 -8.368 -16.349 -34.905 1.00 54.34 C
+ANISOU 180 CG TYR A 24 7898 5950 6796 -378 1291 -263 C
+ATOM 181 CD1 TYR A 24 -9.369 -16.572 -35.863 1.00 61.64 C
+ANISOU 181 CD1 TYR A 24 8804 6911 7703 -595 1316 -450 C
+ATOM 182 CD2 TYR A 24 -8.040 -17.385 -34.061 1.00 58.06 C
+ANISOU 182 CD2 TYR A 24 8497 6251 7312 -288 1491 -157 C
+ATOM 183 CE1 TYR A 24 -10.013 -17.808 -35.976 1.00 67.82 C
+ANISOU 183 CE1 TYR A 24 9699 7540 8526 -757 1542 -565 C
+ATOM 184 CE2 TYR A 24 -8.691 -18.634 -34.147 1.00 67.21 C
+ANISOU 184 CE2 TYR A 24 9786 7220 8531 -418 1749 -239 C
+ATOM 185 CZ TYR A 24 -9.672 -18.847 -35.099 1.00 67.30 C
+ANISOU 185 CZ TYR A 24 9783 7246 8539 -670 1777 -462 C
+ATOM 186 OH TYR A 24 -10.304 -20.070 -35.167 1.00 63.80 O
+ANISOU 186 OH TYR A 24 9466 6605 8170 -838 2041 -574 O
+ATOM 187 N VAL A 25 -7.413 -12.132 -36.241 1.00 46.10 N
+ANISOU 187 N VAL A 25 6451 5365 5699 -242 655 -197 N
+ATOM 188 CA VAL A 25 -7.117 -10.720 -36.104 1.00 50.13 C
+ANISOU 188 CA VAL A 25 6853 5957 6237 -176 500 -147 C
+ATOM 189 C VAL A 25 -6.622 -10.284 -34.725 1.00 49.08 C
+ANISOU 189 C VAL A 25 6716 5810 6120 -88 441 -91 C
+ATOM 190 O VAL A 25 -5.602 -9.548 -34.601 1.00 48.80 O
+ANISOU 190 O VAL A 25 6626 5791 6124 -25 355 -35 O
+ATOM 191 CB VAL A 25 -8.407 -10.000 -36.511 1.00 51.95 C
+ANISOU 191 CB VAL A 25 6992 6297 6447 -248 438 -209 C
+ATOM 192 CG1 VAL A 25 -8.482 -8.654 -35.889 1.00 65.37 C
+ANISOU 192 CG1 VAL A 25 8616 8025 8196 -180 340 -173 C
+ATOM 193 CG2 VAL A 25 -8.427 -9.935 -38.033 1.00 52.86 C
+ANISOU 193 CG2 VAL A 25 7066 6496 6519 -296 427 -223 C
+ATOM 194 N LEU A 26 -7.301 -10.753 -33.681 1.00 50.45 N
+ANISOU 194 N LEU A 26 6944 5968 6256 -94 493 -112 N
+ATOM 195 CA LEU A 26 -6.902 -10.450 -32.290 1.00 47.33 C
+ANISOU 195 CA LEU A 26 6562 5597 5822 -14 443 -70 C
+ATOM 196 C LEU A 26 -5.498 -10.894 -32.035 1.00 47.06 C
+ANISOU 196 C LEU A 26 6537 5561 5781 82 436 39 C
+ATOM 197 O LEU A 26 -4.721 -10.194 -31.377 1.00 55.96 O
+ANISOU 197 O LEU A 26 7607 6768 6888 128 318 66 O
+ATOM 198 CB LEU A 26 -7.807 -11.200 -31.306 1.00 53.55 C
+ANISOU 198 CB LEU A 26 7430 6361 6552 -20 551 -79 C
+ATOM 199 CG LEU A 26 -7.510 -11.161 -29.801 1.00 55.13 C
+ANISOU 199 CG LEU A 26 7674 6613 6658 70 531 -26 C
+ATOM 200 CD1 LEU A 26 -7.326 -9.720 -29.325 1.00 55.80 C
+ANISOU 200 CD1 LEU A 26 7695 6785 6722 71 376 -95 C
+ATOM 201 CD2 LEU A 26 -8.666 -11.852 -29.032 1.00 61.83 C
+ANISOU 201 CD2 LEU A 26 8600 7428 7463 52 674 -33 C
+ATOM 202 N ASP A 27 -5.136 -12.069 -32.524 1.00 48.10 N
+ANISOU 202 N ASP A 27 6734 5609 5931 111 571 103 N
+ATOM 203 CA ASP A 27 -3.762 -12.587 -32.305 1.00 48.67 C
+ANISOU 203 CA ASP A 27 6797 5686 6010 241 594 251 C
+ATOM 204 C ASP A 27 -2.701 -11.814 -33.061 1.00 52.00 C
+ANISOU 204 C ASP A 27 7102 6157 6495 255 488 280 C
+ATOM 205 O ASP A 27 -1.619 -11.648 -32.546 1.00 53.84 O
+ANISOU 205 O ASP A 27 7252 6477 6725 342 414 382 O
+ATOM 206 CB ASP A 27 -3.670 -14.036 -32.649 1.00 52.61 C
+ANISOU 206 CB ASP A 27 7412 6040 6537 286 816 319 C
+ATOM 207 CG ASP A 27 -4.541 -14.887 -31.735 1.00 63.74 C
+ANISOU 207 CG ASP A 27 8934 7380 7902 289 954 332 C
+ATOM 208 OD1 ASP A 27 -4.580 -14.630 -30.517 1.00 77.44 O
+ANISOU 208 OD1 ASP A 27 10653 9216 9555 357 885 392 O
+ATOM 209 OD2 ASP A 27 -5.228 -15.780 -32.232 1.00 66.17 O
+ANISOU 209 OD2 ASP A 27 9347 7539 8253 206 1139 268 O
+ATOM 210 N ALA A 28 -3.001 -11.313 -34.254 1.00 45.81 N
+ANISOU 210 N ALA A 28 6297 5346 5763 172 479 200 N
+ATOM 211 CA ALA A 28 -2.052 -10.414 -34.921 1.00 45.27 C
+ANISOU 211 CA ALA A 28 6113 5321 5765 182 389 237 C
+ATOM 212 C ALA A 28 -1.874 -9.098 -34.113 1.00 46.76 C
+ANISOU 212 C ALA A 28 6200 5596 5968 152 219 201 C
+ATOM 213 O ALA A 28 -0.782 -8.604 -33.981 1.00 48.55 O
+ANISOU 213 O ALA A 28 6321 5880 6246 174 142 256 O
+ATOM 214 CB ALA A 28 -2.542 -10.096 -36.327 1.00 48.41 C
+ANISOU 214 CB ALA A 28 6517 5691 6185 111 423 175 C
+ATOM 215 N ALA A 29 -2.956 -8.547 -33.566 1.00 46.59 N
+ANISOU 215 N ALA A 29 6211 5582 5908 92 177 97 N
+ATOM 216 CA ALA A 29 -2.882 -7.367 -32.726 1.00 45.37 C
+ANISOU 216 CA ALA A 29 6001 5476 5760 54 58 28 C
+ATOM 217 C ALA A 29 -2.026 -7.590 -31.506 1.00 45.22 C
+ANISOU 217 C ALA A 29 5953 5566 5662 94 -18 63 C
+ATOM 218 O ALA A 29 -1.157 -6.760 -31.212 1.00 50.70 O
+ANISOU 218 O ALA A 29 6546 6327 6390 54 -129 39 O
+ATOM 219 CB ALA A 29 -4.268 -6.959 -32.299 1.00 45.68 C
+ANISOU 219 CB ALA A 29 6100 5492 5763 13 76 -74 C
+ATOM 220 N GLU A 30 -2.244 -8.704 -30.827 1.00 46.60 N
+ANISOU 220 N GLU A 30 6205 5769 5730 169 45 128 N
+ATOM 221 CA GLU A 30 -1.476 -9.042 -29.636 1.00 54.76 C
+ANISOU 221 CA GLU A 30 7206 6952 6646 243 -23 204 C
+ATOM 222 C GLU A 30 -0.050 -9.331 -29.955 1.00 54.21 C
+ANISOU 222 C GLU A 30 7010 6960 6626 313 -60 346 C
+ATOM 223 O GLU A 30 0.832 -8.823 -29.288 1.00 59.88 O
+ANISOU 223 O GLU A 30 7604 7849 7298 302 -205 354 O
+ATOM 224 CB GLU A 30 -2.122 -10.183 -28.852 1.00 62.74 C
+ANISOU 224 CB GLU A 30 8340 7960 7538 332 92 277 C
+ATOM 225 CG GLU A 30 -3.470 -9.711 -28.236 1.00 72.73 C
+ANISOU 225 CG GLU A 30 9697 9198 8739 260 106 134 C
+ATOM 226 CD GLU A 30 -4.256 -10.812 -27.471 1.00 84.77 C
+ANISOU 226 CD GLU A 30 11347 10699 10163 332 254 206 C
+ATOM 227 OE1 GLU A 30 -4.358 -12.001 -27.950 1.00 80.99 O
+ANISOU 227 OE1 GLU A 30 10932 10104 9737 384 419 311 O
+ATOM 228 OE2 GLU A 30 -4.785 -10.463 -26.379 1.00 83.98 O
+ANISOU 228 OE2 GLU A 30 11293 10681 9934 331 227 148 O
+ATOM 229 N GLU A 31 0.205 -10.073 -31.022 1.00 59.74 N
+ANISOU 229 N GLU A 31 7727 7548 7422 373 72 443 N
+ATOM 230 CA GLU A 31 1.574 -10.229 -31.535 1.00 56.65 C
+ANISOU 230 CA GLU A 31 7199 7210 7113 445 65 582 C
+ATOM 231 C GLU A 31 2.251 -8.862 -31.829 1.00 60.42 C
+ANISOU 231 C GLU A 31 7517 7754 7685 328 -85 505 C
+ATOM 232 O GLU A 31 3.462 -8.797 -31.776 1.00 66.23 O
+ANISOU 232 O GLU A 31 8087 8613 8463 365 -148 610 O
+ATOM 233 CB GLU A 31 1.536 -11.120 -32.771 1.00 64.23 C
+ANISOU 233 CB GLU A 31 8243 7999 8160 503 266 648 C
+ATOM 234 CG GLU A 31 2.861 -11.443 -33.471 1.00 83.36 C
+ANISOU 234 CG GLU A 31 10552 10436 10682 606 328 807 C
+ATOM 235 CD GLU A 31 3.790 -12.366 -32.669 1.00102.53 C
+ANISOU 235 CD GLU A 31 12908 12976 13073 795 367 1027 C
+ATOM 236 OE1 GLU A 31 3.385 -12.888 -31.594 1.00113.60 O
+ANISOU 236 OE1 GLU A 31 14374 14434 14355 859 366 1071 O
+ATOM 237 OE2 GLU A 31 4.946 -12.569 -33.121 1.00102.50 O
+ANISOU 237 OE2 GLU A 31 12770 13016 13158 898 412 1182 O
+ATOM 238 N ALA A 32 1.502 -7.778 -32.127 1.00 57.02 N
+ANISOU 238 N ALA A 32 7120 7240 7301 193 -126 339 N
+ATOM 239 CA ALA A 32 2.120 -6.424 -32.410 1.00 59.13 C
+ANISOU 239 CA ALA A 32 7255 7519 7692 72 -224 265 C
+ATOM 240 C ALA A 32 2.224 -5.516 -31.195 1.00 56.89 C
+ANISOU 240 C ALA A 32 6920 7349 7346 -41 -378 124 C
+ATOM 241 O ALA A 32 2.754 -4.418 -31.279 1.00 65.02 O
+ANISOU 241 O ALA A 32 7847 8373 8484 -167 -445 38 O
+ATOM 242 CB ALA A 32 1.377 -5.676 -33.506 1.00 53.40 C
+ANISOU 242 CB ALA A 32 6588 6626 7076 11 -149 198 C
+ATOM 243 N GLY A 33 1.719 -5.987 -30.077 1.00 55.56 N
+ANISOU 243 N GLY A 33 6832 7274 7000 -3 -414 93 N
+ATOM 244 CA GLY A 33 1.778 -5.257 -28.849 1.00 58.15 C
+ANISOU 244 CA GLY A 33 7139 7738 7215 -106 -550 -56 C
+ATOM 245 C GLY A 33 0.546 -4.451 -28.568 1.00 60.01 C
+ANISOU 245 C GLY A 33 7520 7837 7440 -190 -508 -246 C
+ATOM 246 O GLY A 33 0.620 -3.573 -27.741 1.00 69.82 O
+ANISOU 246 O GLY A 33 8758 9139 8629 -310 -593 -418 O
+ATOM 247 N ILE A 34 -0.586 -4.759 -29.224 1.00 61.19 N
+ANISOU 247 N ILE A 34 7792 7820 7635 -130 -370 -221 N
+ATOM 248 CA ILE A 34 -1.840 -4.017 -29.038 1.00 58.99 C
+ANISOU 248 CA ILE A 34 7627 7418 7368 -177 -306 -363 C
+ATOM 249 C ILE A 34 -2.765 -4.786 -28.094 1.00 62.15 C
+ANISOU 249 C ILE A 34 8149 7876 7589 -107 -261 -367 C
+ATOM 250 O ILE A 34 -3.056 -5.947 -28.343 1.00 63.50 O
+ANISOU 250 O ILE A 34 8359 8045 7721 -13 -186 -239 O
+ATOM 251 CB ILE A 34 -2.577 -3.788 -30.390 1.00 61.05 C
+ANISOU 251 CB ILE A 34 7905 7506 7785 -156 -191 -318 C
+ATOM 252 CG1 ILE A 34 -1.701 -2.983 -31.385 1.00 65.68 C
+ANISOU 252 CG1 ILE A 34 8381 8020 8552 -209 -201 -287 C
+ATOM 253 CG2 ILE A 34 -3.890 -3.029 -30.184 1.00 63.01 C
+ANISOU 253 CG2 ILE A 34 8237 7650 8053 -172 -114 -425 C
+ATOM 254 CD1 ILE A 34 -2.244 -3.016 -32.822 1.00 63.49 C
+ANISOU 254 CD1 ILE A 34 8108 7640 8375 -155 -98 -187 C
+ATOM 255 N ASP A 35 -3.244 -4.141 -27.030 1.00 63.70 N
+ANISOU 255 N ASP A 35 8416 8102 7682 -158 -279 -520 N
+ATOM 256 CA ASP A 35 -4.088 -4.826 -26.025 1.00 71.88 C
+ANISOU 256 CA ASP A 35 9569 9207 8534 -87 -222 -516 C
+ATOM 257 C ASP A 35 -5.567 -4.529 -26.307 1.00 64.56 C
+ANISOU 257 C ASP A 35 8725 8121 7682 -77 -78 -569 C
+ATOM 258 O ASP A 35 -6.130 -3.476 -25.980 1.00 66.69 O
+ANISOU 258 O ASP A 35 9040 8315 7983 -127 -40 -715 O
+ATOM 259 CB ASP A 35 -3.667 -4.503 -24.557 1.00 81.85 C
+ANISOU 259 CB ASP A 35 10862 10660 9575 -127 -325 -633 C
+ATOM 260 CG ASP A 35 -2.375 -5.278 -24.107 1.00 93.06 C
+ANISOU 260 CG ASP A 35 12178 12327 10851 -75 -463 -497 C
+ATOM 261 OD1 ASP A 35 -2.081 -6.430 -24.567 1.00 87.57 O
+ANISOU 261 OD1 ASP A 35 11448 11645 10179 50 -418 -279 O
+ATOM 262 OD2 ASP A 35 -1.644 -4.712 -23.270 1.00100.07 O
+ANISOU 262 OD2 ASP A 35 13013 13406 11600 -161 -608 -613 O
+ATOM 263 N LEU A 36 -6.157 -5.471 -27.010 1.00 61.66 N
+ANISOU 263 N LEU A 36 8363 7702 7362 -15 12 -444 N
+ATOM 264 CA LEU A 36 -7.533 -5.410 -27.353 1.00 56.54 C
+ANISOU 264 CA LEU A 36 7746 6959 6776 -6 133 -460 C
+ATOM 265 C LEU A 36 -8.274 -6.365 -26.418 1.00 58.83 C
+ANISOU 265 C LEU A 36 8125 7301 6925 45 227 -424 C
+ATOM 266 O LEU A 36 -7.725 -7.349 -25.938 1.00 59.91 O
+ANISOU 266 O LEU A 36 8295 7514 6951 96 222 -330 O
+ATOM 267 CB LEU A 36 -7.736 -5.829 -28.796 1.00 54.45 C
+ANISOU 267 CB LEU A 36 7414 6631 6642 -9 169 -370 C
+ATOM 268 CG LEU A 36 -7.150 -4.979 -29.924 1.00 47.43 C
+ANISOU 268 CG LEU A 36 6437 5685 5896 -39 115 -362 C
+ATOM 269 CD1 LEU A 36 -7.661 -5.559 -31.235 1.00 51.84 C
+ANISOU 269 CD1 LEU A 36 6953 6228 6515 -36 168 -282 C
+ATOM 270 CD2 LEU A 36 -7.550 -3.538 -29.754 1.00 48.45 C
+ANISOU 270 CD2 LEU A 36 6559 5739 6109 -60 130 -458 C
+ATOM 271 N PRO A 37 -9.531 -6.066 -26.158 1.00 52.73 N
+ANISOU 271 N PRO A 37 7383 6483 6166 48 333 -477 N
+ATOM 272 CA PRO A 37 -10.189 -6.803 -25.130 1.00 48.70 C
+ANISOU 272 CA PRO A 37 6960 6021 5521 94 437 -451 C
+ATOM 273 C PRO A 37 -10.579 -8.210 -25.630 1.00 53.45 C
+ANISOU 273 C PRO A 37 7558 6591 6158 100 538 -324 C
+ATOM 274 O PRO A 37 -10.785 -8.477 -26.837 1.00 49.32 O
+ANISOU 274 O PRO A 37 6961 6008 5767 49 548 -299 O
+ATOM 275 CB PRO A 37 -11.382 -5.907 -24.791 1.00 51.49 C
+ANISOU 275 CB PRO A 37 7326 6326 5910 95 535 -549 C
+ATOM 276 CG PRO A 37 -11.712 -5.243 -26.095 1.00 57.15 C
+ANISOU 276 CG PRO A 37 7927 6960 6825 64 521 -547 C
+ATOM 277 CD PRO A 37 -10.372 -5.018 -26.760 1.00 53.71 C
+ANISOU 277 CD PRO A 37 7454 6520 6432 30 379 -538 C
+ATOM 278 N TYR A 38 -10.593 -9.140 -24.698 1.00 52.25 N
+ANISOU 278 N TYR A 38 7494 6481 5875 159 621 -244 N
+ATOM 279 CA TYR A 38 -11.096 -10.464 -24.975 1.00 58.41 C
+ANISOU 279 CA TYR A 38 8299 7189 6702 152 774 -141 C
+ATOM 280 C TYR A 38 -11.545 -11.071 -23.664 1.00 53.69 C
+ANISOU 280 C TYR A 38 7809 6629 5962 227 913 -70 C
+ATOM 281 O TYR A 38 -11.164 -10.607 -22.581 1.00 52.44 O
+ANISOU 281 O TYR A 38 7709 6589 5625 301 856 -82 O
+ATOM 282 CB TYR A 38 -9.996 -11.359 -25.594 1.00 54.60 C
+ANISOU 282 CB TYR A 38 7821 6673 6252 178 755 -32 C
+ATOM 283 CG TYR A 38 -8.783 -11.536 -24.706 1.00 57.28 C
+ANISOU 283 CG TYR A 38 8199 7128 6435 299 678 70 C
+ATOM 284 CD1 TYR A 38 -7.743 -10.603 -24.717 1.00 57.17 C
+ANISOU 284 CD1 TYR A 38 8115 7222 6383 300 480 19 C
+ATOM 285 CD2 TYR A 38 -8.679 -12.620 -23.830 1.00 58.87 C
+ANISOU 285 CD2 TYR A 38 8492 7349 6525 412 809 232 C
+ATOM 286 CE1 TYR A 38 -6.629 -10.752 -23.885 1.00 58.64 C
+ANISOU 286 CE1 TYR A 38 8295 7574 6409 396 383 113 C
+ATOM 287 CE2 TYR A 38 -7.565 -12.768 -22.985 1.00 62.26 C
+ANISOU 287 CE2 TYR A 38 8928 7946 6781 545 722 358 C
+ATOM 288 CZ TYR A 38 -6.548 -11.837 -23.032 1.00 65.34 C
+ANISOU 288 CZ TYR A 38 9221 8482 7122 529 494 291 C
+ATOM 289 OH TYR A 38 -5.464 -11.963 -22.208 1.00 72.76 O
+ANISOU 289 OH TYR A 38 10126 9640 7877 642 383 410 O
+ATOM 290 N SER A 39 -12.264 -12.176 -23.765 1.00 51.04 N
+ANISOU 290 N SER A 39 7503 6198 5691 202 1102 6 N
+ATOM 291 CA SER A 39 -12.527 -12.977 -22.556 1.00 52.70 C
+ANISOU 291 CA SER A 39 7828 6422 5770 296 1272 129 C
+ATOM 292 C SER A 39 -12.586 -14.475 -22.933 1.00 54.61 C
+ANISOU 292 C SER A 39 8121 6509 6118 281 1473 260 C
+ATOM 293 O SER A 39 -11.697 -15.196 -22.537 1.00 53.05 O
+ANISOU 293 O SER A 39 8000 6314 5842 404 1512 419 O
+ATOM 294 CB SER A 39 -13.752 -12.480 -21.786 1.00 50.63 C
+ANISOU 294 CB SER A 39 7578 6193 5466 287 1376 64 C
+ATOM 295 OG SER A 39 -14.134 -13.447 -20.804 1.00 57.92 O
+ANISOU 295 OG SER A 39 8608 7099 6297 364 1590 207 O
+ATOM 296 N CYS A 40 -13.549 -14.932 -23.748 1.00 56.78 N
+ANISOU 296 N CYS A 40 8345 6653 6573 127 1599 192 N
+ATOM 297 CA CYS A 40 -13.634 -16.380 -24.053 1.00 57.29 C
+ANISOU 297 CA CYS A 40 8484 6532 6749 80 1830 281 C
+ATOM 298 C CYS A 40 -12.645 -16.882 -25.075 1.00 62.77 C
+ANISOU 298 C CYS A 40 9192 7133 7523 67 1795 293 C
+ATOM 299 O CYS A 40 -12.278 -18.037 -25.022 1.00 51.88 O
+ANISOU 299 O CYS A 40 7920 5599 6191 114 1993 416 O
+ATOM 300 CB CYS A 40 -15.040 -16.831 -24.469 1.00 62.61 C
+ANISOU 300 CB CYS A 40 9100 7107 7580 -117 2004 185 C
+ATOM 301 SG CYS A 40 -15.521 -16.463 -26.163 1.00 58.56 S
+ANISOU 301 SG CYS A 40 8420 6610 7220 -350 1871 -25 S
+ATOM 302 N ARG A 41 -12.233 -16.028 -26.016 1.00 58.00 N
+ANISOU 302 N ARG A 41 8486 6605 6943 14 1575 175 N
+ATOM 303 CA ARG A 41 -11.317 -16.429 -27.087 1.00 58.21 C
+ANISOU 303 CA ARG A 41 8521 6552 7044 -1 1548 175 C
+ATOM 304 C ARG A 41 -11.821 -17.585 -27.916 1.00 57.79 C
+ANISOU 304 C ARG A 41 8520 6302 7133 -157 1766 115 C
+ATOM 305 O ARG A 41 -10.986 -18.264 -28.554 1.00 62.26 O
+ANISOU 305 O ARG A 41 9155 6747 7753 -132 1841 152 O
+ATOM 306 CB ARG A 41 -9.896 -16.763 -26.569 1.00 63.76 C
+ANISOU 306 CB ARG A 41 9289 7271 7664 206 1533 363 C
+ATOM 307 CG ARG A 41 -9.186 -15.605 -25.856 1.00 71.18 C
+ANISOU 307 CG ARG A 41 10160 8433 8450 322 1286 387 C
+ATOM 308 CD ARG A 41 -7.710 -15.932 -25.568 1.00 80.04 C
+ANISOU 308 CD ARG A 41 11287 9622 9501 504 1238 570 C
+ATOM 309 NE ARG A 41 -6.866 -15.741 -26.762 1.00 74.82 N
+ANISOU 309 NE ARG A 41 10554 8929 8944 472 1145 532 N
+ATOM 310 CZ ARG A 41 -6.356 -14.582 -27.159 1.00 78.00 C
+ANISOU 310 CZ ARG A 41 10841 9455 9338 432 915 438 C
+ATOM 311 NH1 ARG A 41 -6.552 -13.467 -26.465 1.00 81.90 N
+ANISOU 311 NH1 ARG A 41 11285 10102 9732 410 749 350 N
+ATOM 312 NH2 ARG A 41 -5.644 -14.532 -28.265 1.00 86.15 N
+ANISOU 312 NH2 ARG A 41 11819 10442 10471 411 877 426 N
+ATOM 313 N ALA A 42 -13.150 -17.769 -27.971 1.00 49.81 N
+ANISOU 313 N ALA A 42 7468 5266 6189 -330 1868 7 N
+ATOM 314 CA ALA A 42 -13.768 -18.969 -28.558 1.00 57.96 C
+ANISOU 314 CA ALA A 42 8557 6104 7358 -524 2112 -75 C
+ATOM 315 C ALA A 42 -14.982 -18.639 -29.396 1.00 57.37 C
+ANISOU 315 C ALA A 42 8326 6129 7343 -777 2047 -282 C
+ATOM 316 O ALA A 42 -15.740 -19.526 -29.769 1.00 64.20 O
+ANISOU 316 O ALA A 42 9200 6877 8312 -990 2234 -389 O
+ATOM 317 CB ALA A 42 -14.200 -19.960 -27.458 1.00 56.47 C
+ANISOU 317 CB ALA A 42 8492 5754 7210 -482 2407 58 C
+ATOM 318 N GLY A 43 -15.231 -17.380 -29.635 1.00 52.54 N
+ANISOU 318 N GLY A 43 7557 5735 6668 -759 1799 -332 N
+ATOM 319 CA GLY A 43 -16.309 -17.040 -30.539 1.00 57.00 C
+ANISOU 319 CA GLY A 43 7941 6441 7273 -969 1718 -492 C
+ATOM 320 C GLY A 43 -17.684 -17.010 -29.934 1.00 58.47 C
+ANISOU 320 C GLY A 43 8011 6695 7510 -1063 1807 -511 C
+ATOM 321 O GLY A 43 -18.693 -16.858 -30.667 1.00 64.87 O
+ANISOU 321 O GLY A 43 8633 7651 8361 -1255 1754 -633 O
+ATOM 322 N SER A 44 -17.753 -17.088 -28.605 1.00 57.15 N
+ANISOU 322 N SER A 44 7930 6459 7323 -922 1931 -379 N
+ATOM 323 CA SER A 44 -19.057 -17.205 -27.927 1.00 59.58 C
+ANISOU 323 CA SER A 44 8144 6800 7692 -1003 2076 -376 C
+ATOM 324 C SER A 44 -19.354 -16.159 -26.851 1.00 51.98 C
+ANISOU 324 C SER A 44 7145 5959 6646 -810 2021 -281 C
+ATOM 325 O SER A 44 -20.144 -16.385 -25.952 1.00 58.60 O
+ANISOU 325 O SER A 44 7978 6778 7507 -803 2197 -224 O
+ATOM 326 CB SER A 44 -19.181 -18.630 -27.398 1.00 63.12 C
+ANISOU 326 CB SER A 44 8744 7008 8228 -1080 2393 -327 C
+ATOM 327 OG SER A 44 -17.989 -18.942 -26.691 1.00 75.47 O
+ANISOU 327 OG SER A 44 10522 8441 9708 -852 2451 -164 O
+ATOM 328 N CYS A 45 -18.785 -14.973 -26.981 1.00 51.65 N
+ANISOU 328 N CYS A 45 7072 6035 6515 -668 1796 -279 N
+ATOM 329 CA CYS A 45 -19.057 -13.886 -26.059 1.00 48.70 C
+ANISOU 329 CA CYS A 45 6677 5758 6066 -505 1753 -233 C
+ATOM 330 C CYS A 45 -18.893 -12.526 -26.780 1.00 51.12 C
+ANISOU 330 C CYS A 45 6860 6197 6366 -453 1521 -288 C
+ATOM 331 O CYS A 45 -18.542 -12.469 -27.980 1.00 50.80 O
+ANISOU 331 O CYS A 45 6749 6191 6360 -532 1388 -341 O
+ATOM 332 CB CYS A 45 -18.171 -13.989 -24.805 1.00 50.90 C
+ANISOU 332 CB CYS A 45 7166 5974 6198 -316 1803 -126 C
+ATOM 333 SG CYS A 45 -16.566 -13.180 -24.911 1.00 53.21 S
+ANISOU 333 SG CYS A 45 7542 6307 6366 -170 1556 -124 S
+ATOM 334 N SER A 46 -19.167 -11.439 -26.041 1.00 49.49 N
+ANISOU 334 N SER A 46 6640 6051 6114 -315 1503 -272 N
+ATOM 335 CA SER A 46 -19.261 -10.117 -26.614 1.00 49.31 C
+ANISOU 335 CA SER A 46 6494 6118 6122 -255 1356 -304 C
+ATOM 336 C SER A 46 -17.941 -9.369 -26.532 1.00 51.44 C
+ANISOU 336 C SER A 46 6888 6345 6311 -146 1208 -320 C
+ATOM 337 O SER A 46 -17.854 -8.268 -27.057 1.00 46.10 O
+ANISOU 337 O SER A 46 6135 5703 5678 -96 1103 -340 O
+ATOM 338 CB SER A 46 -20.298 -9.307 -25.871 1.00 50.14 C
+ANISOU 338 CB SER A 46 6525 6274 6249 -163 1462 -287 C
+ATOM 339 OG SER A 46 -19.973 -9.287 -24.483 1.00 49.91 O
+ANISOU 339 OG SER A 46 6691 6179 6094 -53 1563 -278 O
+ATOM 340 N SER A 47 -16.939 -9.950 -25.880 1.00 47.00 N
+ANISOU 340 N SER A 47 6498 5716 5641 -106 1210 -297 N
+ATOM 341 CA SER A 47 -15.839 -9.148 -25.341 1.00 48.40 C
+ANISOU 341 CA SER A 47 6782 5891 5713 -1 1093 -321 C
+ATOM 342 C SER A 47 -14.884 -8.548 -26.378 1.00 50.48 C
+ANISOU 342 C SER A 47 6998 6152 6030 -15 913 -348 C
+ATOM 343 O SER A 47 -14.433 -7.391 -26.220 1.00 42.86 O
+ANISOU 343 O SER A 47 6043 5186 5055 37 827 -403 O
+ATOM 344 CB SER A 47 -15.052 -9.964 -24.335 1.00 48.69 C
+ANISOU 344 CB SER A 47 6981 5919 5599 58 1134 -259 C
+ATOM 345 OG SER A 47 -14.042 -9.148 -23.822 1.00 52.57 O
+ANISOU 345 OG SER A 47 7538 6457 5976 130 999 -303 O
+ATOM 346 N CYS A 48 -14.586 -9.312 -27.432 1.00 46.30 N
+ANISOU 346 N CYS A 48 6426 5606 5560 -94 881 -320 N
+ATOM 347 CA CYS A 48 -13.615 -8.899 -28.445 1.00 43.55 C
+ANISOU 347 CA CYS A 48 6042 5255 5251 -102 736 -325 C
+ATOM 348 C CYS A 48 -14.282 -8.264 -29.667 1.00 48.19 C
+ANISOU 348 C CYS A 48 6472 5897 5938 -148 687 -339 C
+ATOM 349 O CYS A 48 -13.664 -8.163 -30.727 1.00 52.68 O
+ANISOU 349 O CYS A 48 7001 6475 6538 -171 598 -328 O
+ATOM 350 CB CYS A 48 -12.855 -10.140 -28.938 1.00 45.20 C
+ANISOU 350 CB CYS A 48 6309 5413 5450 -145 755 -280 C
+ATOM 351 SG CYS A 48 -13.936 -11.252 -29.869 1.00 49.74 S
+ANISOU 351 SG CYS A 48 6821 5979 6098 -304 875 -312 S
+ATOM 352 N ALA A 49 -15.536 -7.842 -29.543 1.00 49.80 N
+ANISOU 352 N ALA A 49 6575 6158 6186 -145 751 -344 N
+ATOM 353 CA ALA A 49 -16.294 -7.449 -30.708 1.00 48.00 C
+ANISOU 353 CA ALA A 49 6167 6039 6032 -181 710 -321 C
+ATOM 354 C ALA A 49 -15.698 -6.209 -31.365 1.00 47.62 C
+ANISOU 354 C ALA A 49 6079 5983 6030 -94 608 -287 C
+ATOM 355 O ALA A 49 -15.183 -5.313 -30.693 1.00 45.45 O
+ANISOU 355 O ALA A 49 5885 5614 5769 -6 608 -304 O
+ATOM 356 CB ALA A 49 -17.720 -7.170 -30.327 1.00 44.89 C
+ANISOU 356 CB ALA A 49 5646 5725 5684 -164 808 -302 C
+ATOM 357 N GLY A 50 -15.818 -6.151 -32.678 1.00 48.69 N
+ANISOU 357 N GLY A 50 6091 6224 6184 -128 536 -244 N
+ATOM 358 CA GLY A 50 -15.449 -4.952 -33.442 1.00 49.68 C
+ANISOU 358 CA GLY A 50 6154 6355 6367 -31 471 -170 C
+ATOM 359 C GLY A 50 -16.413 -4.732 -34.592 1.00 50.54 C
+ANISOU 359 C GLY A 50 6054 6667 6481 -27 438 -81 C
+ATOM 360 O GLY A 50 -17.402 -5.446 -34.760 1.00 51.08 O
+ANISOU 360 O GLY A 50 6008 6888 6512 -119 451 -99 O
+ATOM 361 N LYS A 51 -16.125 -3.748 -35.412 1.00 53.55 N
+ANISOU 361 N LYS A 51 6371 7070 6904 74 397 23 N
+ATOM 362 CA LYS A 51 -16.949 -3.502 -36.568 1.00 53.87 C
+ANISOU 362 CA LYS A 51 6201 7352 6915 104 349 142 C
+ATOM 363 C LYS A 51 -16.099 -3.324 -37.812 1.00 52.01 C
+ANISOU 363 C LYS A 51 5967 7166 6626 116 266 208 C
+ATOM 364 O LYS A 51 -15.259 -2.429 -37.884 1.00 49.83 O
+ANISOU 364 O LYS A 51 5763 6736 6431 222 288 275 O
+ATOM 365 CB LYS A 51 -17.819 -2.272 -36.354 1.00 55.11 C
+ANISOU 365 CB LYS A 51 6228 7529 7182 289 432 285 C
+ATOM 366 CG LYS A 51 -19.060 -2.302 -37.241 1.00 69.25 C
+ANISOU 366 CG LYS A 51 7743 9649 8918 311 386 414 C
+ATOM 367 CD LYS A 51 -19.994 -1.116 -37.036 1.00 78.14 C
+ANISOU 367 CD LYS A 51 8713 10807 10169 534 496 599 C
+ATOM 368 CE LYS A 51 -19.697 -0.098 -38.130 1.00 91.14 C
+ANISOU 368 CE LYS A 51 10279 12512 11835 709 478 813 C
+ATOM 369 NZ LYS A 51 -20.322 1.238 -37.924 1.00 98.12 N
+ANISOU 369 NZ LYS A 51 11067 13328 12884 974 639 1022 N
+ATOM 370 N VAL A 52 -16.371 -4.149 -38.805 1.00 56.50 N
+ANISOU 370 N VAL A 52 6451 7958 7057 -1 184 184 N
+ATOM 371 CA VAL A 52 -15.743 -4.044 -40.096 1.00 53.02 C
+ANISOU 371 CA VAL A 52 5995 7623 6524 10 113 251 C
+ATOM 372 C VAL A 52 -16.271 -2.823 -40.812 1.00 55.66 C
+ANISOU 372 C VAL A 52 6153 8116 6878 198 104 478 C
+ATOM 373 O VAL A 52 -17.446 -2.763 -41.107 1.00 57.54 O
+ANISOU 373 O VAL A 52 6184 8614 7061 218 71 553 O
+ATOM 374 CB VAL A 52 -16.050 -5.263 -40.957 1.00 52.46 C
+ANISOU 374 CB VAL A 52 5882 7779 6271 -184 41 135 C
+ATOM 375 CG1 VAL A 52 -15.519 -5.033 -42.382 1.00 54.82 C
+ANISOU 375 CG1 VAL A 52 6153 8239 6436 -149 -26 221 C
+ATOM 376 CG2 VAL A 52 -15.383 -6.462 -40.332 1.00 50.36 C
+ANISOU 376 CG2 VAL A 52 5817 7306 6010 -339 95 -55 C
+ATOM 377 N VAL A 53 -15.394 -1.848 -41.054 1.00 54.66 N
+ANISOU 377 N VAL A 53 6097 7828 6843 341 150 599 N
+ATOM 378 CA VAL A 53 -15.763 -0.629 -41.772 1.00 62.36 C
+ANISOU 378 CA VAL A 53 6930 8905 7859 554 184 855 C
+ATOM 379 C VAL A 53 -15.275 -0.645 -43.240 1.00 58.73 C
+ANISOU 379 C VAL A 53 6429 8643 7241 577 116 972 C
+ATOM 380 O VAL A 53 -15.785 0.085 -44.048 1.00 58.59 O
+ANISOU 380 O VAL A 53 6253 8828 7179 741 116 1203 O
+ATOM 381 CB VAL A 53 -15.351 0.680 -41.005 1.00 65.49 C
+ANISOU 381 CB VAL A 53 7415 8968 8500 719 338 940 C
+ATOM 382 CG1 VAL A 53 -15.576 0.504 -39.522 1.00 72.86 C
+ANISOU 382 CG1 VAL A 53 8446 9701 9533 655 398 764 C
+ATOM 383 CG2 VAL A 53 -13.917 1.090 -41.248 1.00 68.64 C
+ANISOU 383 CG2 VAL A 53 7968 9134 8977 721 376 943 C
+ATOM 384 N SER A 54 -14.348 -1.525 -43.591 1.00 53.74 N
+ANISOU 384 N SER A 54 5935 7975 6509 426 68 825 N
+ATOM 385 CA SER A 54 -13.884 -1.675 -44.972 1.00 55.87 C
+ANISOU 385 CA SER A 54 6190 8441 6597 431 18 904 C
+ATOM 386 C SER A 54 -13.173 -3.046 -45.081 1.00 56.25 C
+ANISOU 386 C SER A 54 6394 8450 6527 213 -15 660 C
+ATOM 387 O SER A 54 -12.486 -3.512 -44.129 1.00 49.66 O
+ANISOU 387 O SER A 54 5714 7335 5817 133 33 511 O
+ATOM 388 CB SER A 54 -12.991 -0.455 -45.367 1.00 56.61 C
+ANISOU 388 CB SER A 54 6326 8357 6824 625 121 1123 C
+ATOM 389 OG SER A 54 -12.138 -0.710 -46.445 1.00 63.73 O
+ANISOU 389 OG SER A 54 7288 9336 7589 611 112 1159 O
+ATOM 390 N GLY A 55 -13.389 -3.710 -46.217 1.00 53.71 N
+ANISOU 390 N GLY A 55 6028 8423 5956 121 -89 620 N
+ATOM 391 CA GLY A 55 -12.890 -5.055 -46.464 1.00 54.03 C
+ANISOU 391 CA GLY A 55 6214 8444 5869 -87 -89 381 C
+ATOM 392 C GLY A 55 -13.780 -6.179 -45.936 1.00 56.10 C
+ANISOU 392 C GLY A 55 6459 8774 6082 -306 -121 151 C
+ATOM 393 O GLY A 55 -14.982 -5.983 -45.681 1.00 60.55 O
+ANISOU 393 O GLY A 55 6840 9527 6637 -318 -183 180 O
+ATOM 394 N SER A 56 -13.181 -7.362 -45.781 1.00 52.30 N
+ANISOU 394 N SER A 56 6161 8128 5583 -472 -54 -60 N
+ATOM 395 CA SER A 56 -13.909 -8.555 -45.414 1.00 56.19 C
+ANISOU 395 CA SER A 56 6669 8647 6032 -704 -41 -291 C
+ATOM 396 C SER A 56 -13.104 -9.443 -44.480 1.00 53.82 C
+ANISOU 396 C SER A 56 6589 7981 5876 -764 94 -420 C
+ATOM 397 O SER A 56 -11.877 -9.347 -44.370 1.00 54.78 O
+ANISOU 397 O SER A 56 6852 7882 6078 -658 162 -364 O
+ATOM 398 CB SER A 56 -14.330 -9.330 -46.692 1.00 60.27 C
+ANISOU 398 CB SER A 56 7153 9473 6272 -904 -92 -449 C
+ATOM 399 OG SER A 56 -13.185 -9.640 -47.492 1.00 64.49 O
+ANISOU 399 OG SER A 56 7867 9923 6713 -890 -21 -484 O
+ATOM 400 N VAL A 57 -13.818 -10.317 -43.788 1.00 57.62 N
+ANISOU 400 N VAL A 57 7081 8413 6396 -929 142 -574 N
+ATOM 401 CA VAL A 57 -13.221 -11.309 -42.892 1.00 53.60 C
+ANISOU 401 CA VAL A 57 6773 7581 6008 -986 293 -680 C
+ATOM 402 C VAL A 57 -13.972 -12.587 -43.112 1.00 55.21 C
+ANISOU 402 C VAL A 57 7008 7830 6138 -1256 368 -912 C
+ATOM 403 O VAL A 57 -15.069 -12.588 -43.684 1.00 53.95 O
+ANISOU 403 O VAL A 57 6676 7964 5858 -1404 275 -989 O
+ATOM 404 CB VAL A 57 -13.373 -10.956 -41.381 1.00 57.18 C
+ANISOU 404 CB VAL A 57 7224 7857 6644 -880 320 -596 C
+ATOM 405 CG1 VAL A 57 -12.463 -9.803 -41.015 1.00 52.19 C
+ANISOU 405 CG1 VAL A 57 6602 7118 6107 -653 277 -417 C
+ATOM 406 CG2 VAL A 57 -14.834 -10.627 -41.047 1.00 53.61 C
+ANISOU 406 CG2 VAL A 57 6573 7599 6197 -936 258 -594 C
+ATOM 407 N ASP A 58 -13.366 -13.666 -42.641 1.00 55.82 N
+ANISOU 407 N ASP A 58 7294 7617 6296 -1318 547 -1013 N
+ATOM 408 CA ASP A 58 -13.996 -14.957 -42.561 1.00 58.46 C
+ANISOU 408 CA ASP A 58 7701 7878 6631 -1574 687 -1233 C
+ATOM 409 C ASP A 58 -14.136 -15.223 -41.085 1.00 55.65 C
+ANISOU 409 C ASP A 58 7395 7287 6461 -1515 794 -1166 C
+ATOM 410 O ASP A 58 -13.156 -15.457 -40.418 1.00 55.05 O
+ANISOU 410 O ASP A 58 7478 6953 6484 -1367 903 -1074 O
+ATOM 411 CB ASP A 58 -13.103 -16.016 -43.188 1.00 65.76 C
+ANISOU 411 CB ASP A 58 8862 8605 7518 -1656 869 -1374 C
+ATOM 412 CG ASP A 58 -13.609 -17.451 -42.970 1.00 72.39 C
+ANISOU 412 CG ASP A 58 9833 9259 8413 -1919 1088 -1606 C
+ATOM 413 OD1 ASP A 58 -14.654 -17.719 -42.304 1.00 72.82 O
+ANISOU 413 OD1 ASP A 58 9792 9332 8542 -2058 1107 -1663 O
+ATOM 414 OD2 ASP A 58 -12.932 -18.339 -43.523 1.00 80.41 O
+ANISOU 414 OD2 ASP A 58 11056 10090 9406 -1990 1274 -1737 O
+ATOM 415 N GLN A 59 -15.358 -15.182 -40.586 1.00 59.22 N
+ANISOU 415 N GLN A 59 7695 7858 6947 -1623 763 -1198 N
+ATOM 416 CA GLN A 59 -15.612 -15.422 -39.174 1.00 62.73 C
+ANISOU 416 CA GLN A 59 8181 8107 7544 -1569 878 -1130 C
+ATOM 417 C GLN A 59 -16.694 -16.457 -38.993 1.00 65.10 C
+ANISOU 417 C GLN A 59 8454 8390 7889 -1842 1015 -1303 C
+ATOM 418 O GLN A 59 -17.576 -16.295 -38.154 1.00 66.15 O
+ANISOU 418 O GLN A 59 8471 8562 8101 -1853 1028 -1256 O
+ATOM 419 CB GLN A 59 -16.011 -14.137 -38.463 1.00 57.25 C
+ANISOU 419 CB GLN A 59 7325 7538 6889 -1378 738 -953 C
+ATOM 420 CG GLN A 59 -17.246 -13.434 -39.016 1.00 55.97 C
+ANISOU 420 CG GLN A 59 6886 7717 6661 -1449 585 -955 C
+ATOM 421 CD GLN A 59 -17.652 -12.296 -38.096 1.00 62.04 C
+ANISOU 421 CD GLN A 59 7537 8522 7511 -1245 528 -780 C
+ATOM 422 OE1 GLN A 59 -18.210 -11.269 -38.534 1.00 66.81 O
+ANISOU 422 OE1 GLN A 59 7938 9366 8079 -1159 394 -682 O
+ATOM 423 NE2 GLN A 59 -17.359 -12.461 -36.800 1.00 56.51 N
+ANISOU 423 NE2 GLN A 59 6972 7583 6913 -1150 646 -731 N
+ATOM 424 N SER A 60 -16.585 -17.512 -39.786 1.00 64.01 N
+ANISOU 424 N SER A 60 8432 8180 7707 -2067 1137 -1510 N
+ATOM 425 CA SER A 60 -17.358 -18.738 -39.660 1.00 71.88 C
+ANISOU 425 CA SER A 60 9472 9060 8776 -2367 1339 -1715 C
+ATOM 426 C SER A 60 -17.042 -19.592 -38.399 1.00 69.57 C
+ANISOU 426 C SER A 60 9386 8371 8673 -2297 1620 -1638 C
+ATOM 427 O SER A 60 -17.817 -20.492 -38.073 1.00 71.72 O
+ANISOU 427 O SER A 60 9674 8528 9048 -2526 1809 -1764 O
+ATOM 428 CB SER A 60 -17.104 -19.609 -40.916 1.00 74.82 C
+ANISOU 428 CB SER A 60 9970 9417 9042 -2615 1424 -1979 C
+ATOM 429 OG SER A 60 -15.720 -19.921 -40.981 1.00 69.57 O
+ANISOU 429 OG SER A 60 9563 8467 8400 -2430 1560 -1910 O
+ATOM 430 N ASP A 61 -15.919 -19.358 -37.720 1.00 66.51 N
+ANISOU 430 N ASP A 61 9149 7790 8330 -1996 1657 -1429 N
+ATOM 431 CA ASP A 61 -15.690 -19.995 -36.412 1.00 71.53 C
+ANISOU 431 CA ASP A 61 9937 8131 9109 -1878 1886 -1294 C
+ATOM 432 C ASP A 61 -16.401 -19.243 -35.270 1.00 70.72 C
+ANISOU 432 C ASP A 61 9687 8145 9037 -1762 1797 -1144 C
+ATOM 433 O ASP A 61 -16.415 -19.738 -34.176 1.00 76.22 O
+ANISOU 433 O ASP A 61 10486 8652 9822 -1683 1980 -1036 O
+ATOM 434 CB ASP A 61 -14.215 -20.094 -36.049 1.00 71.97 C
+ANISOU 434 CB ASP A 61 10185 7978 9182 -1596 1957 -1113 C
+ATOM 435 CG ASP A 61 -13.386 -20.780 -37.089 1.00 73.12 C
+ANISOU 435 CG ASP A 61 10490 7983 9309 -1651 2076 -1223 C
+ATOM 436 OD1 ASP A 61 -13.929 -21.468 -37.992 1.00 83.53 O
+ANISOU 436 OD1 ASP A 61 11838 9288 10611 -1938 2174 -1474 O
+ATOM 437 OD2 ASP A 61 -12.154 -20.643 -36.976 1.00 81.02 O
+ANISOU 437 OD2 ASP A 61 11586 8889 10308 -1407 2081 -1062 O
+ATOM 438 N GLN A 62 -16.979 -18.058 -35.515 1.00 72.21 N
+ANISOU 438 N GLN A 62 9647 8639 9149 -1733 1544 -1123 N
+ATOM 439 CA GLN A 62 -17.756 -17.359 -34.476 1.00 67.75 C
+ANISOU 439 CA GLN A 62 8946 8173 8619 -1633 1498 -1004 C
+ATOM 440 C GLN A 62 -19.164 -17.942 -34.377 1.00 73.09 C
+ANISOU 440 C GLN A 62 9484 8914 9371 -1894 1611 -1123 C
+ATOM 441 O GLN A 62 -19.705 -18.425 -35.366 1.00 70.89 O
+ANISOU 441 O GLN A 62 9116 8743 9073 -2166 1602 -1315 O
+ATOM 442 CB GLN A 62 -17.867 -15.838 -34.717 1.00 66.80 C
+ANISOU 442 CB GLN A 62 8639 8319 8422 -1477 1233 -915 C
+ATOM 443 CG GLN A 62 -19.034 -15.338 -35.614 1.00 67.21 C
+ANISOU 443 CG GLN A 62 8412 8696 8428 -1635 1083 -998 C
+ATOM 444 CD GLN A 62 -20.329 -14.964 -34.874 1.00 64.99 C
+ANISOU 444 CD GLN A 62 7928 8548 8214 -1649 1104 -947 C
+ATOM 445 OE1 GLN A 62 -20.304 -14.340 -33.806 1.00 71.34 O
+ANISOU 445 OE1 GLN A 62 8759 9285 9059 -1444 1131 -808 O
+ATOM 446 NE2 GLN A 62 -21.471 -15.281 -35.476 1.00 63.47 N
+ANISOU 446 NE2 GLN A 62 7516 8576 8024 -1892 1085 -1063 N
+ATOM 447 N SER A 63 -19.742 -17.884 -33.174 1.00 72.66 N
+ANISOU 447 N SER A 63 9406 8808 9392 -1819 1719 -1013 N
+ATOM 448 CA SER A 63 -21.142 -18.244 -32.958 1.00 72.40 C
+ANISOU 448 CA SER A 63 9193 8866 9449 -2039 1821 -1088 C
+ATOM 449 C SER A 63 -21.984 -17.121 -32.341 1.00 66.69 C
+ANISOU 449 C SER A 63 8251 8365 8723 -1899 1711 -963 C
+ATOM 450 O SER A 63 -23.178 -17.067 -32.599 1.00 77.64 O
+ANISOU 450 O SER A 63 9385 9960 10154 -2074 1693 -1026 O
+ATOM 451 CB SER A 63 -21.277 -19.527 -32.118 1.00 70.17 C
+ANISOU 451 CB SER A 63 9088 8272 9301 -2138 2157 -1089 C
+ATOM 452 OG SER A 63 -20.352 -19.523 -31.051 1.00 76.40 O
+ANISOU 452 OG SER A 63 10101 8853 10075 -1847 2253 -890 O
+ATOM 453 N PHE A 64 -21.393 -16.238 -31.540 1.00 58.38 N
+ANISOU 453 N PHE A 64 7282 7276 7622 -1597 1650 -796 N
+ATOM 454 CA PHE A 64 -22.194 -15.361 -30.713 1.00 54.39 C
+ANISOU 454 CA PHE A 64 6633 6895 7136 -1461 1643 -686 C
+ATOM 455 C PHE A 64 -23.087 -14.381 -31.501 1.00 58.70 C
+ANISOU 455 C PHE A 64 6865 7765 7673 -1486 1455 -693 C
+ATOM 456 O PHE A 64 -24.182 -14.086 -31.039 1.00 57.54 O
+ANISOU 456 O PHE A 64 6527 7742 7591 -1488 1516 -644 O
+ATOM 457 CB PHE A 64 -21.262 -14.595 -29.755 1.00 55.93 C
+ANISOU 457 CB PHE A 64 7010 6983 7257 -1156 1611 -549 C
+ATOM 458 CG PHE A 64 -21.972 -13.594 -28.871 1.00 56.33 C
+ANISOU 458 CG PHE A 64 6960 7132 7311 -994 1624 -455 C
+ATOM 459 CD1 PHE A 64 -22.478 -13.970 -27.623 1.00 51.74 C
+ANISOU 459 CD1 PHE A 64 6445 6457 6754 -951 1839 -390 C
+ATOM 460 CD2 PHE A 64 -22.149 -12.275 -29.292 1.00 59.73 C
+ANISOU 460 CD2 PHE A 64 7237 7734 7723 -872 1452 -423 C
+ATOM 461 CE1 PHE A 64 -23.090 -13.031 -26.810 1.00 57.92 C
+ANISOU 461 CE1 PHE A 64 7159 7319 7527 -791 1874 -316 C
+ATOM 462 CE2 PHE A 64 -22.810 -11.337 -28.484 1.00 60.57 C
+ANISOU 462 CE2 PHE A 64 7268 7898 7848 -710 1505 -344 C
+ATOM 463 CZ PHE A 64 -23.289 -11.715 -27.242 1.00 54.75 C
+ANISOU 463 CZ PHE A 64 6607 7070 7122 -674 1715 -302 C
+ATOM 464 N LEU A 65 -22.629 -13.842 -32.646 1.00 59.31 N
+ANISOU 464 N LEU A 65 6879 7987 7667 -1474 1243 -724 N
+ATOM 465 CA LEU A 65 -23.379 -12.775 -33.374 1.00 63.23 C
+ANISOU 465 CA LEU A 65 7079 8808 8137 -1426 1064 -668 C
+ATOM 466 C LEU A 65 -24.616 -13.283 -34.188 1.00 65.16 C
+ANISOU 466 C LEU A 65 7020 9342 8393 -1708 1030 -770 C
+ATOM 467 O LEU A 65 -24.516 -14.329 -34.834 1.00 64.66 O
+ANISOU 467 O LEU A 65 7003 9259 8302 -1976 1052 -946 O
+ATOM 468 CB LEU A 65 -22.421 -11.920 -34.276 1.00 63.03 C
+ANISOU 468 CB LEU A 65 7095 8842 8010 -1279 864 -623 C
+ATOM 469 CG LEU A 65 -21.294 -11.083 -33.600 1.00 62.01 C
+ANISOU 469 CG LEU A 65 7179 8506 7874 -1004 852 -518 C
+ATOM 470 CD1 LEU A 65 -20.274 -10.486 -34.575 1.00 60.47 C
+ANISOU 470 CD1 LEU A 65 7035 8338 7604 -917 691 -493 C
+ATOM 471 CD2 LEU A 65 -21.842 -9.965 -32.731 1.00 60.62 C
+ANISOU 471 CD2 LEU A 65 6923 8352 7758 -795 888 -391 C
+ATOM 472 N ASP A 66 -25.764 -12.554 -34.051 1.00 69.31 N
+ANISOU 472 N ASP A 66 7243 10123 8968 -1644 999 -661 N
+ATOM 473 CA ASP A 66 -27.047 -12.615 -34.848 1.00 72.82 C
+ANISOU 473 CA ASP A 66 7291 10968 9408 -1843 905 -692 C
+ATOM 474 C ASP A 66 -26.639 -12.271 -36.317 1.00 77.46 C
+ANISOU 474 C ASP A 66 7794 11812 9825 -1871 656 -723 C
+ATOM 475 O ASP A 66 -25.716 -11.438 -36.541 1.00 65.69 O
+ANISOU 475 O ASP A 66 6447 10241 8269 -1624 566 -617 O
+ATOM 476 CB ASP A 66 -28.090 -11.511 -34.364 1.00 77.64 C
+ANISOU 476 CB ASP A 66 7609 11789 10101 -1619 914 -476 C
+ATOM 477 CG ASP A 66 -29.226 -12.030 -33.407 1.00 93.62 C
+ANISOU 477 CG ASP A 66 9481 13808 12279 -1733 1126 -471 C
+ATOM 478 OD1 ASP A 66 -29.080 -13.108 -32.793 1.00106.10 O
+ANISOU 478 OD1 ASP A 66 11255 15134 13923 -1914 1308 -596 O
+ATOM 479 OD2 ASP A 66 -30.299 -11.343 -33.266 1.00 93.76 O
+ANISOU 479 OD2 ASP A 66 9173 14081 12368 -1624 1134 -319 O
+ATOM 480 N ASP A 67 -27.292 -12.872 -37.323 1.00 79.83 N
+ANISOU 480 N ASP A 67 7864 12428 10039 -2173 549 -870 N
+ATOM 481 CA ASP A 67 -26.991 -12.525 -38.711 1.00 83.48 C
+ANISOU 481 CA ASP A 67 8232 13188 10299 -2190 314 -888 C
+ATOM 482 C ASP A 67 -27.305 -11.060 -38.958 1.00 81.61 C
+ANISOU 482 C ASP A 67 7760 13217 10028 -1857 174 -603 C
+ATOM 483 O ASP A 67 -26.634 -10.428 -39.777 1.00 81.48 O
+ANISOU 483 O ASP A 67 7791 13288 9878 -1705 34 -521 O
+ATOM 484 CB ASP A 67 -27.780 -13.356 -39.743 1.00 99.82 C
+ANISOU 484 CB ASP A 67 10050 15632 12243 -2589 204 -1107 C
+ATOM 485 CG ASP A 67 -27.453 -14.842 -39.701 1.00102.82 C
+ANISOU 485 CG ASP A 67 10677 15732 12655 -2952 367 -1422 C
+ATOM 486 OD1 ASP A 67 -26.299 -15.215 -39.353 1.00102.93 O
+ANISOU 486 OD1 ASP A 67 11082 15321 12706 -2872 499 -1465 O
+ATOM 487 OD2 ASP A 67 -28.380 -15.622 -40.029 1.00 94.69 O
+ANISOU 487 OD2 ASP A 67 9430 14922 11623 -3321 370 -1619 O
+ATOM 488 N GLU A 68 -28.313 -10.508 -38.287 1.00 76.33 N
+ANISOU 488 N GLU A 68 6842 12669 9490 -1729 236 -436 N
+ATOM 489 CA GLU A 68 -28.488 -9.053 -38.331 1.00 87.60 C
+ANISOU 489 CA GLU A 68 8114 14233 10935 -1350 179 -137 C
+ATOM 490 C GLU A 68 -27.140 -8.357 -37.951 1.00 89.20 C
+ANISOU 490 C GLU A 68 8695 14033 11161 -1073 233 -65 C
+ATOM 491 O GLU A 68 -26.669 -7.443 -38.628 1.00 88.13 O
+ANISOU 491 O GLU A 68 8554 13978 10954 -862 128 85 O
+ATOM 492 CB GLU A 68 -29.608 -8.602 -37.395 1.00 95.60 C
+ANISOU 492 CB GLU A 68 8892 15305 12126 -1215 319 23 C
+ATOM 493 CG GLU A 68 -29.735 -7.087 -37.282 1.00104.83 C
+ANISOU 493 CG GLU A 68 9958 16515 13354 -793 334 332 C
+ATOM 494 CD GLU A 68 -30.926 -6.636 -36.439 1.00115.12 C
+ANISOU 494 CD GLU A 68 11001 17904 14832 -647 495 501 C
+ATOM 495 OE1 GLU A 68 -31.956 -7.348 -36.393 1.00115.20 O
+ANISOU 495 OE1 GLU A 68 10727 18166 14878 -878 505 440 O
+ATOM 496 OE2 GLU A 68 -30.828 -5.546 -35.827 1.00115.96 O
+ANISOU 496 OE2 GLU A 68 11189 17821 15050 -303 630 690 O
+ATOM 497 N GLN A 69 -26.519 -8.821 -36.871 1.00 84.99 N
+ANISOU 497 N GLN A 69 8479 13084 10727 -1087 401 -169 N
+ATOM 498 CA GLN A 69 -25.278 -8.246 -36.383 1.00 74.41 C
+ANISOU 498 CA GLN A 69 7470 11389 9412 -867 450 -126 C
+ATOM 499 C GLN A 69 -24.113 -8.417 -37.351 1.00 73.31 C
+ANISOU 499 C GLN A 69 7506 11209 9139 -912 323 -199 C
+ATOM 500 O GLN A 69 -23.352 -7.485 -37.533 1.00 68.06 O
+ANISOU 500 O GLN A 69 6940 10450 8469 -692 283 -80 O
+ATOM 501 CB GLN A 69 -24.929 -8.815 -34.993 1.00 71.55 C
+ANISOU 501 CB GLN A 69 7378 10660 9148 -886 645 -216 C
+ATOM 502 CG GLN A 69 -25.865 -8.310 -33.913 1.00 72.95 C
+ANISOU 502 CG GLN A 69 7442 10823 9452 -746 799 -105 C
+ATOM 503 CD GLN A 69 -25.579 -8.891 -32.535 1.00 72.43 C
+ANISOU 503 CD GLN A 69 7636 10439 9442 -758 996 -178 C
+ATOM 504 OE1 GLN A 69 -25.227 -10.079 -32.369 1.00 64.31 O
+ANISOU 504 OE1 GLN A 69 6765 9275 8394 -961 1053 -316 O
+ATOM 505 NE2 GLN A 69 -25.737 -8.050 -31.530 1.00 72.76 N
+ANISOU 505 NE2 GLN A 69 7734 10360 9548 -530 1119 -79 N
+ATOM 506 N ILE A 70 -23.969 -9.589 -37.964 1.00 78.29 N
+ANISOU 506 N ILE A 70 8181 11890 9673 -1199 285 -397 N
+ATOM 507 CA ILE A 70 -22.959 -9.783 -39.017 1.00 75.81 C
+ANISOU 507 CA ILE A 70 8009 11579 9215 -1247 178 -469 C
+ATOM 508 C ILE A 70 -23.247 -8.950 -40.279 1.00 80.31 C
+ANISOU 508 C ILE A 70 8337 12536 9640 -1154 -9 -332 C
+ATOM 509 O ILE A 70 -22.334 -8.336 -40.829 1.00 79.77 O
+ANISOU 509 O ILE A 70 8384 12414 9511 -993 -67 -242 O
+ATOM 510 CB ILE A 70 -22.818 -11.250 -39.409 1.00 73.74 C
+ANISOU 510 CB ILE A 70 7859 11274 8884 -1583 218 -732 C
+ATOM 511 CG1 ILE A 70 -22.302 -12.031 -38.193 1.00 70.17 C
+ANISOU 511 CG1 ILE A 70 7687 10403 8571 -1612 426 -812 C
+ATOM 512 CG2 ILE A 70 -21.890 -11.368 -40.629 1.00 69.89 C
+ANISOU 512 CG2 ILE A 70 7488 10843 8223 -1620 113 -800 C
+ATOM 513 CD1 ILE A 70 -22.178 -13.529 -38.421 1.00 73.86 C
+ANISOU 513 CD1 ILE A 70 8298 10742 9024 -1925 541 -1055 C
+ATOM 514 N GLY A 71 -24.501 -8.934 -40.720 1.00 80.29 N
+ANISOU 514 N GLY A 71 7989 12934 9582 -1249 -96 -298 N
+ATOM 515 CA GLY A 71 -24.945 -8.065 -41.782 1.00 84.25 C
+ANISOU 515 CA GLY A 71 8211 13855 9944 -1113 -267 -106 C
+ATOM 516 C GLY A 71 -24.627 -6.587 -41.543 1.00 90.55 C
+ANISOU 516 C GLY A 71 9018 14542 10843 -709 -231 194 C
+ATOM 517 O GLY A 71 -24.287 -5.858 -42.499 1.00 81.85 O
+ANISOU 517 O GLY A 71 7861 13613 9622 -547 -332 358 O
+ATOM 518 N GLU A 72 -24.732 -6.122 -40.290 1.00 85.84 N
+ANISOU 518 N GLU A 72 8502 13652 10461 -547 -67 267 N
+ATOM 519 CA GLU A 72 -24.363 -4.720 -39.956 1.00 84.90 C
+ANISOU 519 CA GLU A 72 8443 13349 10466 -189 11 507 C
+ATOM 520 C GLU A 72 -22.834 -4.496 -39.871 1.00 78.13 C
+ANISOU 520 C GLU A 72 7942 12117 9627 -119 45 456 C
+ATOM 521 O GLU A 72 -22.372 -3.347 -39.798 1.00 75.56 O
+ANISOU 521 O GLU A 72 7680 11635 9392 134 104 627 O
+ATOM 522 CB GLU A 72 -25.091 -4.227 -38.684 1.00 90.04 C
+ANISOU 522 CB GLU A 72 9044 13847 11319 -41 188 589 C
+ATOM 523 CG GLU A 72 -26.571 -3.883 -38.951 1.00104.52 C
+ANISOU 523 CG GLU A 72 10456 16088 13168 32 166 776 C
+ATOM 524 CD GLU A 72 -27.484 -3.868 -37.708 1.00115.41 C
+ANISOU 524 CD GLU A 72 11754 17371 14724 75 350 790 C
+ATOM 525 OE1 GLU A 72 -27.080 -4.369 -36.632 1.00119.16 O
+ANISOU 525 OE1 GLU A 72 12496 17503 15276 -13 480 617 O
+ATOM 526 OE2 GLU A 72 -28.638 -3.366 -37.807 1.00117.96 O
+ANISOU 526 OE2 GLU A 72 11730 17986 15102 210 373 993 O
+ATOM 527 N GLY A 73 -22.058 -5.585 -39.875 1.00 67.33 N
+ANISOU 527 N GLY A 73 6793 10600 8189 -345 28 226 N
+ATOM 528 CA GLY A 73 -20.599 -5.498 -39.918 1.00 67.28 C
+ANISOU 528 CA GLY A 73 7077 10299 8185 -298 44 183 C
+ATOM 529 C GLY A 73 -19.821 -5.908 -38.667 1.00 62.16 C
+ANISOU 529 C GLY A 73 6708 9260 7648 -326 164 53 C
+ATOM 530 O GLY A 73 -18.585 -5.771 -38.638 1.00 63.30 O
+ANISOU 530 O GLY A 73 7062 9181 7806 -276 171 35 O
+ATOM 531 N PHE A 74 -20.506 -6.407 -37.635 1.00 54.21 N
+ANISOU 531 N PHE A 74 5695 8188 6714 -400 259 -21 N
+ATOM 532 CA PHE A 74 -19.813 -6.733 -36.379 1.00 50.47 C
+ANISOU 532 CA PHE A 74 5476 7384 6317 -394 373 -110 C
+ATOM 533 C PHE A 74 -19.017 -7.976 -36.610 1.00 48.37 C
+ANISOU 533 C PHE A 74 5385 7015 5978 -577 371 -263 C
+ATOM 534 O PHE A 74 -19.389 -8.786 -37.447 1.00 48.97 O
+ANISOU 534 O PHE A 74 5379 7259 5968 -764 327 -353 O
+ATOM 535 CB PHE A 74 -20.762 -6.849 -35.179 1.00 51.93 C
+ANISOU 535 CB PHE A 74 5616 7527 6587 -388 503 -119 C
+ATOM 536 CG PHE A 74 -21.382 -5.561 -34.825 1.00 54.65 C
+ANISOU 536 CG PHE A 74 5836 7903 7023 -170 553 31 C
+ATOM 537 CD1 PHE A 74 -20.611 -4.556 -34.263 1.00 59.00 C
+ANISOU 537 CD1 PHE A 74 6552 8226 7638 12 602 74 C
+ATOM 538 CD2 PHE A 74 -22.705 -5.309 -35.097 1.00 62.03 C
+ANISOU 538 CD2 PHE A 74 6482 9097 7988 -145 562 133 C
+ATOM 539 CE1 PHE A 74 -21.141 -3.312 -33.970 1.00 61.30 C
+ANISOU 539 CE1 PHE A 74 6759 8497 8034 221 689 205 C
+ATOM 540 CE2 PHE A 74 -23.278 -4.074 -34.762 1.00 65.97 C
+ANISOU 540 CE2 PHE A 74 6870 9599 8593 96 649 300 C
+ATOM 541 CZ PHE A 74 -22.481 -3.064 -34.213 1.00 69.36 C
+ANISOU 541 CZ PHE A 74 7503 9751 9097 283 726 331 C
+ATOM 542 N VAL A 75 -17.889 -8.074 -35.901 1.00 48.27 N
+ANISOU 542 N VAL A 75 5608 6737 5995 -517 420 -290 N
+ATOM 543 CA VAL A 75 -16.947 -9.203 -35.999 1.00 47.38 C
+ANISOU 543 CA VAL A 75 5685 6480 5837 -632 453 -395 C
+ATOM 544 C VAL A 75 -16.430 -9.520 -34.615 1.00 49.15 C
+ANISOU 544 C VAL A 75 6091 6473 6108 -575 558 -404 C
+ATOM 545 O VAL A 75 -16.248 -8.629 -33.798 1.00 47.13 O
+ANISOU 545 O VAL A 75 5866 6148 5892 -428 559 -343 O
+ATOM 546 CB VAL A 75 -15.775 -8.834 -36.956 1.00 48.33 C
+ANISOU 546 CB VAL A 75 5867 6583 5911 -571 365 -359 C
+ATOM 547 CG1 VAL A 75 -15.079 -7.549 -36.507 1.00 49.98 C
+ANISOU 547 CG1 VAL A 75 6112 6686 6192 -372 333 -248 C
+ATOM 548 CG2 VAL A 75 -14.782 -9.929 -37.088 1.00 49.25 C
+ANISOU 548 CG2 VAL A 75 6167 6549 5995 -653 422 -442 C
+ATOM 549 N LEU A 76 -16.184 -10.794 -34.355 1.00 49.57 N
+ANISOU 549 N LEU A 76 6273 6411 6149 -688 660 -479 N
+ATOM 550 CA LEU A 76 -15.521 -11.198 -33.153 1.00 47.93 C
+ANISOU 550 CA LEU A 76 6243 6013 5953 -611 755 -452 C
+ATOM 551 C LEU A 76 -14.098 -11.431 -33.507 1.00 45.41 C
+ANISOU 551 C LEU A 76 6054 5590 5609 -559 721 -432 C
+ATOM 552 O LEU A 76 -13.751 -12.422 -34.211 1.00 46.04 O
+ANISOU 552 O LEU A 76 6200 5615 5676 -659 783 -486 O
+ATOM 553 CB LEU A 76 -16.177 -12.472 -32.551 1.00 49.85 C
+ANISOU 553 CB LEU A 76 6545 6174 6220 -737 935 -501 C
+ATOM 554 CG LEU A 76 -17.619 -12.228 -32.105 1.00 52.45 C
+ANISOU 554 CG LEU A 76 6721 6616 6591 -787 985 -507 C
+ATOM 555 CD1 LEU A 76 -18.258 -13.483 -31.561 1.00 56.78 C
+ANISOU 555 CD1 LEU A 76 7318 7068 7185 -930 1185 -551 C
+ATOM 556 CD2 LEU A 76 -17.640 -11.190 -31.039 1.00 52.12 C
+ANISOU 556 CD2 LEU A 76 6691 6565 6545 -599 972 -426 C
+ATOM 557 N THR A 77 -13.248 -10.565 -32.967 1.00 46.19 N
+ANISOU 557 N THR A 77 6193 5650 5705 -409 646 -365 N
+ATOM 558 CA THR A 77 -11.875 -10.505 -33.442 1.00 42.15 C
+ANISOU 558 CA THR A 77 5743 5084 5186 -350 586 -327 C
+ATOM 559 C THR A 77 -11.098 -11.716 -33.100 1.00 45.26 C
+ANISOU 559 C THR A 77 6277 5354 5565 -343 692 -303 C
+ATOM 560 O THR A 77 -10.095 -11.997 -33.772 1.00 50.56 O
+ANISOU 560 O THR A 77 6987 5982 6241 -320 686 -277 O
+ATOM 561 CB THR A 77 -11.139 -9.239 -32.928 1.00 47.57 C
+ANISOU 561 CB THR A 77 6417 5768 5889 -225 479 -279 C
+ATOM 562 OG1 THR A 77 -11.277 -9.041 -31.498 1.00 46.78 O
+ANISOU 562 OG1 THR A 77 6374 5641 5757 -165 507 -279 O
+ATOM 563 CG2 THR A 77 -11.677 -8.033 -33.637 1.00 44.69 C
+ANISOU 563 CG2 THR A 77 5923 5486 5568 -210 405 -272 C
+ATOM 564 N CYS A 78 -11.496 -12.435 -32.033 1.00 50.28 N
+ANISOU 564 N CYS A 78 6990 5924 6188 -338 814 -286 N
+ATOM 565 CA CYS A 78 -10.739 -13.646 -31.587 1.00 46.96 C
+ANISOU 565 CA CYS A 78 6711 5367 5761 -289 955 -214 C
+ATOM 566 C CYS A 78 -11.053 -14.787 -32.559 1.00 49.46 C
+ANISOU 566 C CYS A 78 7079 5587 6126 -435 1104 -293 C
+ATOM 567 O CYS A 78 -10.411 -15.828 -32.559 1.00 51.48 O
+ANISOU 567 O CYS A 78 7458 5693 6407 -405 1257 -244 O
+ATOM 568 CB CYS A 78 -11.178 -14.092 -30.182 1.00 53.40 C
+ANISOU 568 CB CYS A 78 7600 6145 6541 -234 1071 -151 C
+ATOM 569 SG CYS A 78 -12.881 -14.758 -30.242 1.00 51.94 S
+ANISOU 569 SG CYS A 78 7387 5928 6417 -420 1238 -249 S
+ATOM 570 N ALA A 79 -12.058 -14.598 -33.405 1.00 53.34 N
+ANISOU 570 N ALA A 79 7469 6170 6626 -598 1068 -418 N
+ATOM 571 CA ALA A 79 -12.515 -15.685 -34.236 1.00 55.83 C
+ANISOU 571 CA ALA A 79 7829 6416 6967 -787 1210 -543 C
+ATOM 572 C ALA A 79 -12.550 -15.316 -35.744 1.00 59.35 C
+ANISOU 572 C ALA A 79 8188 7002 7360 -894 1092 -650 C
+ATOM 573 O ALA A 79 -13.139 -16.061 -36.535 1.00 55.41 O
+ANISOU 573 O ALA A 79 7693 6513 6847 -1099 1172 -802 O
+ATOM 574 CB ALA A 79 -13.912 -16.109 -33.759 1.00 59.21 C
+ANISOU 574 CB ALA A 79 8205 6858 7433 -940 1313 -616 C
+ATOM 575 N ALA A 80 -11.913 -14.208 -36.131 1.00 51.54 N
+ANISOU 575 N ALA A 80 7126 6121 6335 -767 917 -576 N
+ATOM 576 CA ALA A 80 -12.025 -13.689 -37.496 1.00 52.60 C
+ANISOU 576 CA ALA A 80 7161 6426 6398 -833 799 -635 C
+ATOM 577 C ALA A 80 -10.641 -13.659 -38.187 1.00 52.00 C
+ANISOU 577 C ALA A 80 7168 6282 6305 -734 797 -581 C
+ATOM 578 O ALA A 80 -9.618 -13.161 -37.620 1.00 49.22 O
+ANISOU 578 O ALA A 80 6840 5858 6002 -561 760 -450 O
+ATOM 579 CB ALA A 80 -12.672 -12.314 -37.499 1.00 53.13 C
+ANISOU 579 CB ALA A 80 7044 6690 6453 -769 627 -571 C
+ATOM 580 N TYR A 81 -10.617 -14.269 -39.382 1.00 50.25 N
+ANISOU 580 N TYR A 81 6991 6091 6011 -860 853 -698 N
+ATOM 581 CA TYR A 81 -9.473 -14.232 -40.301 1.00 47.17 C
+ANISOU 581 CA TYR A 81 6664 5673 5582 -786 868 -665 C
+ATOM 582 C TYR A 81 -9.695 -13.111 -41.287 1.00 50.29 C
+ANISOU 582 C TYR A 81 6913 6311 5882 -771 694 -634 C
+ATOM 583 O TYR A 81 -10.787 -12.986 -41.832 1.00 51.07 O
+ANISOU 583 O TYR A 81 6906 6613 5885 -903 620 -722 O
+ATOM 584 CB TYR A 81 -9.426 -15.493 -41.146 1.00 51.08 C
+ANISOU 584 CB TYR A 81 7306 6080 6021 -943 1048 -833 C
+ATOM 585 CG TYR A 81 -9.189 -16.735 -40.354 1.00 58.36 C
+ANISOU 585 CG TYR A 81 8398 6724 7050 -954 1282 -854 C
+ATOM 586 CD1 TYR A 81 -8.089 -16.833 -39.537 1.00 55.81 C
+ANISOU 586 CD1 TYR A 81 8143 6231 6829 -740 1353 -672 C
+ATOM 587 CD2 TYR A 81 -10.088 -17.800 -40.389 1.00 63.94 C
+ANISOU 587 CD2 TYR A 81 9183 7347 7763 -1179 1441 -1042 C
+ATOM 588 CE1 TYR A 81 -7.853 -17.958 -38.801 1.00 58.92 C
+ANISOU 588 CE1 TYR A 81 8687 6381 7317 -708 1583 -641 C
+ATOM 589 CE2 TYR A 81 -9.854 -18.945 -39.642 1.00 66.35 C
+ANISOU 589 CE2 TYR A 81 9659 7359 8190 -1168 1700 -1029 C
+ATOM 590 CZ TYR A 81 -8.713 -19.009 -38.869 1.00 60.72 C
+ANISOU 590 CZ TYR A 81 9018 6485 7566 -910 1772 -810 C
+ATOM 591 OH TYR A 81 -8.409 -20.106 -38.119 1.00 67.42 O
+ANISOU 591 OH TYR A 81 10026 7058 8530 -846 2038 -740 O
+ATOM 592 N PRO A 82 -8.665 -12.297 -41.547 1.00 49.08 N
+ANISOU 592 N PRO A 82 6740 6152 5756 -609 636 -494 N
+ATOM 593 CA PRO A 82 -8.810 -11.345 -42.651 1.00 47.57 C
+ANISOU 593 CA PRO A 82 6433 6172 5466 -585 518 -444 C
+ATOM 594 C PRO A 82 -8.910 -12.091 -43.994 1.00 51.19 C
+ANISOU 594 C PRO A 82 6956 6741 5751 -719 580 -581 C
+ATOM 595 O PRO A 82 -8.241 -13.098 -44.143 1.00 50.40 O
+ANISOU 595 O PRO A 82 7018 6474 5657 -755 739 -662 O
+ATOM 596 CB PRO A 82 -7.518 -10.563 -42.588 1.00 45.77 C
+ANISOU 596 CB PRO A 82 6205 5851 5335 -407 504 -279 C
+ATOM 597 CG PRO A 82 -6.511 -11.495 -41.974 1.00 47.02 C
+ANISOU 597 CG PRO A 82 6497 5788 5579 -368 638 -280 C
+ATOM 598 CD PRO A 82 -7.288 -12.383 -41.033 1.00 48.95 C
+ANISOU 598 CD PRO A 82 6803 5951 5844 -460 702 -380 C
+ATOM 599 N THR A 83 -9.757 -11.627 -44.924 1.00 48.49 N
+ANISOU 599 N THR A 83 6489 6685 5247 -788 466 -606 N
+ATOM 600 CA THR A 83 -9.762 -12.153 -46.307 1.00 51.50 C
+ANISOU 600 CA THR A 83 6925 7231 5411 -907 499 -734 C
+ATOM 601 C THR A 83 -9.429 -11.095 -47.342 1.00 49.00 C
+ANISOU 601 C THR A 83 6517 7124 4975 -771 406 -571 C
+ATOM 602 O THR A 83 -9.557 -11.323 -48.533 1.00 50.94 O
+ANISOU 602 O THR A 83 6777 7584 4992 -851 400 -650 O
+ATOM 603 CB THR A 83 -11.157 -12.749 -46.647 1.00 56.46 C
+ANISOU 603 CB THR A 83 7475 8093 5884 -1158 444 -940 C
+ATOM 604 OG1 THR A 83 -12.178 -11.809 -46.291 1.00 57.08 O
+ANISOU 604 OG1 THR A 83 7322 8384 5979 -1111 275 -821 O
+ATOM 605 CG2 THR A 83 -11.377 -14.007 -45.846 1.00 57.41 C
+ANISOU 605 CG2 THR A 83 7729 7967 6115 -1324 602 -1126 C
+ATOM 606 N SER A 84 -9.123 -9.892 -46.868 1.00 49.80 N
+ANISOU 606 N SER A 84 6516 7183 5220 -575 335 -345 N
+ATOM 607 CA SER A 84 -8.642 -8.809 -47.689 1.00 51.09 C
+ANISOU 607 CA SER A 84 6609 7464 5339 -413 295 -145 C
+ATOM 608 C SER A 84 -8.017 -7.870 -46.668 1.00 49.54 C
+ANISOU 608 C SER A 84 6376 7040 5405 -251 294 24 C
+ATOM 609 O SER A 84 -8.128 -8.093 -45.490 1.00 47.99 O
+ANISOU 609 O SER A 84 6201 6679 5354 -276 298 -28 O
+ATOM 610 CB SER A 84 -9.795 -8.069 -48.389 1.00 56.08 C
+ANISOU 610 CB SER A 84 7050 8454 5800 -400 154 -60 C
+ATOM 611 OG SER A 84 -10.589 -7.330 -47.413 1.00 52.75 O
+ANISOU 611 OG SER A 84 6487 8017 5536 -337 76 32 O
+ATOM 612 N ASP A 85 -7.382 -6.806 -47.126 1.00 46.38 N
+ANISOU 612 N ASP A 85 5924 6639 5057 -96 299 222 N
+ATOM 613 CA ASP A 85 -6.983 -5.755 -46.253 1.00 49.05 C
+ANISOU 613 CA ASP A 85 6206 6797 5631 21 291 358 C
+ATOM 614 C ASP A 85 -8.286 -5.304 -45.638 1.00 50.62 C
+ANISOU 614 C ASP A 85 6295 7088 5849 14 202 357 C
+ATOM 615 O ASP A 85 -9.334 -5.212 -46.322 1.00 54.44 O
+ANISOU 615 O ASP A 85 6675 7839 6170 0 136 381 O
+ATOM 616 CB ASP A 85 -6.341 -4.609 -47.058 1.00 47.60 C
+ANISOU 616 CB ASP A 85 5967 6628 5489 170 330 579 C
+ATOM 617 CG ASP A 85 -4.900 -4.925 -47.559 1.00 52.73 C
+ANISOU 617 CG ASP A 85 6707 7157 6169 197 442 609 C
+ATOM 618 OD1 ASP A 85 -4.277 -5.936 -47.150 1.00 52.35 O
+ANISOU 618 OD1 ASP A 85 6760 6983 6148 128 494 481 O
+ATOM 619 OD2 ASP A 85 -4.368 -4.108 -48.369 1.00 56.01 O
+ANISOU 619 OD2 ASP A 85 7082 7598 6598 307 501 791 O
+ATOM 620 N VAL A 86 -8.255 -4.968 -44.377 1.00 45.98 N
+ANISOU 620 N VAL A 86 5710 6311 5446 32 200 343 N
+ATOM 621 CA VAL A 86 -9.522 -4.737 -43.682 1.00 45.59 C
+ANISOU 621 CA VAL A 86 5573 6331 5415 18 147 316 C
+ATOM 622 C VAL A 86 -9.338 -3.725 -42.597 1.00 43.07 C
+ANISOU 622 C VAL A 86 5245 5812 5305 107 169 375 C
+ATOM 623 O VAL A 86 -8.275 -3.619 -42.020 1.00 44.22 O
+ANISOU 623 O VAL A 86 5470 5760 5572 112 201 355 O
+ATOM 624 CB VAL A 86 -10.078 -6.072 -43.148 1.00 48.01 C
+ANISOU 624 CB VAL A 86 5939 6654 5647 -143 144 117 C
+ATOM 625 CG1 VAL A 86 -9.082 -6.710 -42.219 1.00 49.95 C
+ANISOU 625 CG1 VAL A 86 6328 6652 5997 -170 206 38 C
+ATOM 626 CG2 VAL A 86 -11.442 -5.939 -42.465 1.00 50.17 C
+ANISOU 626 CG2 VAL A 86 6107 7020 5936 -171 105 89 C
+ATOM 627 N THR A 87 -10.371 -2.925 -42.367 1.00 45.19 N
+ANISOU 627 N THR A 87 5406 6148 5615 181 159 451 N
+ATOM 628 CA THR A 87 -10.350 -1.923 -41.352 1.00 45.50 C
+ANISOU 628 CA THR A 87 5452 5991 5845 259 209 481 C
+ATOM 629 C THR A 87 -11.421 -2.288 -40.351 1.00 47.74 C
+ANISOU 629 C THR A 87 5716 6302 6122 213 199 378 C
+ATOM 630 O THR A 87 -12.526 -2.582 -40.730 1.00 47.10 O
+ANISOU 630 O THR A 87 5523 6431 5940 201 166 397 O
+ATOM 631 CB THR A 87 -10.656 -0.544 -41.917 1.00 50.80 C
+ANISOU 631 CB THR A 87 6025 6671 6605 425 268 690 C
+ATOM 632 OG1 THR A 87 -9.617 -0.209 -42.839 1.00 51.07 O
+ANISOU 632 OG1 THR A 87 6082 6667 6653 467 301 799 O
+ATOM 633 CG2 THR A 87 -10.675 0.502 -40.782 1.00 50.21 C
+ANISOU 633 CG2 THR A 87 5986 6346 6744 486 359 679 C
+ATOM 634 N ILE A 88 -11.062 -2.273 -39.075 1.00 47.12 N
+ANISOU 634 N ILE A 88 5735 6028 6137 183 227 271 N
+ATOM 635 CA ILE A 88 -11.915 -2.724 -38.016 1.00 47.67 C
+ANISOU 635 CA ILE A 88 5818 6102 6192 138 240 168 C
+ATOM 636 C ILE A 88 -11.927 -1.719 -36.867 1.00 42.11 C
+ANISOU 636 C ILE A 88 5161 5214 5622 206 309 145 C
+ATOM 637 O ILE A 88 -10.907 -1.494 -36.286 1.00 43.07 O
+ANISOU 637 O ILE A 88 5383 5181 5801 181 309 80 O
+ATOM 638 CB ILE A 88 -11.395 -4.068 -37.512 1.00 49.90 C
+ANISOU 638 CB ILE A 88 6214 6349 6396 13 220 34 C
+ATOM 639 CG1 ILE A 88 -11.587 -5.112 -38.628 1.00 49.65 C
+ANISOU 639 CG1 ILE A 88 6153 6480 6231 -76 191 16 C
+ATOM 640 CG2 ILE A 88 -12.108 -4.473 -36.212 1.00 51.61 C
+ANISOU 640 CG2 ILE A 88 6470 6528 6608 -19 261 -58 C
+ATOM 641 CD1 ILE A 88 -10.896 -6.432 -38.386 1.00 49.71 C
+ANISOU 641 CD1 ILE A 88 6291 6410 6186 -176 218 -87 C
+ATOM 642 N GLU A 89 -13.099 -1.193 -36.519 1.00 43.90 N
+ANISOU 642 N GLU A 89 5312 5478 5890 282 372 184 N
+ATOM 643 CA GLU A 89 -13.278 -0.421 -35.290 1.00 47.43 C
+ANISOU 643 CA GLU A 89 5831 5749 6437 331 467 118 C
+ATOM 644 C GLU A 89 -13.369 -1.368 -34.118 1.00 48.10 C
+ANISOU 644 C GLU A 89 6014 5828 6434 235 456 -33 C
+ATOM 645 O GLU A 89 -14.208 -2.238 -34.131 1.00 46.09 O
+ANISOU 645 O GLU A 89 5699 5711 6099 192 450 -38 O
+ATOM 646 CB GLU A 89 -14.570 0.378 -35.316 1.00 52.55 C
+ANISOU 646 CB GLU A 89 6361 6442 7161 470 572 230 C
+ATOM 647 CG GLU A 89 -14.633 1.492 -36.347 1.00 63.41 C
+ANISOU 647 CG GLU A 89 7637 7813 8643 621 629 431 C
+ATOM 648 CD GLU A 89 -15.842 2.407 -36.147 1.00 73.77 C
+ANISOU 648 CD GLU A 89 8843 9123 10063 800 777 562 C
+ATOM 649 OE1 GLU A 89 -16.733 2.070 -35.336 1.00 80.53 O
+ANISOU 649 OE1 GLU A 89 9673 10027 10895 795 819 497 O
+ATOM 650 OE2 GLU A 89 -15.887 3.472 -36.793 1.00 76.86 O
+ANISOU 650 OE2 GLU A 89 9175 9453 10575 962 875 747 O
+ATOM 651 N THR A 90 -12.531 -1.166 -33.102 1.00 44.70 N
+ANISOU 651 N THR A 90 5722 5248 6013 199 462 -150 N
+ATOM 652 CA THR A 90 -12.427 -2.084 -32.002 1.00 43.34 C
+ANISOU 652 CA THR A 90 5650 5087 5727 129 448 -262 C
+ATOM 653 C THR A 90 -13.337 -1.652 -30.827 1.00 47.39 C
+ANISOU 653 C THR A 90 6210 5556 6240 178 561 -329 C
+ATOM 654 O THR A 90 -13.940 -0.586 -30.855 1.00 46.89 O
+ANISOU 654 O THR A 90 6109 5423 6283 268 659 -299 O
+ATOM 655 CB THR A 90 -10.937 -2.167 -31.551 1.00 42.54 C
+ANISOU 655 CB THR A 90 5651 4917 5596 69 368 -337 C
+ATOM 656 OG1 THR A 90 -10.480 -0.884 -31.081 1.00 46.16 O
+ANISOU 656 OG1 THR A 90 6155 5238 6145 78 400 -410 O
+ATOM 657 CG2 THR A 90 -10.008 -2.601 -32.693 1.00 42.77 C
+ANISOU 657 CG2 THR A 90 5633 4980 5636 38 287 -260 C
+ATOM 658 N HIS A 91 -13.394 -2.452 -29.757 1.00 47.53 N
+ANISOU 658 N HIS A 91 6321 5601 6138 136 573 -409 N
+ATOM 659 CA HIS A 91 -14.121 -2.027 -28.523 1.00 50.54 C
+ANISOU 659 CA HIS A 91 6775 5936 6488 184 696 -488 C
+ATOM 660 C HIS A 91 -15.577 -1.689 -28.823 1.00 48.63 C
+ANISOU 660 C HIS A 91 6407 5732 6336 269 818 -403 C
+ATOM 661 O HIS A 91 -16.087 -0.683 -28.370 1.00 47.55 O
+ANISOU 661 O HIS A 91 6289 5503 6273 358 945 -426 O
+ATOM 662 CB HIS A 91 -13.449 -0.819 -27.839 1.00 53.09 C
+ANISOU 662 CB HIS A 91 7212 6116 6841 192 723 -613 C
+ATOM 663 CG HIS A 91 -12.037 -1.062 -27.377 1.00 53.84 C
+ANISOU 663 CG HIS A 91 7400 6222 6835 99 592 -706 C
+ATOM 664 ND1 HIS A 91 -10.998 -1.282 -28.245 1.00 52.95 N
+ANISOU 664 ND1 HIS A 91 7230 6124 6762 50 467 -650 N
+ATOM 665 CD2 HIS A 91 -11.494 -1.106 -26.132 1.00 56.62 C
+ANISOU 665 CD2 HIS A 91 7877 6601 7033 54 565 -841 C
+ATOM 666 CE1 HIS A 91 -9.869 -1.434 -27.568 1.00 52.38 C
+ANISOU 666 CE1 HIS A 91 7223 6088 6589 -18 367 -735 C
+ATOM 667 NE2 HIS A 91 -10.149 -1.348 -26.282 1.00 55.87 N
+ANISOU 667 NE2 HIS A 91 7774 6556 6899 -20 411 -852 N
+ATOM 668 N LYS A 92 -16.228 -2.521 -29.624 1.00 49.04 N
+ANISOU 668 N LYS A 92 6318 5927 6386 236 787 -308 N
+ATOM 669 CA LYS A 92 -17.650 -2.390 -29.844 1.00 50.58 C
+ANISOU 669 CA LYS A 92 6348 6224 6644 297 884 -219 C
+ATOM 670 C LYS A 92 -18.507 -3.326 -28.988 1.00 47.54 C
+ANISOU 670 C LYS A 92 5964 5904 6193 250 976 -250 C
+ATOM 671 O LYS A 92 -19.654 -3.503 -29.328 1.00 46.77 O
+ANISOU 671 O LYS A 92 5686 5937 6144 257 1030 -172 O
+ATOM 672 CB LYS A 92 -17.947 -2.701 -31.306 1.00 53.04 C
+ANISOU 672 CB LYS A 92 6468 6705 6979 263 785 -107 C
+ATOM 673 CG LYS A 92 -17.183 -1.817 -32.271 1.00 56.58 C
+ANISOU 673 CG LYS A 92 6898 7107 7489 325 715 -36 C
+ATOM 674 CD LYS A 92 -17.486 -0.352 -32.061 1.00 58.78 C
+ANISOU 674 CD LYS A 92 7167 7262 7905 494 841 28 C
+ATOM 675 CE LYS A 92 -18.585 0.113 -32.975 1.00 67.73 C
+ANISOU 675 CE LYS A 92 8061 8564 9107 618 876 223 C
+ATOM 676 NZ LYS A 92 -18.423 1.591 -33.141 1.00 70.69 N
+ANISOU 676 NZ LYS A 92 8453 8766 9637 795 997 324 N
+ATOM 677 N GLU A 93 -17.977 -3.940 -27.920 1.00 48.14 N
+ANISOU 677 N GLU A 93 6220 5912 6155 204 998 -342 N
+ATOM 678 CA GLU A 93 -18.834 -4.744 -26.990 1.00 51.58 C
+ANISOU 678 CA GLU A 93 6674 6388 6535 183 1133 -348 C
+ATOM 679 C GLU A 93 -20.133 -4.043 -26.630 1.00 53.52 C
+ANISOU 679 C GLU A 93 6808 6660 6864 287 1296 -305 C
+ATOM 680 O GLU A 93 -21.165 -4.650 -26.637 1.00 58.70 O
+ANISOU 680 O GLU A 93 7330 7419 7554 250 1380 -249 O
+ATOM 681 CB GLU A 93 -18.112 -5.078 -25.684 1.00 53.98 C
+ANISOU 681 CB GLU A 93 7203 6619 6686 189 1166 -429 C
+ATOM 682 CG GLU A 93 -18.999 -5.656 -24.586 1.00 58.34 C
+ANISOU 682 CG GLU A 93 7798 7194 7171 208 1345 -418 C
+ATOM 683 CD GLU A 93 -18.194 -6.346 -23.498 1.00 59.78 C
+ANISOU 683 CD GLU A 93 8187 7360 7166 207 1352 -449 C
+ATOM 684 OE1 GLU A 93 -17.556 -5.652 -22.668 1.00 64.37 O
+ANISOU 684 OE1 GLU A 93 8915 7917 7626 267 1330 -538 O
+ATOM 685 OE2 GLU A 93 -18.184 -7.597 -23.528 1.00 52.88 O
+ANISOU 685 OE2 GLU A 93 7321 6504 6265 142 1381 -382 O
+ATOM 686 N GLU A 94 -20.084 -2.768 -26.311 1.00 59.72 N
+ANISOU 686 N GLU A 94 7647 7342 7699 413 1362 -331 N
+ATOM 687 CA GLU A 94 -21.265 -2.097 -25.790 1.00 66.89 C
+ANISOU 687 CA GLU A 94 8483 8242 8687 544 1565 -289 C
+ATOM 688 C GLU A 94 -22.389 -2.061 -26.822 1.00 70.98 C
+ANISOU 688 C GLU A 94 8697 8926 9344 581 1575 -124 C
+ATOM 689 O GLU A 94 -23.572 -2.215 -26.481 1.00 76.40 O
+ANISOU 689 O GLU A 94 9243 9704 10081 626 1721 -54 O
+ATOM 690 CB GLU A 94 -20.887 -0.700 -25.315 1.00 74.24 C
+ANISOU 690 CB GLU A 94 9560 8986 9660 665 1660 -370 C
+ATOM 691 CG GLU A 94 -20.302 -0.701 -23.891 1.00 88.53 C
+ANISOU 691 CG GLU A 94 11642 10696 11297 640 1723 -551 C
+ATOM 692 CD GLU A 94 -21.356 -0.505 -22.760 1.00104.83 C
+ANISOU 692 CD GLU A 94 13759 12740 13331 745 1979 -573 C
+ATOM 693 OE1 GLU A 94 -20.982 0.024 -21.666 1.00102.89 O
+ANISOU 693 OE1 GLU A 94 13744 12388 12962 767 2076 -740 O
+ATOM 694 OE2 GLU A 94 -22.562 -0.867 -22.947 1.00106.29 O
+ANISOU 694 OE2 GLU A 94 13749 13029 13605 797 2092 -434 O
+ATOM 695 N ALA A 95 -22.007 -1.909 -28.091 1.00 68.41 N
+ANISOU 695 N ALA A 95 8255 8672 9065 556 1414 -53 N
+ATOM 696 CA ALA A 95 -22.956 -1.709 -29.182 1.00 66.09 C
+ANISOU 696 CA ALA A 95 7658 8583 8869 608 1388 116 C
+ATOM 697 C ALA A 95 -23.662 -2.996 -29.528 1.00 66.44 C
+ANISOU 697 C ALA A 95 7523 8851 8867 435 1328 127 C
+ATOM 698 O ALA A 95 -24.779 -2.940 -30.017 1.00 70.13 O
+ANISOU 698 O ALA A 95 7710 9533 9402 465 1352 251 O
+ATOM 699 CB ALA A 95 -22.245 -1.163 -30.422 1.00 66.10 C
+ANISOU 699 CB ALA A 95 7613 8606 8896 636 1238 189 C
+ATOM 700 N ILE A 96 -23.008 -4.142 -29.324 1.00 64.35 N
+ANISOU 700 N ILE A 96 7407 8544 8498 253 1257 4 N
+ATOM 701 CA ILE A 96 -23.650 -5.436 -29.582 1.00 69.19 C
+ANISOU 701 CA ILE A 96 7886 9314 9088 56 1244 -17 C
+ATOM 702 C ILE A 96 -24.290 -6.032 -28.311 1.00 75.00 C
+ANISOU 702 C ILE A 96 8682 9987 9825 30 1440 -50 C
+ATOM 703 O ILE A 96 -24.815 -7.127 -28.332 1.00 68.54 O
+ANISOU 703 O ILE A 96 7782 9246 9011 -142 1479 -77 O
+ATOM 704 CB ILE A 96 -22.743 -6.492 -30.279 1.00 69.26 C
+ANISOU 704 CB ILE A 96 7991 9314 9009 -136 1099 -110 C
+ATOM 705 CG1 ILE A 96 -21.443 -6.740 -29.528 1.00 72.23 C
+ANISOU 705 CG1 ILE A 96 8677 9458 9305 -123 1101 -195 C
+ATOM 706 CG2 ILE A 96 -22.463 -6.154 -31.716 1.00 67.05 C
+ANISOU 706 CG2 ILE A 96 7581 9181 8715 -151 922 -66 C
+ATOM 707 CD1 ILE A 96 -21.463 -8.031 -28.757 1.00 71.63 C
+ANISOU 707 CD1 ILE A 96 8723 9309 9184 -245 1210 -253 C
+ATOM 708 N MET A 97 -24.258 -5.310 -27.201 1.00 82.61 N
+ANISOU 708 N MET A 97 9796 10805 10784 194 1584 -55 N
+ATOM 709 CA MET A 97 -25.147 -5.636 -26.099 1.00 87.11 C
+ANISOU 709 CA MET A 97 10364 11365 11366 215 1801 -42 C
+ATOM 710 C MET A 97 -26.325 -4.668 -26.205 1.00 95.61 C
+ANISOU 710 C MET A 97 11196 12551 12577 376 1919 80 C
+ATOM 711 O MET A 97 -27.410 -5.101 -26.587 1.00 94.92 O
+ANISOU 711 O MET A 97 10826 12664 12575 303 1954 163 O
+ATOM 712 CB MET A 97 -24.435 -5.516 -24.761 1.00 78.92 C
+ANISOU 712 CB MET A 97 9648 10134 10203 296 1904 -129 C
+ATOM 713 CG MET A 97 -23.264 -6.468 -24.547 1.00 69.75 C
+ANISOU 713 CG MET A 97 8709 8888 8904 181 1804 -207 C
+ATOM 714 SD MET A 97 -22.432 -5.914 -23.038 1.00 73.23 S
+ANISOU 714 SD MET A 97 9478 9183 9162 316 1882 -298 S
+ATOM 715 CE MET A 97 -21.484 -7.324 -22.587 1.00 70.81 C
+ANISOU 715 CE MET A 97 9359 8848 8698 213 1836 -305 C
+ATOM 716 N LEU A 98 -26.060 -3.361 -25.977 1.00101.64 N
+ANISOU 716 N LEU A 98 12055 13191 13371 583 1974 95 N
+ATOM 717 CA LEU A 98 -27.090 -2.306 -25.727 1.00104.44 C
+ANISOU 717 CA LEU A 98 12260 13563 13858 803 2175 216 C
+ATOM 718 C LEU A 98 -27.843 -1.768 -26.965 1.00 99.32 C
+ANISOU 718 C LEU A 98 11253 13135 13349 890 2107 411 C
+ATOM 719 O LEU A 98 -27.308 -1.714 -28.071 1.00 91.78 O
+ANISOU 719 O LEU A 98 10232 12263 12378 839 1898 441 O
+ATOM 720 CB LEU A 98 -26.469 -1.140 -24.941 1.00 98.56 C
+ANISOU 720 CB LEU A 98 11797 12554 13097 977 2303 129 C
+TER 721 LEU A 98
+ATOM 722 N ALA B 2 -32.420 -24.500 -28.343 1.00 55.40 N
+ANISOU 722 N ALA B 2 8165 6777 6106 -670 -1057 -125 N
+ATOM 723 CA ALA B 2 -32.280 -23.018 -28.309 1.00 49.74 C
+ANISOU 723 CA ALA B 2 7221 6215 5463 -512 -965 -28 C
+ATOM 724 C ALA B 2 -30.968 -22.594 -27.656 1.00 49.10 C
+ANISOU 724 C ALA B 2 7123 6073 5460 -324 -756 -44 C
+ATOM 725 O ALA B 2 -30.475 -23.240 -26.699 1.00 48.76 O
+ANISOU 725 O ALA B 2 7101 5932 5490 -308 -687 -81 O
+ATOM 726 CB ALA B 2 -33.452 -22.398 -27.562 1.00 46.79 C
+ANISOU 726 CB ALA B 2 6548 6005 5225 -580 -1026 92 C
+ATOM 727 N THR B 3 -30.475 -21.450 -28.119 1.00 46.70 N
+ANISOU 727 N THR B 3 6765 5842 5136 -203 -668 1 N
+ATOM 728 CA THR B 3 -29.337 -20.783 -27.525 1.00 45.09 C
+ANISOU 728 CA THR B 3 6493 5632 5006 -79 -488 8 C
+ATOM 729 C THR B 3 -29.711 -19.332 -27.227 1.00 42.65 C
+ANISOU 729 C THR B 3 6022 5395 4786 -46 -461 119 C
+ATOM 730 O THR B 3 -30.163 -18.603 -28.102 1.00 49.78 O
+ANISOU 730 O THR B 3 6948 6349 5617 -31 -515 186 O
+ATOM 731 CB THR B 3 -28.152 -20.886 -28.525 1.00 48.51 C
+ANISOU 731 CB THR B 3 7083 6061 5285 14 -383 -53 C
+ATOM 732 OG1 THR B 3 -27.960 -22.272 -28.848 1.00 53.59 O
+ANISOU 732 OG1 THR B 3 7925 6609 5827 21 -421 -170 O
+ATOM 733 CG2 THR B 3 -26.865 -20.283 -27.959 1.00 46.16 C
+ANISOU 733 CG2 THR B 3 6683 5804 5049 105 -200 -45 C
+ATOM 734 N TYR B 4 -29.515 -18.935 -25.980 1.00 41.02 N
+ANISOU 734 N TYR B 4 5685 5178 4720 -22 -381 136 N
+ATOM 735 CA TYR B 4 -29.849 -17.616 -25.484 1.00 41.59 C
+ANISOU 735 CA TYR B 4 5649 5273 4878 26 -345 216 C
+ATOM 736 C TYR B 4 -28.595 -16.874 -25.182 1.00 37.08 C
+ANISOU 736 C TYR B 4 5099 4664 4323 55 -200 205 C
+ATOM 737 O TYR B 4 -27.552 -17.444 -25.084 1.00 42.67 O
+ANISOU 737 O TYR B 4 5829 5376 5007 49 -128 142 O
+ATOM 738 CB TYR B 4 -30.686 -17.729 -24.208 1.00 37.93 C
+ANISOU 738 CB TYR B 4 5032 4839 4538 12 -366 231 C
+ATOM 739 CG TYR B 4 -31.986 -18.470 -24.482 1.00 40.65 C
+ANISOU 739 CG TYR B 4 5310 5268 4864 -68 -514 257 C
+ATOM 740 CD1 TYR B 4 -32.953 -17.916 -25.304 1.00 41.09 C
+ANISOU 740 CD1 TYR B 4 5314 5421 4875 -38 -621 333 C
+ATOM 741 CD2 TYR B 4 -32.253 -19.691 -23.893 1.00 39.18 C
+ANISOU 741 CD2 TYR B 4 5113 5074 4699 -188 -554 219 C
+ATOM 742 CE1 TYR B 4 -34.139 -18.580 -25.546 1.00 44.88 C
+ANISOU 742 CE1 TYR B 4 5690 6029 5332 -146 -773 362 C
+ATOM 743 CE2 TYR B 4 -33.429 -20.383 -24.132 1.00 44.73 C
+ANISOU 743 CE2 TYR B 4 5750 5865 5377 -328 -695 249 C
+ATOM 744 CZ TYR B 4 -34.369 -19.827 -24.951 1.00 49.31 C
+ANISOU 744 CZ TYR B 4 6235 6582 5915 -317 -807 316 C
+ATOM 745 OH TYR B 4 -35.506 -20.526 -25.188 1.00 53.31 O
+ANISOU 745 OH TYR B 4 6643 7219 6390 -490 -962 347 O
+ATOM 746 N LYS B 5 -28.735 -15.589 -25.005 1.00 42.61 N
+ANISOU 746 N LYS B 5 5794 5333 5063 87 -164 270 N
+ATOM 747 CA LYS B 5 -27.647 -14.685 -24.656 1.00 46.72 C
+ANISOU 747 CA LYS B 5 6346 5805 5598 57 -42 270 C
+ATOM 748 C LYS B 5 -27.871 -14.311 -23.218 1.00 44.65 C
+ANISOU 748 C LYS B 5 6004 5508 5453 71 -18 246 C
+ATOM 749 O LYS B 5 -28.949 -13.910 -22.869 1.00 45.52 O
+ANISOU 749 O LYS B 5 6085 5600 5610 146 -64 281 O
+ATOM 750 CB LYS B 5 -27.735 -13.411 -25.451 1.00 51.37 C
+ANISOU 750 CB LYS B 5 7063 6323 6130 68 -27 364 C
+ATOM 751 CG LYS B 5 -27.674 -13.596 -26.941 1.00 58.63 C
+ANISOU 751 CG LYS B 5 8089 7285 6902 63 -56 410 C
+ATOM 752 CD LYS B 5 -26.289 -13.986 -27.387 1.00 70.28 C
+ANISOU 752 CD LYS B 5 9582 8829 8291 -17 60 365 C
+ATOM 753 CE LYS B 5 -26.281 -14.277 -28.899 1.00 79.59 C
+ANISOU 753 CE LYS B 5 10887 10066 9288 -6 42 396 C
+ATOM 754 NZ LYS B 5 -26.107 -13.052 -29.737 1.00 78.80 N
+ANISOU 754 NZ LYS B 5 10935 9919 9086 -50 88 523 N
+ATOM 755 N VAL B 6 -26.848 -14.482 -22.400 1.00 44.73 N
+ANISOU 755 N VAL B 6 5968 5536 5490 12 52 185 N
+ATOM 756 CA VAL B 6 -26.898 -14.160 -21.017 1.00 43.45 C
+ANISOU 756 CA VAL B 6 5755 5350 5403 9 75 149 C
+ATOM 757 C VAL B 6 -25.875 -13.071 -20.817 1.00 41.71 C
+ANISOU 757 C VAL B 6 5600 5078 5168 -88 150 141 C
+ATOM 758 O VAL B 6 -24.703 -13.264 -21.100 1.00 40.03 O
+ANISOU 758 O VAL B 6 5351 4944 4913 -178 196 125 O
+ATOM 759 CB VAL B 6 -26.496 -15.357 -20.132 1.00 43.61 C
+ANISOU 759 CB VAL B 6 5675 5449 5445 0 68 89 C
+ATOM 760 CG1 VAL B 6 -26.579 -14.975 -18.662 1.00 45.36 C
+ANISOU 760 CG1 VAL B 6 5860 5659 5714 -5 90 55 C
+ATOM 761 CG2 VAL B 6 -27.382 -16.547 -20.422 1.00 42.80 C
+ANISOU 761 CG2 VAL B 6 5551 5370 5340 37 -7 99 C
+ATOM 762 N LYS B 7 -26.334 -11.940 -20.314 1.00 40.23 N
+ANISOU 762 N LYS B 7 5512 4765 5007 -71 162 150 N
+ATOM 763 CA LYS B 7 -25.489 -10.806 -20.042 1.00 45.32 C
+ANISOU 763 CA LYS B 7 6277 5311 5631 -205 217 138 C
+ATOM 764 C LYS B 7 -25.268 -10.732 -18.545 1.00 45.32 C
+ANISOU 764 C LYS B 7 6243 5315 5660 -241 224 48 C
+ATOM 765 O LYS B 7 -26.230 -10.649 -17.762 1.00 42.09 O
+ANISOU 765 O LYS B 7 5848 4860 5282 -112 213 21 O
+ATOM 766 CB LYS B 7 -26.179 -9.567 -20.522 1.00 45.61 C
+ANISOU 766 CB LYS B 7 6527 5150 5652 -141 218 203 C
+ATOM 767 CG LYS B 7 -25.518 -8.255 -20.177 1.00 54.48 C
+ANISOU 767 CG LYS B 7 7863 6090 6747 -291 265 191 C
+ATOM 768 CD LYS B 7 -26.348 -7.148 -20.886 1.00 64.52 C
+ANISOU 768 CD LYS B 7 9392 7132 7990 -162 255 284 C
+ATOM 769 CE LYS B 7 -25.977 -5.744 -20.437 1.00 79.55 C
+ANISOU 769 CE LYS B 7 11603 8759 9861 -274 292 266 C
+ATOM 770 NZ LYS B 7 -26.138 -4.714 -21.507 1.00 86.71 N
+ANISOU 770 NZ LYS B 7 12802 9439 10702 -264 295 396 N
+ATOM 771 N PHE B 8 -24.001 -10.796 -18.153 1.00 44.26 N
+ANISOU 771 N PHE B 8 6044 5273 5500 -411 242 4 N
+ATOM 772 CA PHE B 8 -23.636 -10.739 -16.757 1.00 48.27 C
+ANISOU 772 CA PHE B 8 6521 5811 6006 -472 227 -80 C
+ATOM 773 C PHE B 8 -23.203 -9.366 -16.431 1.00 50.61 C
+ANISOU 773 C PHE B 8 7012 5952 6265 -641 245 -114 C
+ATOM 774 O PHE B 8 -22.332 -8.836 -17.115 1.00 51.85 O
+ANISOU 774 O PHE B 8 7205 6107 6388 -833 269 -77 O
+ATOM 775 CB PHE B 8 -22.495 -11.714 -16.458 1.00 46.54 C
+ANISOU 775 CB PHE B 8 6090 5823 5767 -542 208 -104 C
+ATOM 776 CG PHE B 8 -22.919 -13.133 -16.573 1.00 43.20 C
+ANISOU 776 CG PHE B 8 5543 5501 5370 -371 182 -85 C
+ATOM 777 CD1 PHE B 8 -23.753 -13.684 -15.611 1.00 45.99 C
+ANISOU 777 CD1 PHE B 8 5889 5839 5743 -264 152 -107 C
+ATOM 778 CD2 PHE B 8 -22.561 -13.888 -17.670 1.00 43.53 C
+ANISOU 778 CD2 PHE B 8 5511 5629 5397 -326 196 -45 C
+ATOM 779 CE1 PHE B 8 -24.172 -15.008 -15.719 1.00 45.51 C
+ANISOU 779 CE1 PHE B 8 5756 5836 5697 -151 123 -79 C
+ATOM 780 CE2 PHE B 8 -22.977 -15.203 -17.786 1.00 47.96 C
+ANISOU 780 CE2 PHE B 8 6024 6230 5968 -183 163 -39 C
+ATOM 781 CZ PHE B 8 -23.809 -15.751 -16.817 1.00 42.32 C
+ANISOU 781 CZ PHE B 8 5316 5479 5284 -113 120 -50 C
+ATOM 782 N ILE B 9 -23.818 -8.777 -15.407 1.00 50.12 N
+ANISOU 782 N ILE B 9 7095 5752 6194 -582 242 -186 N
+ATOM 783 CA ILE B 9 -23.293 -7.532 -14.841 1.00 52.49 C
+ANISOU 783 CA ILE B 9 7627 5881 6436 -773 243 -255 C
+ATOM 784 C ILE B 9 -22.569 -7.908 -13.581 1.00 53.51 C
+ANISOU 784 C ILE B 9 7645 6168 6518 -894 195 -352 C
+ATOM 785 O ILE B 9 -23.199 -8.276 -12.624 1.00 53.62 O
+ANISOU 785 O ILE B 9 7645 6206 6520 -744 190 -409 O
+ATOM 786 CB ILE B 9 -24.432 -6.583 -14.587 1.00 57.52 C
+ANISOU 786 CB ILE B 9 8544 6244 7065 -590 275 -283 C
+ATOM 787 CG1 ILE B 9 -25.188 -6.426 -15.903 1.00 59.96 C
+ANISOU 787 CG1 ILE B 9 8902 6461 7416 -426 296 -159 C
+ATOM 788 CG2 ILE B 9 -23.932 -5.267 -13.966 1.00 60.99 C
+ANISOU 788 CG2 ILE B 9 9309 6437 7425 -785 272 -375 C
+ATOM 789 CD1 ILE B 9 -26.172 -5.282 -15.905 1.00 63.59 C
+ANISOU 789 CD1 ILE B 9 9670 6630 7859 -227 324 -158 C
+ATOM 790 N THR B 10 -21.243 -7.928 -13.622 1.00 58.51 N
+ANISOU 790 N THR B 10 8157 6958 7116 -1157 160 -355 N
+ATOM 791 CA THR B 10 -20.440 -8.325 -12.483 1.00 58.08 C
+ANISOU 791 CA THR B 10 7958 7106 7001 -1275 86 -431 C
+ATOM 792 C THR B 10 -19.973 -7.044 -11.813 1.00 70.23 C
+ANISOU 792 C THR B 10 9748 8484 8451 -1550 48 -529 C
+ATOM 793 O THR B 10 -20.144 -5.958 -12.368 1.00 71.35 O
+ANISOU 793 O THR B 10 10161 8360 8588 -1655 87 -519 O
+ATOM 794 CB THR B 10 -19.189 -9.135 -12.876 1.00 58.06 C
+ANISOU 794 CB THR B 10 7627 7434 6998 -1387 54 -376 C
+ATOM 795 OG1 THR B 10 -18.233 -8.281 -13.503 1.00 67.21 O
+ANISOU 795 OG1 THR B 10 8801 8610 8125 -1697 67 -349 O
+ATOM 796 CG2 THR B 10 -19.528 -10.276 -13.818 1.00 59.69 C
+ANISOU 796 CG2 THR B 10 7661 7742 7275 -1147 101 -286 C
+ATOM 797 N PRO B 11 -19.376 -7.160 -10.620 1.00 72.85 N
+ANISOU 797 N PRO B 11 10022 8962 8697 -1676 -39 -622 N
+ATOM 798 CA PRO B 11 -18.837 -5.933 -10.022 1.00 82.51 C
+ANISOU 798 CA PRO B 11 11506 10030 9814 -1997 -96 -729 C
+ATOM 799 C PRO B 11 -17.740 -5.357 -10.913 1.00 82.13 C
+ANISOU 799 C PRO B 11 11402 10036 9765 -2359 -105 -662 C
+ATOM 800 O PRO B 11 -17.601 -4.166 -11.043 1.00 81.04 O
+ANISOU 800 O PRO B 11 11578 9634 9578 -2614 -104 -697 O
+ATOM 801 CB PRO B 11 -18.263 -6.417 -8.685 1.00 79.55 C
+ANISOU 801 CB PRO B 11 10990 9902 9333 -2070 -213 -819 C
+ATOM 802 CG PRO B 11 -19.024 -7.665 -8.373 1.00 77.41 C
+ANISOU 802 CG PRO B 11 10544 9762 9107 -1699 -182 -776 C
+ATOM 803 CD PRO B 11 -19.316 -8.308 -9.700 1.00 70.96 C
+ANISOU 803 CD PRO B 11 9555 8976 8429 -1526 -97 -639 C
+ATOM 804 N GLU B 12 -17.008 -6.230 -11.575 1.00 88.50 N
+ANISOU 804 N GLU B 12 11824 11180 10621 -2365 -98 -558 N
+ATOM 805 CA GLU B 12 -15.873 -5.804 -12.367 1.00 99.06 C
+ANISOU 805 CA GLU B 12 13027 12669 11940 -2715 -89 -484 C
+ATOM 806 C GLU B 12 -16.299 -5.351 -13.766 1.00 93.10 C
+ANISOU 806 C GLU B 12 12432 11697 11242 -2687 35 -371 C
+ATOM 807 O GLU B 12 -15.498 -4.776 -14.476 1.00 97.19 O
+ANISOU 807 O GLU B 12 12930 12268 11727 -3008 67 -299 O
+ATOM 808 CB GLU B 12 -14.832 -6.940 -12.446 1.00112.44 C
+ANISOU 808 CB GLU B 12 14216 14866 13638 -2694 -123 -425 C
+ATOM 809 CG GLU B 12 -14.678 -7.719 -11.130 1.00124.13 C
+ANISOU 809 CG GLU B 12 15529 16561 15070 -2562 -247 -503 C
+ATOM 810 CD GLU B 12 -13.339 -8.441 -10.973 1.00129.71 C
+ANISOU 810 CD GLU B 12 15773 17775 15735 -2649 -327 -459 C
+ATOM 811 OE1 GLU B 12 -12.591 -8.120 -10.015 1.00122.40 O
+ANISOU 811 OE1 GLU B 12 14767 17032 14705 -2906 -469 -526 O
+ATOM 812 OE2 GLU B 12 -13.042 -9.343 -11.788 1.00121.66 O
+ANISOU 812 OE2 GLU B 12 14470 16981 14772 -2441 -255 -362 O
+ATOM 813 N GLY B 13 -17.543 -5.608 -14.166 1.00 81.49 N
+ANISOU 813 N GLY B 13 11109 10009 9842 -2323 99 -344 N
+ATOM 814 CA GLY B 13 -18.037 -5.147 -15.451 1.00 73.28 C
+ANISOU 814 CA GLY B 13 10250 8758 8835 -2271 193 -234 C
+ATOM 815 C GLY B 13 -18.997 -6.122 -16.098 1.00 65.13 C
+ANISOU 815 C GLY B 13 9104 7761 7882 -1867 241 -172 C
+ATOM 816 O GLY B 13 -19.539 -6.995 -15.467 1.00 67.40 O
+ANISOU 816 O GLY B 13 9263 8138 8207 -1617 210 -222 O
+ATOM 817 N GLU B 14 -19.185 -5.957 -17.384 1.00 61.80 N
+ANISOU 817 N GLU B 14 8743 7270 7466 -1838 311 -57 N
+ATOM 818 CA GLU B 14 -20.256 -6.598 -18.125 1.00 63.32 C
+ANISOU 818 CA GLU B 14 8924 7423 7712 -1496 338 2 C
+ATOM 819 C GLU B 14 -19.671 -7.497 -19.189 1.00 56.31 C
+ANISOU 819 C GLU B 14 7774 6809 6810 -1480 388 83 C
+ATOM 820 O GLU B 14 -18.634 -7.194 -19.774 1.00 62.63 O
+ANISOU 820 O GLU B 14 8502 7742 7551 -1731 443 140 O
+ATOM 821 CB GLU B 14 -21.129 -5.544 -18.792 1.00 71.21 C
+ANISOU 821 CB GLU B 14 10284 8074 8699 -1428 362 71 C
+ATOM 822 CG GLU B 14 -22.416 -5.260 -18.043 1.00 86.78 C
+ANISOU 822 CG GLU B 14 12442 9819 10709 -1152 330 6 C
+ATOM 823 CD GLU B 14 -22.957 -3.842 -18.244 1.00101.03 C
+ANISOU 823 CD GLU B 14 14681 11229 12476 -1139 343 36 C
+ATOM 824 OE1 GLU B 14 -22.373 -2.917 -17.631 1.00107.53 O
+ANISOU 824 OE1 GLU B 14 15741 11869 13245 -1388 335 -29 O
+ATOM 825 OE2 GLU B 14 -23.973 -3.658 -18.983 1.00100.60 O
+ANISOU 825 OE2 GLU B 14 14745 11041 12435 -874 348 124 O
+ATOM 826 N LEU B 15 -20.365 -8.587 -19.454 1.00 56.17 N
+ANISOU 826 N LEU B 15 7631 6874 6835 -1191 377 86 N
+ATOM 827 CA LEU B 15 -20.023 -9.507 -20.528 1.00 55.27 C
+ANISOU 827 CA LEU B 15 7340 6967 6692 -1109 425 143 C
+ATOM 828 C LEU B 15 -21.290 -10.308 -20.860 1.00 53.66 C
+ANISOU 828 C LEU B 15 7166 6692 6529 -812 384 148 C
+ATOM 829 O LEU B 15 -22.039 -10.720 -19.940 1.00 50.69 O
+ANISOU 829 O LEU B 15 6774 6269 6216 -671 324 88 O
+ATOM 830 CB LEU B 15 -18.948 -10.454 -20.044 1.00 57.82 C
+ANISOU 830 CB LEU B 15 7356 7605 7007 -1128 426 93 C
+ATOM 831 CG LEU B 15 -18.440 -11.420 -21.099 1.00 63.30 C
+ANISOU 831 CG LEU B 15 7878 8524 7650 -1015 495 130 C
+ATOM 832 CD1 LEU B 15 -17.756 -10.666 -22.216 1.00 63.58 C
+ANISOU 832 CD1 LEU B 15 7943 8622 7594 -1222 602 221 C
+ATOM 833 CD2 LEU B 15 -17.443 -12.372 -20.490 1.00 65.97 C
+ANISOU 833 CD2 LEU B 15 7922 9161 7982 -958 487 79 C
+ATOM 834 N GLU B 16 -21.532 -10.510 -22.157 1.00 47.63 N
+ANISOU 834 N GLU B 16 6447 5937 5713 -745 415 221 N
+ATOM 835 CA GLU B 16 -22.664 -11.304 -22.654 1.00 45.67 C
+ANISOU 835 CA GLU B 16 6218 5656 5479 -515 358 230 C
+ATOM 836 C GLU B 16 -22.099 -12.584 -23.254 1.00 48.61 C
+ANISOU 836 C GLU B 16 6436 6232 5799 -443 384 205 C
+ATOM 837 O GLU B 16 -21.055 -12.553 -23.930 1.00 46.18 O
+ANISOU 837 O GLU B 16 6067 6070 5407 -536 474 229 O
+ATOM 838 CB GLU B 16 -23.451 -10.553 -23.698 1.00 48.11 C
+ANISOU 838 CB GLU B 16 6731 5809 5738 -476 346 328 C
+ATOM 839 CG GLU B 16 -24.832 -11.113 -24.032 1.00 53.37 C
+ANISOU 839 CG GLU B 16 7413 6439 6424 -265 251 343 C
+ATOM 840 CD GLU B 16 -25.747 -10.126 -24.829 1.00 57.72 C
+ANISOU 840 CD GLU B 16 8169 6829 6932 -188 209 453 C
+ATOM 841 OE1 GLU B 16 -26.936 -9.937 -24.446 1.00 69.98 O
+ANISOU 841 OE1 GLU B 16 9737 8308 8544 -25 134 464 O
+ATOM 842 OE2 GLU B 16 -25.279 -9.506 -25.809 1.00 71.51 O
+ANISOU 842 OE2 GLU B 16 10058 8536 8577 -278 255 541 O
+ATOM 843 N VAL B 17 -22.770 -13.706 -22.978 1.00 44.60 N
+ANISOU 843 N VAL B 17 5878 5736 5329 -281 315 156 N
+ATOM 844 CA VAL B 17 -22.304 -14.976 -23.436 1.00 46.75 C
+ANISOU 844 CA VAL B 17 6070 6143 5548 -182 330 114 C
+ATOM 845 C VAL B 17 -23.463 -15.746 -23.995 1.00 45.90 C
+ANISOU 845 C VAL B 17 6061 5952 5427 -66 243 110 C
+ATOM 846 O VAL B 17 -24.614 -15.485 -23.683 1.00 43.95 O
+ANISOU 846 O VAL B 17 5860 5598 5240 -49 164 134 O
+ATOM 847 CB VAL B 17 -21.605 -15.796 -22.302 1.00 47.60 C
+ANISOU 847 CB VAL B 17 6021 6360 5702 -132 323 46 C
+ATOM 848 CG1 VAL B 17 -20.698 -14.897 -21.492 1.00 51.12 C
+ANISOU 848 CG1 VAL B 17 6363 6888 6173 -288 361 47 C
+ATOM 849 CG2 VAL B 17 -22.618 -16.422 -21.353 1.00 49.09 C
+ANISOU 849 CG2 VAL B 17 6236 6442 5970 -53 227 18 C
+ATOM 850 N GLU B 18 -23.109 -16.745 -24.776 1.00 46.07 N
+ANISOU 850 N GLU B 18 6102 6043 5357 16 260 72 N
+ATOM 851 CA GLU B 18 -24.020 -17.745 -25.270 1.00 49.63 C
+ANISOU 851 CA GLU B 18 6660 6424 5772 95 165 41 C
+ATOM 852 C GLU B 18 -24.215 -18.851 -24.218 1.00 44.35 C
+ANISOU 852 C GLU B 18 5956 5714 5177 154 106 -15 C
+ATOM 853 O GLU B 18 -23.267 -19.284 -23.560 1.00 51.13 O
+ANISOU 853 O GLU B 18 6734 6641 6052 214 157 -53 O
+ATOM 854 CB GLU B 18 -23.469 -18.355 -26.555 1.00 50.78 C
+ANISOU 854 CB GLU B 18 6901 6634 5756 163 218 4 C
+ATOM 855 CG GLU B 18 -23.996 -17.686 -27.802 1.00 68.77 C
+ANISOU 855 CG GLU B 18 9305 8898 7926 113 200 68 C
+ATOM 856 CD GLU B 18 -23.835 -18.551 -29.075 1.00 88.05 C
+ANISOU 856 CD GLU B 18 11901 11375 10178 191 210 8 C
+ATOM 857 OE1 GLU B 18 -22.896 -19.410 -29.126 1.00 81.31 O
+ANISOU 857 OE1 GLU B 18 11040 10592 9262 305 301 -77 O
+ATOM 858 OE2 GLU B 18 -24.664 -18.355 -30.020 1.00 95.29 O
+ANISOU 858 OE2 GLU B 18 12955 12254 10995 158 122 45 O
+ATOM 859 N CYS B 19 -25.445 -19.302 -24.075 1.00 41.64 N
+ANISOU 859 N CYS B 19 5672 5279 4869 130 -6 -8 N
+ATOM 860 CA CYS B 19 -25.763 -20.344 -23.133 1.00 45.79 C
+ANISOU 860 CA CYS B 19 6202 5746 5449 144 -63 -39 C
+ATOM 861 C CYS B 19 -26.882 -21.159 -23.766 1.00 46.84 C
+ANISOU 861 C CYS B 19 6462 5798 5535 89 -183 -46 C
+ATOM 862 O CYS B 19 -27.984 -20.631 -23.986 1.00 45.31 O
+ANISOU 862 O CYS B 19 6227 5622 5365 10 -256 7 O
+ATOM 863 CB CYS B 19 -26.236 -19.742 -21.802 1.00 44.81 C
+ANISOU 863 CB CYS B 19 5955 5628 5442 93 -68 2 C
+ATOM 864 SG CYS B 19 -26.514 -21.029 -20.541 1.00 44.98 S
+ANISOU 864 SG CYS B 19 5996 5591 5503 93 -120 -8 S
+ATOM 865 N ASP B 20 -26.627 -22.429 -24.061 1.00 46.35 N
+ANISOU 865 N ASP B 20 6561 5651 5398 132 -213 -114 N
+ATOM 866 CA ASP B 20 -27.710 -23.303 -24.531 1.00 48.89 C
+ANISOU 866 CA ASP B 20 7032 5874 5668 19 -349 -130 C
+ATOM 867 C ASP B 20 -28.747 -23.474 -23.465 1.00 47.10 C
+ANISOU 867 C ASP B 20 6711 5635 5547 -116 -420 -68 C
+ATOM 868 O ASP B 20 -28.472 -23.214 -22.296 1.00 47.38 O
+ANISOU 868 O ASP B 20 6628 5699 5673 -83 -357 -35 O
+ATOM 869 CB ASP B 20 -27.195 -24.650 -25.016 1.00 49.61 C
+ANISOU 869 CB ASP B 20 7385 5821 5642 92 -366 -229 C
+ATOM 870 CG ASP B 20 -26.366 -24.538 -26.278 1.00 56.74 C
+ANISOU 870 CG ASP B 20 8391 6766 6398 224 -291 -299 C
+ATOM 871 OD1 ASP B 20 -26.482 -23.537 -27.079 1.00 61.65 O
+ANISOU 871 OD1 ASP B 20 8935 7508 6978 194 -270 -261 O
+ATOM 872 OD2 ASP B 20 -25.587 -25.487 -26.498 1.00 64.45 O
+ANISOU 872 OD2 ASP B 20 9551 7653 7283 379 -246 -389 O
+ATOM 873 N ASP B 21 -29.960 -23.866 -23.882 1.00 51.35 N
+ANISOU 873 N ASP B 21 7285 6165 6058 -283 -552 -48 N
+ATOM 874 CA ASP B 21 -31.093 -24.022 -22.958 1.00 47.36 C
+ANISOU 874 CA ASP B 21 6647 5708 5637 -444 -612 27 C
+ATOM 875 C ASP B 21 -30.985 -25.153 -21.926 1.00 47.41 C
+ANISOU 875 C ASP B 21 6767 5582 5664 -512 -610 28 C
+ATOM 876 O ASP B 21 -31.828 -25.247 -21.025 1.00 45.27 O
+ANISOU 876 O ASP B 21 6372 5373 5454 -650 -626 105 O
+ATOM 877 CB ASP B 21 -32.458 -24.057 -23.695 1.00 51.66 C
+ANISOU 877 CB ASP B 21 7134 6351 6143 -629 -764 67 C
+ATOM 878 CG ASP B 21 -32.657 -25.259 -24.632 1.00 61.29 C
+ANISOU 878 CG ASP B 21 8623 7436 7229 -779 -899 -7 C
+ATOM 879 OD1 ASP B 21 -31.869 -26.233 -24.690 1.00 60.99 O
+ANISOU 879 OD1 ASP B 21 8860 7188 7124 -738 -879 -93 O
+ATOM 880 OD2 ASP B 21 -33.671 -25.198 -25.362 1.00 76.44 O
+ANISOU 880 OD2 ASP B 21 10482 9466 9093 -935 -1042 19 O
+ATOM 881 N ASP B 22 -29.986 -26.019 -22.094 1.00 45.76 N
+ANISOU 881 N ASP B 22 6801 5197 5386 -402 -588 -47 N
+ATOM 882 CA ASP B 22 -29.698 -27.103 -21.184 1.00 49.94 C
+ANISOU 882 CA ASP B 22 7499 5560 5913 -408 -587 -39 C
+ATOM 883 C ASP B 22 -28.367 -26.870 -20.478 1.00 51.81 C
+ANISOU 883 C ASP B 22 7692 5815 6179 -156 -468 -51 C
+ATOM 884 O ASP B 22 -27.852 -27.770 -19.904 1.00 47.85 O
+ANISOU 884 O ASP B 22 7360 5171 5649 -76 -467 -52 O
+ATOM 885 CB ASP B 22 -29.681 -28.442 -21.915 1.00 54.09 C
+ANISOU 885 CB ASP B 22 8395 5838 6318 -461 -680 -116 C
+ATOM 886 CG ASP B 22 -28.657 -28.512 -23.084 1.00 63.91 C
+ANISOU 886 CG ASP B 22 9803 7027 7451 -230 -637 -239 C
+ATOM 887 OD1 ASP B 22 -28.251 -27.429 -23.607 1.00 56.77 O
+ANISOU 887 OD1 ASP B 22 8699 6311 6557 -118 -561 -247 O
+ATOM 888 OD2 ASP B 22 -28.283 -29.685 -23.476 1.00 60.29 O
+ANISOU 888 OD2 ASP B 22 9703 6324 6879 -163 -672 -325 O
+ATOM 889 N VAL B 23 -27.833 -25.644 -20.499 1.00 44.07 N
+ANISOU 889 N VAL B 23 6485 5013 5246 -45 -380 -50 N
+ATOM 890 CA VAL B 23 -26.611 -25.310 -19.757 1.00 47.28 C
+ANISOU 890 CA VAL B 23 6793 5491 5677 138 -286 -54 C
+ATOM 891 C VAL B 23 -26.941 -24.305 -18.663 1.00 46.19 C
+ANISOU 891 C VAL B 23 6430 5488 5630 71 -247 9 C
+ATOM 892 O VAL B 23 -27.644 -23.285 -18.881 1.00 39.27 O
+ANISOU 892 O VAL B 23 5415 4705 4798 -11 -238 32 O
+ATOM 893 CB VAL B 23 -25.523 -24.795 -20.707 1.00 50.38 C
+ANISOU 893 CB VAL B 23 7146 5975 6020 297 -208 -117 C
+ATOM 894 CG1 VAL B 23 -24.342 -24.208 -19.967 1.00 46.76 C
+ANISOU 894 CG1 VAL B 23 6507 5665 5593 423 -122 -109 C
+ATOM 895 CG2 VAL B 23 -25.132 -25.955 -21.653 1.00 50.32 C
+ANISOU 895 CG2 VAL B 23 7401 5823 5893 416 -228 -198 C
+ATOM 896 N TYR B 24 -26.524 -24.659 -17.451 1.00 44.23 N
+ANISOU 896 N TYR B 24 6178 5236 5390 119 -233 41 N
+ATOM 897 CA TYR B 24 -26.635 -23.726 -16.362 1.00 42.32 C
+ANISOU 897 CA TYR B 24 5758 5120 5199 83 -187 78 C
+ATOM 898 C TYR B 24 -25.823 -22.471 -16.675 1.00 41.44 C
+ANISOU 898 C TYR B 24 5501 5135 5109 147 -123 34 C
+ATOM 899 O TYR B 24 -24.735 -22.521 -17.198 1.00 44.52 O
+ANISOU 899 O TYR B 24 5887 5563 5465 255 -98 -5 O
+ATOM 900 CB TYR B 24 -26.178 -24.336 -15.052 1.00 44.23 C
+ANISOU 900 CB TYR B 24 6041 5350 5413 135 -194 117 C
+ATOM 901 CG TYR B 24 -27.087 -25.431 -14.497 1.00 46.96 C
+ANISOU 901 CG TYR B 24 6541 5568 5732 16 -244 192 C
+ATOM 902 CD1 TYR B 24 -28.468 -25.241 -14.364 1.00 44.56 C
+ANISOU 902 CD1 TYR B 24 6173 5299 5459 -181 -243 243 C
+ATOM 903 CD2 TYR B 24 -26.538 -26.649 -14.079 1.00 51.68 C
+ANISOU 903 CD2 TYR B 24 7347 6023 6266 106 -288 224 C
+ATOM 904 CE1 TYR B 24 -29.285 -26.242 -13.871 1.00 49.24 C
+ANISOU 904 CE1 TYR B 24 6889 5801 6017 -343 -281 325 C
+ATOM 905 CE2 TYR B 24 -27.342 -27.663 -13.564 1.00 49.44 C
+ANISOU 905 CE2 TYR B 24 7249 5591 5944 -40 -332 309 C
+ATOM 906 CZ TYR B 24 -28.691 -27.448 -13.430 1.00 51.30 C
+ANISOU 906 CZ TYR B 24 7400 5881 6209 -289 -324 362 C
+ATOM 907 OH TYR B 24 -29.429 -28.459 -12.887 1.00 52.12 O
+ANISOU 907 OH TYR B 24 7677 5862 6265 -476 -359 461 O
+ATOM 908 N VAL B 25 -26.397 -21.353 -16.303 1.00 42.58 N
+ANISOU 908 N VAL B 25 5534 5344 5298 74 -91 48 N
+ATOM 909 CA VAL B 25 -25.870 -19.977 -16.515 1.00 43.51 C
+ANISOU 909 CA VAL B 25 5561 5536 5435 77 -35 18 C
+ATOM 910 C VAL B 25 -24.479 -19.883 -15.914 1.00 45.47 C
+ANISOU 910 C VAL B 25 5750 5871 5655 125 -13 -11 C
+ATOM 911 O VAL B 25 -23.583 -19.234 -16.483 1.00 42.02 O
+ANISOU 911 O VAL B 25 5255 5505 5205 121 24 -37 O
+ATOM 912 CB VAL B 25 -27.014 -19.053 -15.974 1.00 47.07 C
+ANISOU 912 CB VAL B 25 5964 5993 5928 22 -14 42 C
+ATOM 913 CG1 VAL B 25 -26.658 -17.985 -14.979 1.00 51.34 C
+ANISOU 913 CG1 VAL B 25 6467 6569 6468 14 35 10 C
+ATOM 914 CG2 VAL B 25 -27.951 -18.612 -17.124 1.00 50.07 C
+ANISOU 914 CG2 VAL B 25 6347 6348 6328 11 -32 68 C
+ATOM 915 N LEU B 26 -24.262 -20.562 -14.781 1.00 42.91 N
+ANISOU 915 N LEU B 26 5432 5567 5305 159 -44 3 N
+ATOM 916 CA LEU B 26 -22.937 -20.508 -14.120 1.00 44.21 C
+ANISOU 916 CA LEU B 26 5508 5860 5427 214 -52 -16 C
+ATOM 917 C LEU B 26 -21.873 -21.156 -15.044 1.00 43.16 C
+ANISOU 917 C LEU B 26 5348 5786 5263 347 -46 -31 C
+ATOM 918 O LEU B 26 -20.782 -20.644 -15.204 1.00 41.77 O
+ANISOU 918 O LEU B 26 5032 5771 5066 355 -19 -54 O
+ATOM 919 CB LEU B 26 -22.973 -21.227 -12.757 1.00 43.87 C
+ANISOU 919 CB LEU B 26 5503 5824 5338 252 -103 21 C
+ATOM 920 CG LEU B 26 -21.633 -21.303 -12.009 1.00 51.12 C
+ANISOU 920 CG LEU B 26 6319 6909 6194 330 -147 15 C
+ATOM 921 CD1 LEU B 26 -20.989 -19.928 -11.865 1.00 47.47 C
+ANISOU 921 CD1 LEU B 26 5717 6587 5732 203 -127 -41 C
+ATOM 922 CD2 LEU B 26 -21.802 -21.989 -10.650 1.00 53.81 C
+ANISOU 922 CD2 LEU B 26 6734 7244 6465 368 -206 70 C
+ATOM 923 N ASP B 27 -22.221 -22.283 -15.633 1.00 44.33 N
+ANISOU 923 N ASP B 27 5638 5809 5394 443 -66 -21 N
+ATOM 924 CA ASP B 27 -21.332 -23.028 -16.510 1.00 46.01 C
+ANISOU 924 CA ASP B 27 5876 6049 5554 621 -47 -49 C
+ATOM 925 C ASP B 27 -20.956 -22.226 -17.766 1.00 49.22 C
+ANISOU 925 C ASP B 27 6200 6549 5953 583 32 -86 C
+ATOM 926 O ASP B 27 -19.802 -22.149 -18.106 1.00 50.44 O
+ANISOU 926 O ASP B 27 6223 6878 6063 680 86 -104 O
+ATOM 927 CB ASP B 27 -21.974 -24.337 -16.843 1.00 48.69 C
+ANISOU 927 CB ASP B 27 6461 6173 5864 695 -93 -45 C
+ATOM 928 CG ASP B 27 -22.021 -25.293 -15.605 1.00 61.91 C
+ANISOU 928 CG ASP B 27 8247 7761 7515 764 -163 12 C
+ATOM 929 OD1 ASP B 27 -21.027 -25.395 -14.870 1.00 72.00 O
+ANISOU 929 OD1 ASP B 27 9424 9171 8760 907 -177 30 O
+ATOM 930 OD2 ASP B 27 -23.034 -25.974 -15.376 1.00 65.76 O
+ANISOU 930 OD2 ASP B 27 8922 8059 8004 668 -211 51 O
+ATOM 931 N ALA B 28 -21.929 -21.573 -18.394 1.00 48.34 N
+ANISOU 931 N ALA B 28 6146 6346 5874 438 40 -82 N
+ATOM 932 CA ALA B 28 -21.708 -20.761 -19.556 1.00 48.04 C
+ANISOU 932 CA ALA B 28 6072 6368 5811 384 108 -93 C
+ATOM 933 C ALA B 28 -20.772 -19.641 -19.163 1.00 49.27 C
+ANISOU 933 C ALA B 28 6043 6698 5979 293 162 -84 C
+ATOM 934 O ALA B 28 -19.857 -19.319 -19.908 1.00 48.19 O
+ANISOU 934 O ALA B 28 5813 6707 5789 295 240 -88 O
+ATOM 935 CB ALA B 28 -23.039 -20.183 -20.056 1.00 52.12 C
+ANISOU 935 CB ALA B 28 6682 6758 6362 258 77 -68 C
+ATOM 936 N ALA B 29 -20.986 -19.058 -17.979 1.00 46.38 N
+ANISOU 936 N ALA B 29 5631 6327 5664 194 124 -74 N
+ATOM 937 CA ALA B 29 -20.076 -18.026 -17.489 1.00 48.20 C
+ANISOU 937 CA ALA B 29 5715 6706 5890 65 150 -79 C
+ATOM 938 C ALA B 29 -18.630 -18.516 -17.392 1.00 50.01 C
+ANISOU 938 C ALA B 29 5752 7184 6064 154 166 -86 C
+ATOM 939 O ALA B 29 -17.691 -17.860 -17.830 1.00 49.30 O
+ANISOU 939 O ALA B 29 5514 7276 5941 54 227 -80 O
+ATOM 940 CB ALA B 29 -20.518 -17.475 -16.122 1.00 48.24 C
+ANISOU 940 CB ALA B 29 5740 6659 5928 -29 96 -90 C
+ATOM 941 N GLU B 30 -18.455 -19.668 -16.787 1.00 50.74 N
+ANISOU 941 N GLU B 30 5842 7297 6140 344 111 -87 N
+ATOM 942 CA GLU B 30 -17.125 -20.211 -16.573 1.00 53.52 C
+ANISOU 942 CA GLU B 30 5996 7905 6434 495 109 -84 C
+ATOM 943 C GLU B 30 -16.487 -20.582 -17.882 1.00 55.58 C
+ANISOU 943 C GLU B 30 6200 8279 6639 634 213 -95 C
+ATOM 944 O GLU B 30 -15.310 -20.345 -18.062 1.00 53.30 O
+ANISOU 944 O GLU B 30 5662 8284 6302 650 267 -87 O
+ATOM 945 CB GLU B 30 -17.245 -21.433 -15.659 1.00 55.76 C
+ANISOU 945 CB GLU B 30 6364 8121 6701 708 18 -66 C
+ATOM 946 CG GLU B 30 -17.599 -20.966 -14.244 1.00 60.54 C
+ANISOU 946 CG GLU B 30 6973 8707 7322 564 -69 -52 C
+ATOM 947 CD GLU B 30 -17.847 -22.100 -13.266 1.00 67.44 C
+ANISOU 947 CD GLU B 30 7969 9491 8161 734 -157 -9 C
+ATOM 948 OE1 GLU B 30 -18.209 -23.248 -13.665 1.00 66.53 O
+ANISOU 948 OE1 GLU B 30 8035 9206 8037 915 -159 8 O
+ATOM 949 OE2 GLU B 30 -17.669 -21.807 -12.069 1.00 71.86 O
+ANISOU 949 OE2 GLU B 30 8471 10144 8689 666 -231 5 O
+ATOM 950 N GLU B 31 -17.279 -21.156 -18.796 1.00 55.65 N
+ANISOU 950 N GLU B 31 6432 8073 6637 723 241 -115 N
+ATOM 951 CA GLU B 31 -16.811 -21.477 -20.146 1.00 59.63 C
+ANISOU 951 CA GLU B 31 6942 8655 7058 853 350 -141 C
+ATOM 952 C GLU B 31 -16.291 -20.194 -20.865 1.00 55.72 C
+ANISOU 952 C GLU B 31 6283 8348 6540 632 457 -115 C
+ATOM 953 O GLU B 31 -15.355 -20.248 -21.599 1.00 58.65 O
+ANISOU 953 O GLU B 31 6505 8951 6826 714 569 -117 O
+ATOM 954 CB GLU B 31 -17.945 -22.145 -20.947 1.00 70.50 C
+ANISOU 954 CB GLU B 31 8629 9739 8417 905 329 -174 C
+ATOM 955 CG GLU B 31 -17.483 -23.157 -21.980 1.00 89.10 C
+ANISOU 955 CG GLU B 31 11093 12105 10654 1169 401 -233 C
+ATOM 956 CD GLU B 31 -16.540 -24.196 -21.373 1.00108.88 C
+ANISOU 956 CD GLU B 31 13534 14713 13120 1482 395 -248 C
+ATOM 957 OE1 GLU B 31 -16.868 -24.715 -20.275 1.00122.63 O
+ANISOU 957 OE1 GLU B 31 15352 16322 14918 1517 281 -221 O
+ATOM 958 OE2 GLU B 31 -15.461 -24.475 -21.968 1.00106.25 O
+ANISOU 958 OE2 GLU B 31 13067 14613 12689 1708 509 -276 O
+ATOM 959 N ALA B 32 -16.902 -19.037 -20.607 1.00 54.88 N
+ANISOU 959 N ALA B 32 6217 8134 6498 356 427 -85 N
+ATOM 960 CA ALA B 32 -16.492 -17.745 -21.179 1.00 59.73 C
+ANISOU 960 CA ALA B 32 6747 8857 7089 106 511 -44 C
+ATOM 961 C ALA B 32 -15.343 -17.016 -20.467 1.00 63.02 C
+ANISOU 961 C ALA B 32 6892 9546 7504 -75 520 -22 C
+ATOM 962 O ALA B 32 -14.998 -15.927 -20.905 1.00 63.67 O
+ANISOU 962 O ALA B 32 6934 9694 7561 -332 587 19 O
+ATOM 963 CB ALA B 32 -17.705 -16.806 -21.263 1.00 56.13 C
+ANISOU 963 CB ALA B 32 6511 8123 6691 -78 469 -20 C
+ATOM 964 N GLY B 33 -14.771 -17.574 -19.387 1.00 61.55 N
+ANISOU 964 N GLY B 33 6539 9514 7332 31 442 -42 N
+ATOM 965 CA GLY B 33 -13.600 -16.980 -18.707 1.00 63.73 C
+ANISOU 965 CA GLY B 33 6518 10110 7586 -146 423 -23 C
+ATOM 966 C GLY B 33 -13.895 -16.058 -17.525 1.00 66.50 C
+ANISOU 966 C GLY B 33 6927 10352 7985 -414 308 -38 C
+ATOM 967 O GLY B 33 -13.016 -15.338 -17.073 1.00 78.05 O
+ANISOU 967 O GLY B 33 8192 12044 9417 -656 282 -30 O
+ATOM 968 N ILE B 34 -15.129 -16.076 -17.028 1.00 67.68 N
+ANISOU 968 N ILE B 34 7348 10169 8195 -380 241 -66 N
+ATOM 969 CA ILE B 34 -15.538 -15.285 -15.866 1.00 69.74 C
+ANISOU 969 CA ILE B 34 7714 10302 8481 -573 147 -99 C
+ATOM 970 C ILE B 34 -15.518 -16.184 -14.636 1.00 64.98 C
+ANISOU 970 C ILE B 34 7061 9759 7866 -396 34 -118 C
+ATOM 971 O ILE B 34 -15.991 -17.333 -14.669 1.00 60.93 O
+ANISOU 971 O ILE B 34 6620 9161 7366 -127 24 -105 O
+ATOM 972 CB ILE B 34 -17.001 -14.806 -15.975 1.00 71.51 C
+ANISOU 972 CB ILE B 34 8249 10155 8763 -593 156 -112 C
+ATOM 973 CG1 ILE B 34 -17.270 -14.074 -17.281 1.00 80.00 C
+ANISOU 973 CG1 ILE B 34 9439 11114 9843 -696 254 -73 C
+ATOM 974 CG2 ILE B 34 -17.370 -13.876 -14.827 1.00 74.50 C
+ANISOU 974 CG2 ILE B 34 8756 10405 9144 -770 88 -161 C
+ATOM 975 CD1 ILE B 34 -18.763 -13.913 -17.553 1.00 74.26 C
+ANISOU 975 CD1 ILE B 34 8970 10076 9167 -610 251 -68 C
+ATOM 976 N ASP B 35 -15.021 -15.649 -13.537 1.00 61.68 N
+ANISOU 976 N ASP B 35 6562 9464 7408 -566 -59 -146 N
+ATOM 977 CA ASP B 35 -15.019 -16.414 -12.290 1.00 75.53 C
+ANISOU 977 CA ASP B 35 8296 11276 9122 -414 -177 -152 C
+ATOM 978 C ASP B 35 -16.098 -15.810 -11.437 1.00 67.96 C
+ANISOU 978 C ASP B 35 7599 10051 8171 -525 -210 -201 C
+ATOM 979 O ASP B 35 -16.004 -14.664 -11.028 1.00 71.36 O
+ANISOU 979 O ASP B 35 8091 10448 8572 -786 -232 -255 O
+ATOM 980 CB ASP B 35 -13.639 -16.434 -11.587 1.00 82.96 C
+ANISOU 980 CB ASP B 35 8931 12609 9978 -475 -282 -144 C
+ATOM 981 CG ASP B 35 -12.583 -17.205 -12.400 1.00 94.51 C
+ANISOU 981 CG ASP B 35 10096 14387 11425 -270 -232 -89 C
+ATOM 982 OD1 ASP B 35 -12.806 -18.403 -12.759 1.00 96.53 O
+ANISOU 982 OD1 ASP B 35 10403 14579 11694 79 -201 -57 O
+ATOM 983 OD2 ASP B 35 -11.544 -16.586 -12.714 1.00 99.59 O
+ANISOU 983 OD2 ASP B 35 10468 15337 12033 -469 -215 -78 O
+ATOM 984 N LEU B 36 -17.154 -16.583 -11.237 1.00 61.63 N
+ANISOU 984 N LEU B 36 6966 9051 7399 -328 -200 -183 N
+ATOM 985 CA LEU B 36 -18.261 -16.213 -10.383 1.00 56.78 C
+ANISOU 985 CA LEU B 36 6568 8229 6777 -371 -208 -218 C
+ATOM 986 C LEU B 36 -18.245 -17.129 -9.153 1.00 52.62 C
+ANISOU 986 C LEU B 36 6041 7780 6171 -238 -300 -192 C
+ATOM 987 O LEU B 36 -17.788 -18.261 -9.215 1.00 51.28 O
+ANISOU 987 O LEU B 36 5782 7714 5987 -45 -339 -130 O
+ATOM 988 CB LEU B 36 -19.602 -16.402 -11.121 1.00 60.32 C
+ANISOU 988 CB LEU B 36 7183 8425 7309 -276 -120 -195 C
+ATOM 989 CG LEU B 36 -19.852 -15.603 -12.408 1.00 57.54 C
+ANISOU 989 CG LEU B 36 6878 7960 7022 -360 -36 -197 C
+ATOM 990 CD1 LEU B 36 -21.213 -16.023 -13.015 1.00 57.02 C
+ANISOU 990 CD1 LEU B 36 6941 7702 7020 -235 11 -162 C
+ATOM 991 CD2 LEU B 36 -19.778 -14.120 -12.106 1.00 59.01 C
+ANISOU 991 CD2 LEU B 36 7159 8073 7187 -580 -26 -256 C
+ATOM 992 N PRO B 37 -18.782 -16.647 -8.045 1.00 49.77 N
+ANISOU 992 N PRO B 37 5814 7352 5742 -321 -326 -238 N
+ATOM 993 CA PRO B 37 -18.701 -17.404 -6.819 1.00 52.69 C
+ANISOU 993 CA PRO B 37 6200 7815 6003 -225 -415 -204 C
+ATOM 994 C PRO B 37 -19.633 -18.609 -6.877 1.00 53.75 C
+ANISOU 994 C PRO B 37 6445 7807 6169 -30 -373 -116 C
+ATOM 995 O PRO B 37 -20.659 -18.578 -7.575 1.00 52.82 O
+ANISOU 995 O PRO B 37 6420 7504 6142 -22 -275 -109 O
+ATOM 996 CB PRO B 37 -19.214 -16.410 -5.772 1.00 55.23 C
+ANISOU 996 CB PRO B 37 6682 8069 6232 -380 -415 -294 C
+ATOM 997 CG PRO B 37 -20.178 -15.544 -6.538 1.00 56.99 C
+ANISOU 997 CG PRO B 37 7035 8061 6556 -438 -287 -341 C
+ATOM 998 CD PRO B 37 -19.480 -15.359 -7.863 1.00 55.95 C
+ANISOU 998 CD PRO B 37 6768 7965 6526 -486 -269 -323 C
+ATOM 999 N TYR B 38 -19.264 -19.661 -6.164 1.00 51.10 N
+ANISOU 999 N TYR B 38 6105 7561 5748 112 -458 -39 N
+ATOM 1000 CA TYR B 38 -20.137 -20.809 -5.974 1.00 53.20 C
+ANISOU 1000 CA TYR B 38 6529 7673 6010 243 -434 55 C
+ATOM 1001 C TYR B 38 -19.656 -21.588 -4.747 1.00 54.18 C
+ANISOU 1001 C TYR B 38 6693 7909 5982 349 -548 134 C
+ATOM 1002 O TYR B 38 -18.582 -21.362 -4.322 1.00 49.82 O
+ANISOU 1002 O TYR B 38 6003 7570 5353 362 -654 116 O
+ATOM 1003 CB TYR B 38 -20.086 -21.734 -7.179 1.00 49.99 C
+ANISOU 1003 CB TYR B 38 6125 7167 5701 391 -407 104 C
+ATOM 1004 CG TYR B 38 -18.715 -22.275 -7.467 1.00 51.86 C
+ANISOU 1004 CG TYR B 38 6213 7579 5912 569 -486 127 C
+ATOM 1005 CD1 TYR B 38 -17.850 -21.585 -8.312 1.00 55.55 C
+ANISOU 1005 CD1 TYR B 38 6471 8204 6429 528 -464 64 C
+ATOM 1006 CD2 TYR B 38 -18.269 -23.505 -6.904 1.00 61.75 C
+ANISOU 1006 CD2 TYR B 38 7532 8850 7078 796 -577 225 C
+ATOM 1007 CE1 TYR B 38 -16.594 -22.086 -8.614 1.00 58.14 C
+ANISOU 1007 CE1 TYR B 38 6611 8752 6728 714 -515 89 C
+ATOM 1008 CE2 TYR B 38 -16.989 -24.012 -7.186 1.00 59.46 C
+ANISOU 1008 CE2 TYR B 38 7079 8753 6757 1025 -645 249 C
+ATOM 1009 CZ TYR B 38 -16.163 -23.294 -8.041 1.00 63.46 C
+ANISOU 1009 CZ TYR B 38 7329 9462 7319 985 -607 177 C
+ATOM 1010 OH TYR B 38 -14.891 -23.736 -8.343 1.00 72.30 O
+ANISOU 1010 OH TYR B 38 8229 10837 8402 1217 -652 201 O
+ATOM 1011 N SER B 39 -20.429 -22.569 -4.273 1.00 53.67 N
+ANISOU 1011 N SER B 39 6815 7706 5871 420 -534 237 N
+ATOM 1012 CA SER B 39 -19.980 -23.484 -3.243 1.00 53.24 C
+ANISOU 1012 CA SER B 39 6845 7718 5665 553 -645 347 C
+ATOM 1013 C SER B 39 -20.482 -24.911 -3.576 1.00 53.99 C
+ANISOU 1013 C SER B 39 7143 7585 5782 691 -631 477 C
+ATOM 1014 O SER B 39 -19.746 -25.715 -4.122 1.00 60.00 O
+ANISOU 1014 O SER B 39 7905 8323 6567 901 -692 520 O
+ATOM 1015 CB SER B 39 -20.438 -22.974 -1.880 1.00 54.47 C
+ANISOU 1015 CB SER B 39 7088 7945 5660 422 -647 339 C
+ATOM 1016 OG SER B 39 -19.961 -23.809 -0.856 1.00 58.10 O
+ANISOU 1016 OG SER B 39 7640 8485 5947 547 -768 457 O
+ATOM 1017 N CYS B 40 -21.745 -25.188 -3.303 1.00 53.52 N
+ANISOU 1017 N CYS B 40 7259 7360 5714 563 -542 532 N
+ATOM 1018 CA CYS B 40 -22.341 -26.502 -3.494 1.00 52.54 C
+ANISOU 1018 CA CYS B 40 7371 6999 5591 607 -533 661 C
+ATOM 1019 C CYS B 40 -22.554 -26.894 -4.990 1.00 54.29 C
+ANISOU 1019 C CYS B 40 7615 7039 5972 636 -494 621 C
+ATOM 1020 O CYS B 40 -22.599 -28.079 -5.354 1.00 56.18 O
+ANISOU 1020 O CYS B 40 8070 7067 6206 733 -528 702 O
+ATOM 1021 CB CYS B 40 -23.706 -26.493 -2.758 1.00 53.96 C
+ANISOU 1021 CB CYS B 40 7670 7122 5708 390 -431 727 C
+ATOM 1022 SG CYS B 40 -25.014 -25.506 -3.570 1.00 54.05 S
+ANISOU 1022 SG CYS B 40 7540 7122 5874 175 -270 621 S
+ATOM 1023 N ARG B 41 -22.745 -25.881 -5.830 1.00 55.21 N
+ANISOU 1023 N ARG B 41 7548 7218 6210 539 -423 498 N
+ATOM 1024 CA ARG B 41 -23.100 -26.036 -7.243 1.00 57.45 C
+ANISOU 1024 CA ARG B 41 7842 7361 6623 525 -377 449 C
+ATOM 1025 C ARG B 41 -24.289 -26.944 -7.426 1.00 53.39 C
+ANISOU 1025 C ARG B 41 7544 6624 6118 400 -351 531 C
+ATOM 1026 O ARG B 41 -24.325 -27.732 -8.363 1.00 57.10 O
+ANISOU 1026 O ARG B 41 8153 6914 6628 449 -373 531 O
+ATOM 1027 CB ARG B 41 -21.926 -26.568 -8.054 1.00 57.25 C
+ANISOU 1027 CB ARG B 41 7805 7331 6614 765 -433 421 C
+ATOM 1028 CG ARG B 41 -20.730 -25.656 -8.128 1.00 63.18 C
+ANISOU 1028 CG ARG B 41 8288 8346 7369 845 -452 341 C
+ATOM 1029 CD ARG B 41 -19.678 -26.364 -8.976 1.00 72.83 C
+ANISOU 1029 CD ARG B 41 9491 9584 8595 1112 -481 331 C
+ATOM 1030 NE ARG B 41 -20.005 -26.268 -10.416 1.00 66.24 N
+ANISOU 1030 NE ARG B 41 8672 8642 7853 1080 -399 256 N
+ATOM 1031 CZ ARG B 41 -19.501 -25.337 -11.206 1.00 60.12 C
+ANISOU 1031 CZ ARG B 41 7679 8033 7131 1040 -342 173 C
+ATOM 1032 NH1 ARG B 41 -18.683 -24.440 -10.693 1.00 58.08 N
+ANISOU 1032 NH1 ARG B 41 7175 8038 6852 995 -361 150 N
+ATOM 1033 NH2 ARG B 41 -19.820 -25.271 -12.489 1.00 59.63 N
+ANISOU 1033 NH2 ARG B 41 7655 7877 7124 1014 -273 118 N
+ATOM 1034 N ALA B 42 -25.254 -26.842 -6.528 1.00 50.75 N
+ANISOU 1034 N ALA B 42 7240 6313 5731 225 -301 598 N
+ATOM 1035 CA ALA B 42 -26.322 -27.854 -6.466 1.00 55.82 C
+ANISOU 1035 CA ALA B 42 8087 6773 6348 63 -286 714 C
+ATOM 1036 C ALA B 42 -27.689 -27.296 -6.092 1.00 53.85 C
+ANISOU 1036 C ALA B 42 7723 6630 6105 -178 -176 738 C
+ATOM 1037 O ALA B 42 -28.646 -28.060 -5.838 1.00 55.78 O
+ANISOU 1037 O ALA B 42 8091 6791 6308 -370 -150 854 O
+ATOM 1038 CB ALA B 42 -25.919 -28.950 -5.457 1.00 58.15 C
+ANISOU 1038 CB ALA B 42 8635 6960 6496 141 -354 856 C
+ATOM 1039 N GLY B 43 -27.766 -25.976 -6.007 1.00 52.94 N
+ANISOU 1039 N GLY B 43 7380 6706 6028 -168 -108 636 N
+ATOM 1040 CA GLY B 43 -29.019 -25.311 -5.704 1.00 57.58 C
+ANISOU 1040 CA GLY B 43 7828 7426 6621 -321 9 641 C
+ATOM 1041 C GLY B 43 -29.393 -25.157 -4.247 1.00 56.47 C
+ANISOU 1041 C GLY B 43 7699 7426 6330 -371 90 705 C
+ATOM 1042 O GLY B 43 -30.490 -24.676 -3.919 1.00 61.40 O
+ANISOU 1042 O GLY B 43 8200 8190 6936 -473 214 718 O
+ATOM 1043 N SER B 44 -28.507 -25.552 -3.359 1.00 57.15 N
+ANISOU 1043 N SER B 44 7922 7502 6288 -282 25 748 N
+ATOM 1044 CA SER B 44 -28.864 -25.573 -1.947 1.00 60.58 C
+ANISOU 1044 CA SER B 44 8415 8061 6539 -340 95 828 C
+ATOM 1045 C SER B 44 -28.070 -24.590 -1.083 1.00 55.02 C
+ANISOU 1045 C SER B 44 7667 7512 5724 -218 81 721 C
+ATOM 1046 O SER B 44 -27.939 -24.770 0.117 1.00 56.43 O
+ANISOU 1046 O SER B 44 7952 7776 5712 -219 84 785 O
+ATOM 1047 CB SER B 44 -28.724 -26.997 -1.455 1.00 64.11 C
+ANISOU 1047 CB SER B 44 9118 8363 6875 -384 27 1009 C
+ATOM 1048 OG SER B 44 -27.369 -27.403 -1.576 1.00 72.90 O
+ANISOU 1048 OG SER B 44 10341 9378 7978 -177 -128 997 O
+ATOM 1049 N CYS B 45 -27.538 -23.526 -1.680 1.00 50.30 N
+ANISOU 1049 N CYS B 45 6932 6949 5228 -137 60 559 N
+ATOM 1050 CA CYS B 45 -26.911 -22.490 -0.877 1.00 49.85 C
+ANISOU 1050 CA CYS B 45 6852 7028 5060 -85 47 441 C
+ATOM 1051 C CYS B 45 -27.172 -21.136 -1.520 1.00 51.33 C
+ANISOU 1051 C CYS B 45 6911 7228 5361 -83 119 279 C
+ATOM 1052 O CYS B 45 -27.967 -21.005 -2.440 1.00 55.12 O
+ANISOU 1052 O CYS B 45 7307 7650 5984 -106 191 278 O
+ATOM 1053 CB CYS B 45 -25.390 -22.791 -0.653 1.00 48.86 C
+ANISOU 1053 CB CYS B 45 6762 6928 4874 20 -134 439 C
+ATOM 1054 SG CYS B 45 -24.160 -22.368 -1.931 1.00 53.35 S
+ANISOU 1054 SG CYS B 45 7176 7476 5616 105 -244 330 S
+ATOM 1055 N SER B 46 -26.488 -20.125 -1.034 1.00 50.33 N
+ANISOU 1055 N SER B 46 6793 7170 5158 -63 86 148 N
+ATOM 1056 CA SER B 46 -26.687 -18.804 -1.525 1.00 53.49 C
+ANISOU 1056 CA SER B 46 7146 7540 5638 -62 151 0 C
+ATOM 1057 C SER B 46 -25.436 -18.250 -2.234 1.00 51.56 C
+ANISOU 1057 C SER B 46 6851 7262 5478 -77 28 -89 C
+ATOM 1058 O SER B 46 -25.397 -17.049 -2.580 1.00 51.57 O
+ANISOU 1058 O SER B 46 6861 7210 5522 -105 60 -215 O
+ATOM 1059 CB SER B 46 -27.077 -17.908 -0.321 1.00 54.94 C
+ANISOU 1059 CB SER B 46 7434 7804 5634 -60 242 -100 C
+ATOM 1060 OG SER B 46 -25.958 -17.693 0.515 1.00 59.45 O
+ANISOU 1060 OG SER B 46 8091 8449 6049 -97 114 -164 O
+ATOM 1061 N SER B 47 -24.417 -19.082 -2.465 1.00 50.22 N
+ANISOU 1061 N SER B 47 6631 7124 5322 -52 -104 -22 N
+ATOM 1062 CA SER B 47 -23.104 -18.545 -2.910 1.00 53.80 C
+ANISOU 1062 CA SER B 47 6993 7634 5811 -82 -216 -100 C
+ATOM 1063 C SER B 47 -23.102 -17.974 -4.299 1.00 49.57 C
+ANISOU 1063 C SER B 47 6378 7002 5454 -106 -173 -147 C
+ATOM 1064 O SER B 47 -22.409 -17.004 -4.556 1.00 47.90 O
+ANISOU 1064 O SER B 47 6131 6812 5254 -198 -204 -242 O
+ATOM 1065 CB SER B 47 -21.985 -19.587 -2.863 1.00 55.00 C
+ANISOU 1065 CB SER B 47 7072 7893 5931 4 -358 -10 C
+ATOM 1066 OG SER B 47 -21.799 -19.986 -1.539 1.00 67.17 O
+ANISOU 1066 OG SER B 47 8697 9542 7281 24 -428 35 O
+ATOM 1067 N CYS B 48 -23.836 -18.597 -5.210 1.00 47.83 N
+ANISOU 1067 N CYS B 48 6142 6677 5355 -48 -112 -75 N
+ATOM 1068 CA CYS B 48 -23.825 -18.180 -6.626 1.00 44.63 C
+ANISOU 1068 CA CYS B 48 5671 6187 5098 -57 -82 -102 C
+ATOM 1069 C CYS B 48 -25.021 -17.249 -6.959 1.00 50.82 C
+ANISOU 1069 C CYS B 48 6502 6866 5939 -77 30 -146 C
+ATOM 1070 O CYS B 48 -25.428 -17.128 -8.127 1.00 51.63 O
+ANISOU 1070 O CYS B 48 6573 6888 6154 -61 61 -130 O
+ATOM 1071 CB CYS B 48 -23.944 -19.426 -7.480 1.00 41.68 C
+ANISOU 1071 CB CYS B 48 5279 5758 4800 24 -100 -7 C
+ATOM 1072 SG CYS B 48 -25.514 -20.250 -7.174 1.00 47.58 S
+ANISOU 1072 SG CYS B 48 6110 6423 5543 17 -32 87 S
+ATOM 1073 N ALA B 49 -25.604 -16.621 -5.943 1.00 49.42 N
+ANISOU 1073 N ALA B 49 6406 6702 5668 -83 90 -197 N
+ATOM 1074 CA ALA B 49 -26.803 -15.852 -6.145 1.00 47.37 C
+ANISOU 1074 CA ALA B 49 6180 6371 5446 -34 205 -227 C
+ATOM 1075 C ALA B 49 -26.501 -14.656 -7.025 1.00 46.14 C
+ANISOU 1075 C ALA B 49 6068 6096 5364 -55 208 -304 C
+ATOM 1076 O ALA B 49 -25.486 -13.952 -6.837 1.00 47.19 O
+ANISOU 1076 O ALA B 49 6266 6210 5452 -154 153 -386 O
+ATOM 1077 CB ALA B 49 -27.369 -15.388 -4.811 1.00 48.90 C
+ANISOU 1077 CB ALA B 49 6469 6616 5493 -1 286 -284 C
+ATOM 1078 N GLY B 50 -27.414 -14.412 -7.959 1.00 46.35 N
+ANISOU 1078 N GLY B 50 6066 6052 5491 20 266 -269 N
+ATOM 1079 CA GLY B 50 -27.486 -13.112 -8.644 1.00 47.72 C
+ANISOU 1079 CA GLY B 50 6340 6080 5709 42 296 -328 C
+ATOM 1080 C GLY B 50 -28.933 -12.665 -8.683 1.00 52.51 C
+ANISOU 1080 C GLY B 50 6951 6666 6333 212 397 -314 C
+ATOM 1081 O GLY B 50 -29.796 -13.183 -7.949 1.00 51.98 O
+ANISOU 1081 O GLY B 50 6805 6723 6220 284 461 -282 O
+ATOM 1082 N LYS B 51 -29.194 -11.690 -9.542 1.00 56.73 N
+ANISOU 1082 N LYS B 51 7570 7061 6924 284 413 -325 N
+ATOM 1083 CA LYS B 51 -30.512 -11.104 -9.670 1.00 58.00 C
+ANISOU 1083 CA LYS B 51 7730 7209 7099 498 500 -309 C
+ATOM 1084 C LYS B 51 -30.801 -10.888 -11.160 1.00 51.95 C
+ANISOU 1084 C LYS B 51 6929 6374 6435 547 454 -226 C
+ATOM 1085 O LYS B 51 -30.004 -10.302 -11.879 1.00 52.34 O
+ANISOU 1085 O LYS B 51 7113 6268 6503 462 408 -238 O
+ATOM 1086 CB LYS B 51 -30.496 -9.813 -8.890 1.00 62.10 C
+ANISOU 1086 CB LYS B 51 8498 7573 7524 591 570 -437 C
+ATOM 1087 CG LYS B 51 -31.824 -9.123 -8.706 1.00 71.92 C
+ANISOU 1087 CG LYS B 51 9764 8816 8744 885 686 -447 C
+ATOM 1088 CD LYS B 51 -31.618 -8.015 -7.667 1.00 84.43 C
+ANISOU 1088 CD LYS B 51 11656 10230 10191 959 758 -609 C
+ATOM 1089 CE LYS B 51 -32.841 -7.727 -6.792 1.00 94.36 C
+ANISOU 1089 CE LYS B 51 12897 11600 11354 1256 917 -653 C
+ATOM 1090 NZ LYS B 51 -33.550 -6.484 -7.218 1.00 96.90 N
+ANISOU 1090 NZ LYS B 51 13408 11730 11677 1566 985 -687 N
+ATOM 1091 N VAL B 52 -31.914 -11.423 -11.620 1.00 50.92 N
+ANISOU 1091 N VAL B 52 6608 6386 6353 653 460 -133 N
+ATOM 1092 CA VAL B 52 -32.367 -11.250 -12.978 1.00 51.68 C
+ANISOU 1092 CA VAL B 52 6658 6458 6518 721 403 -47 C
+ATOM 1093 C VAL B 52 -32.869 -9.817 -13.125 1.00 55.73 C
+ANISOU 1093 C VAL B 52 7340 6819 7014 951 455 -71 C
+ATOM 1094 O VAL B 52 -33.750 -9.385 -12.411 1.00 58.68 O
+ANISOU 1094 O VAL B 52 7692 7253 7351 1160 545 -97 O
+ATOM 1095 CB VAL B 52 -33.490 -12.237 -13.328 1.00 54.96 C
+ANISOU 1095 CB VAL B 52 6806 7103 6972 744 375 55 C
+ATOM 1096 CG1 VAL B 52 -34.003 -12.011 -14.775 1.00 52.68 C
+ANISOU 1096 CG1 VAL B 52 6472 6811 6730 819 290 142 C
+ATOM 1097 CG2 VAL B 52 -33.016 -13.669 -13.135 1.00 50.23 C
+ANISOU 1097 CG2 VAL B 52 6115 6592 6375 524 325 77 C
+ATOM 1098 N VAL B 53 -32.237 -9.071 -14.009 1.00 58.89 N
+ANISOU 1098 N VAL B 53 7936 7012 7426 915 408 -62 N
+ATOM 1099 CA VAL B 53 -32.688 -7.736 -14.395 1.00 62.70 C
+ANISOU 1099 CA VAL B 53 8634 7295 7891 1137 434 -54 C
+ATOM 1100 C VAL B 53 -33.762 -7.758 -15.502 1.00 61.16 C
+ANISOU 1100 C VAL B 53 8295 7206 7737 1336 378 79 C
+ATOM 1101 O VAL B 53 -34.656 -6.932 -15.513 1.00 69.08 O
+ANISOU 1101 O VAL B 53 9355 8170 8723 1636 413 102 O
+ATOM 1102 CB VAL B 53 -31.492 -6.995 -14.961 1.00 67.39 C
+ANISOU 1102 CB VAL B 53 9512 7623 8467 954 398 -72 C
+ATOM 1103 CG1 VAL B 53 -31.901 -5.593 -15.416 1.00 75.74 C
+ANISOU 1103 CG1 VAL B 53 10871 8410 9495 1168 416 -46 C
+ATOM 1104 CG2 VAL B 53 -30.375 -6.982 -13.920 1.00 67.44 C
+ANISOU 1104 CG2 VAL B 53 9626 7572 8426 722 423 -198 C
+ATOM 1105 N SER B 54 -33.617 -8.645 -16.484 1.00 54.51 N
+ANISOU 1105 N SER B 54 7294 6485 6931 1182 280 163 N
+ATOM 1106 CA SER B 54 -34.604 -8.785 -17.528 1.00 57.42 C
+ANISOU 1106 CA SER B 54 7508 6990 7316 1325 196 285 C
+ATOM 1107 C SER B 54 -34.480 -10.128 -18.163 1.00 49.00 C
+ANISOU 1107 C SER B 54 6241 6104 6271 1103 103 329 C
+ATOM 1108 O SER B 54 -33.420 -10.732 -18.126 1.00 48.61 O
+ANISOU 1108 O SER B 54 6245 6001 6221 872 101 279 O
+ATOM 1109 CB SER B 54 -34.457 -7.676 -18.615 1.00 67.92 C
+ANISOU 1109 CB SER B 54 9097 8093 8615 1441 149 357 C
+ATOM 1110 OG SER B 54 -33.212 -7.732 -19.310 1.00 68.84 O
+ANISOU 1110 OG SER B 54 9383 8061 8712 1181 119 358 O
+ATOM 1111 N GLY B 55 -35.568 -10.582 -18.760 1.00 49.29 N
+ANISOU 1111 N GLY B 55 6054 6357 6315 1182 19 420 N
+ATOM 1112 CA GLY B 55 -35.709 -11.925 -19.288 1.00 50.10 C
+ANISOU 1112 CA GLY B 55 5974 6638 6423 971 -80 453 C
+ATOM 1113 C GLY B 55 -36.015 -12.954 -18.190 1.00 54.88 C
+ANISOU 1113 C GLY B 55 6384 7412 7052 843 -31 418 C
+ATOM 1114 O GLY B 55 -36.357 -12.606 -17.055 1.00 51.85 O
+ANISOU 1114 O GLY B 55 5948 7078 6673 954 81 384 O
+ATOM 1115 N SER B 56 -35.910 -14.235 -18.540 1.00 52.05 N
+ANISOU 1115 N SER B 56 5952 7132 6691 610 -114 429 N
+ATOM 1116 CA SER B 56 -36.309 -15.287 -17.628 1.00 53.81 C
+ANISOU 1116 CA SER B 56 6017 7504 6924 461 -86 428 C
+ATOM 1117 C SER B 56 -35.313 -16.444 -17.548 1.00 48.18 C
+ANISOU 1117 C SER B 56 5432 6672 6199 230 -112 379 C
+ATOM 1118 O SER B 56 -34.496 -16.695 -18.438 1.00 51.01 O
+ANISOU 1118 O SER B 56 5943 6898 6540 166 -175 352 O
+ATOM 1119 CB SER B 56 -37.721 -15.783 -17.988 1.00 54.48 C
+ANISOU 1119 CB SER B 56 5818 7872 7006 422 -173 525 C
+ATOM 1120 OG SER B 56 -37.776 -16.208 -19.330 1.00 61.00 O
+ANISOU 1120 OG SER B 56 6673 8698 7805 316 -335 559 O
+ATOM 1121 N VAL B 57 -35.377 -17.125 -16.430 1.00 52.89 N
+ANISOU 1121 N VAL B 57 5977 7324 6794 133 -50 372 N
+ATOM 1122 CA VAL B 57 -34.589 -18.335 -16.192 1.00 52.55 C
+ANISOU 1122 CA VAL B 57 6056 7179 6732 -51 -77 346 C
+ATOM 1123 C VAL B 57 -35.550 -19.389 -15.674 1.00 55.14 C
+ANISOU 1123 C VAL B 57 6247 7658 7045 -229 -95 418 C
+ATOM 1124 O VAL B 57 -36.603 -19.052 -15.133 1.00 53.51 O
+ANISOU 1124 O VAL B 57 5830 7660 6841 -192 -35 473 O
+ATOM 1125 CB VAL B 57 -33.487 -18.134 -15.162 1.00 52.68 C
+ANISOU 1125 CB VAL B 57 6199 7082 6734 -9 13 278 C
+ATOM 1126 CG1 VAL B 57 -32.429 -17.171 -15.703 1.00 51.20 C
+ANISOU 1126 CG1 VAL B 57 6147 6751 6553 92 24 213 C
+ATOM 1127 CG2 VAL B 57 -34.091 -17.723 -13.810 1.00 53.07 C
+ANISOU 1127 CG2 VAL B 57 6147 7252 6763 53 130 286 C
+ATOM 1128 N ASP B 58 -35.198 -20.651 -15.913 1.00 54.40 N
+ANISOU 1128 N ASP B 58 6283 7459 6926 -420 -174 422 N
+ATOM 1129 CA ASP B 58 -35.847 -21.810 -15.319 1.00 52.99 C
+ANISOU 1129 CA ASP B 58 6069 7345 6718 -650 -190 493 C
+ATOM 1130 C ASP B 58 -34.894 -22.245 -14.184 1.00 50.66 C
+ANISOU 1130 C ASP B 58 5942 6913 6390 -637 -113 472 C
+ATOM 1131 O ASP B 58 -33.754 -22.666 -14.424 1.00 47.29 O
+ANISOU 1131 O ASP B 58 5729 6287 5951 -598 -150 415 O
+ATOM 1132 CB ASP B 58 -36.003 -22.916 -16.375 1.00 56.52 C
+ANISOU 1132 CB ASP B 58 6638 7699 7137 -861 -345 501 C
+ATOM 1133 CG ASP B 58 -36.384 -24.259 -15.771 1.00 65.37 C
+ANISOU 1133 CG ASP B 58 7842 8781 8214 -1139 -373 568 C
+ATOM 1134 OD1 ASP B 58 -36.846 -24.290 -14.603 1.00 66.65 O
+ANISOU 1134 OD1 ASP B 58 7883 9073 8365 -1194 -270 640 O
+ATOM 1135 OD2 ASP B 58 -36.259 -25.280 -16.483 1.00 70.20 O
+ANISOU 1135 OD2 ASP B 58 8664 9224 8785 -1310 -494 551 O
+ATOM 1136 N GLN B 59 -35.324 -22.089 -12.942 1.00 54.05 N
+ANISOU 1136 N GLN B 59 6267 7475 6792 -640 -1 517 N
+ATOM 1137 CA GLN B 59 -34.515 -22.555 -11.829 1.00 56.53 C
+ANISOU 1137 CA GLN B 59 6742 7686 7049 -640 51 516 C
+ATOM 1138 C GLN B 59 -35.268 -23.486 -10.889 1.00 59.14 C
+ANISOU 1138 C GLN B 59 7050 8107 7313 -851 94 632 C
+ATOM 1139 O GLN B 59 -35.188 -23.390 -9.661 1.00 65.41 O
+ANISOU 1139 O GLN B 59 7848 8966 8035 -822 198 658 O
+ATOM 1140 CB GLN B 59 -33.848 -21.372 -11.086 1.00 52.52 C
+ANISOU 1140 CB GLN B 59 6227 7196 6529 -422 151 436 C
+ATOM 1141 CG GLN B 59 -34.803 -20.396 -10.480 1.00 52.17 C
+ANISOU 1141 CG GLN B 59 5988 7361 6471 -326 274 442 C
+ATOM 1142 CD GLN B 59 -34.109 -19.292 -9.719 1.00 53.41 C
+ANISOU 1142 CD GLN B 59 6218 7483 6592 -139 359 343 C
+ATOM 1143 OE1 GLN B 59 -33.067 -19.483 -9.016 1.00 53.43 O
+ANISOU 1143 OE1 GLN B 59 6375 7387 6535 -140 352 304 O
+ATOM 1144 NE2 GLN B 59 -34.697 -18.133 -9.795 1.00 52.42 N
+ANISOU 1144 NE2 GLN B 59 5992 7441 6483 26 432 304 N
+ATOM 1145 N SER B 60 -35.956 -24.435 -11.476 1.00 61.58 N
+ANISOU 1145 N SER B 60 7365 8407 7623 -1092 6 703 N
+ATOM 1146 CA SER B 60 -36.740 -25.363 -10.706 1.00 72.30 C
+ANISOU 1146 CA SER B 60 8709 9847 8911 -1360 39 834 C
+ATOM 1147 C SER B 60 -35.825 -26.402 -10.017 1.00 74.05 C
+ANISOU 1147 C SER B 60 9269 9808 9057 -1412 17 868 C
+ATOM 1148 O SER B 60 -36.221 -27.047 -9.059 1.00 79.84 O
+ANISOU 1148 O SER B 60 10049 10581 9705 -1588 76 985 O
+ATOM 1149 CB SER B 60 -37.836 -25.999 -11.579 1.00 70.49 C
+ANISOU 1149 CB SER B 60 8372 9709 8700 -1655 -64 902 C
+ATOM 1150 OG SER B 60 -37.380 -26.382 -12.862 1.00 66.63 O
+ANISOU 1150 OG SER B 60 8069 9001 8245 -1672 -224 825 O
+ATOM 1151 N ASP B 61 -34.586 -26.497 -10.469 1.00 73.32 N
+ANISOU 1151 N ASP B 61 9398 9476 8984 -1231 -57 775 N
+ATOM 1152 CA ASP B 61 -33.572 -27.336 -9.811 1.00 80.97 C
+ANISOU 1152 CA ASP B 61 10666 10220 9879 -1177 -83 802 C
+ATOM 1153 C ASP B 61 -32.954 -26.686 -8.541 1.00 78.11 C
+ANISOU 1153 C ASP B 61 10262 9960 9455 -993 15 795 C
+ATOM 1154 O ASP B 61 -32.067 -27.263 -7.927 1.00 77.14 O
+ANISOU 1154 O ASP B 61 10352 9697 9259 -910 -16 823 O
+ATOM 1155 CB ASP B 61 -32.442 -27.683 -10.824 1.00 80.12 C
+ANISOU 1155 CB ASP B 61 10771 9865 9803 -1012 -194 700 C
+ATOM 1156 CG ASP B 61 -32.957 -28.443 -12.071 1.00 80.27 C
+ANISOU 1156 CG ASP B 61 10914 9741 9842 -1194 -306 687 C
+ATOM 1157 OD1 ASP B 61 -34.142 -28.856 -12.081 1.00 92.44 O
+ANISOU 1157 OD1 ASP B 61 12396 11355 11371 -1491 -323 772 O
+ATOM 1158 OD2 ASP B 61 -32.182 -28.623 -13.047 1.00 76.90 O
+ANISOU 1158 OD2 ASP B 61 10638 9149 9429 -1052 -377 588 O
+ATOM 1159 N GLN B 62 -33.390 -25.476 -8.178 1.00 79.30 N
+ANISOU 1159 N GLN B 62 10161 10347 9623 -909 123 751 N
+ATOM 1160 CA GLN B 62 -32.867 -24.772 -7.012 1.00 68.13 C
+ANISOU 1160 CA GLN B 62 8730 9027 8129 -755 210 719 C
+ATOM 1161 C GLN B 62 -33.726 -25.126 -5.824 1.00 70.39 C
+ANISOU 1161 C GLN B 62 8983 9467 8294 -906 322 843 C
+ATOM 1162 O GLN B 62 -34.807 -25.613 -6.012 1.00 70.22 O
+ANISOU 1162 O GLN B 62 8868 9532 8279 -1119 351 940 O
+ATOM 1163 CB GLN B 62 -32.896 -23.248 -7.236 1.00 67.38 C
+ANISOU 1163 CB GLN B 62 8445 9063 8093 -577 276 593 C
+ATOM 1164 CG GLN B 62 -34.246 -22.561 -6.972 1.00 69.55 C
+ANISOU 1164 CG GLN B 62 8479 9582 8363 -600 408 617 C
+ATOM 1165 CD GLN B 62 -34.463 -22.057 -5.534 1.00 62.14 C
+ANISOU 1165 CD GLN B 62 7513 8808 7289 -536 557 618 C
+ATOM 1166 OE1 GLN B 62 -33.521 -21.731 -4.823 1.00 54.90 O
+ANISOU 1166 OE1 GLN B 62 6736 7827 6294 -429 553 551 O
+ATOM 1167 NE2 GLN B 62 -35.725 -21.958 -5.128 1.00 63.75 N
+ANISOU 1167 NE2 GLN B 62 7519 9253 7449 -599 689 690 N
+ATOM 1168 N SER B 63 -33.270 -24.812 -4.615 1.00 70.67 N
+ANISOU 1168 N SER B 63 9076 9569 8205 -808 389 839 N
+ATOM 1169 CA SER B 63 -34.035 -25.114 -3.403 1.00 75.26 C
+ANISOU 1169 CA SER B 63 9643 10319 8633 -940 519 961 C
+ATOM 1170 C SER B 63 -33.862 -24.131 -2.248 1.00 70.31 C
+ANISOU 1170 C SER B 63 8977 9863 7874 -780 639 888 C
+ATOM 1171 O SER B 63 -34.598 -24.210 -1.268 1.00 78.27 O
+ANISOU 1171 O SER B 63 9939 11060 8737 -863 783 973 O
+ATOM 1172 CB SER B 63 -33.622 -26.492 -2.865 1.00 78.05 C
+ANISOU 1172 CB SER B 63 10283 10493 8878 -1077 445 1110 C
+ATOM 1173 OG SER B 63 -32.682 -26.352 -1.790 1.00 90.02 O
+ANISOU 1173 OG SER B 63 11950 12004 10249 -923 435 1099 O
+ATOM 1174 N PHE B 64 -32.871 -23.255 -2.316 1.00 65.41 N
+ANISOU 1174 N PHE B 64 8394 9180 7277 -573 583 734 N
+ATOM 1175 CA PHE B 64 -32.513 -22.466 -1.160 1.00 66.55 C
+ANISOU 1175 CA PHE B 64 8587 9435 7264 -453 656 655 C
+ATOM 1176 C PHE B 64 -33.316 -21.199 -1.122 1.00 68.15 C
+ANISOU 1176 C PHE B 64 8618 9800 7476 -340 809 543 C
+ATOM 1177 O PHE B 64 -33.653 -20.718 -0.042 1.00 74.02 O
+ANISOU 1177 O PHE B 64 9375 10700 8049 -284 945 514 O
+ATOM 1178 CB PHE B 64 -31.016 -22.107 -1.193 1.00 68.74 C
+ANISOU 1178 CB PHE B 64 8990 9582 7543 -323 508 542 C
+ATOM 1179 CG PHE B 64 -30.513 -21.437 0.066 1.00 66.26 C
+ANISOU 1179 CG PHE B 64 8771 9370 7032 -245 537 461 C
+ATOM 1180 CD1 PHE B 64 -30.170 -22.204 1.194 1.00 72.14 C
+ANISOU 1180 CD1 PHE B 64 9675 10158 7576 -288 506 569 C
+ATOM 1181 CD2 PHE B 64 -30.367 -20.052 0.126 1.00 68.69 C
+ANISOU 1181 CD2 PHE B 64 9050 9711 7337 -137 581 279 C
+ATOM 1182 CE1 PHE B 64 -29.710 -21.588 2.347 1.00 71.63 C
+ANISOU 1182 CE1 PHE B 64 9709 10202 7302 -228 515 487 C
+ATOM 1183 CE2 PHE B 64 -29.898 -19.430 1.275 1.00 69.45 C
+ANISOU 1183 CE2 PHE B 64 9273 9885 7231 -91 592 184 C
+ATOM 1184 CZ PHE B 64 -29.571 -20.192 2.381 1.00 72.58 C
+ANISOU 1184 CZ PHE B 64 9799 10357 7420 -139 555 283 C
+ATOM 1185 N LEU B 65 -33.564 -20.610 -2.286 1.00 63.83 N
+ANISOU 1185 N LEU B 65 7937 9206 7106 -274 785 473 N
+ATOM 1186 CA LEU B 65 -34.355 -19.387 -2.350 1.00 66.16 C
+ANISOU 1186 CA LEU B 65 8089 9630 7419 -115 921 375 C
+ATOM 1187 C LEU B 65 -35.835 -19.702 -2.078 1.00 70.47 C
+ANISOU 1187 C LEU B 65 8411 10440 7921 -180 1083 494 C
+ATOM 1188 O LEU B 65 -36.350 -20.690 -2.636 1.00 62.63 O
+ANISOU 1188 O LEU B 65 7317 9477 7002 -379 1035 634 O
+ATOM 1189 CB LEU B 65 -34.235 -18.733 -3.729 1.00 59.60 C
+ANISOU 1189 CB LEU B 65 7191 8674 6779 -25 837 299 C
+ATOM 1190 CG LEU B 65 -32.861 -18.246 -4.188 1.00 57.76 C
+ANISOU 1190 CG LEU B 65 7120 8221 6602 27 700 183 C
+ATOM 1191 CD1 LEU B 65 -32.917 -17.582 -5.576 1.00 57.81 C
+ANISOU 1191 CD1 LEU B 65 7061 8127 6775 102 646 135 C
+ATOM 1192 CD2 LEU B 65 -32.327 -17.275 -3.169 1.00 54.39 C
+ANISOU 1192 CD2 LEU B 65 6839 7788 6036 131 752 49 C
+ATOM 1193 N ASP B 66 -36.487 -18.860 -1.244 1.00 74.89 N
+ANISOU 1193 N ASP B 66 8903 11198 8353 -19 1274 433 N
+ATOM 1194 CA ASP B 66 -37.951 -18.868 -1.031 1.00 83.97 C
+ANISOU 1194 CA ASP B 66 9768 12675 9461 -11 1464 525 C
+ATOM 1195 C ASP B 66 -38.674 -18.077 -2.147 1.00 89.05 C
+ANISOU 1195 C ASP B 66 10182 13382 10272 163 1465 482 C
+ATOM 1196 O ASP B 66 -38.020 -17.512 -3.028 1.00 82.08 O
+ANISOU 1196 O ASP B 66 9403 12261 9520 266 1329 383 O
+ATOM 1197 CB ASP B 66 -38.358 -18.435 0.427 1.00 96.74 C
+ANISOU 1197 CB ASP B 66 11411 14515 10828 108 1694 490 C
+ATOM 1198 CG ASP B 66 -37.950 -16.966 0.829 1.00101.11 C
+ANISOU 1198 CG ASP B 66 12141 14972 11304 434 1759 259 C
+ATOM 1199 OD1 ASP B 66 -37.822 -16.062 -0.014 1.00103.38 O
+ANISOU 1199 OD1 ASP B 66 12437 15111 11732 617 1698 145 O
+ATOM 1200 OD2 ASP B 66 -37.801 -16.698 2.048 1.00107.31 O
+ANISOU 1200 OD2 ASP B 66 13086 15829 11857 502 1880 192 O
+ATOM 1201 N ASP B 67 -40.005 -18.040 -2.158 1.00 86.95 N
+ANISOU 1201 N ASP B 67 9589 13450 9995 197 1609 569 N
+ATOM 1202 CA ASP B 67 -40.677 -17.431 -3.312 1.00 90.53 C
+ANISOU 1202 CA ASP B 67 9811 13977 10608 358 1567 559 C
+ATOM 1203 C ASP B 67 -40.717 -15.891 -3.254 1.00 86.24 C
+ANISOU 1203 C ASP B 67 9333 13386 10046 784 1662 390 C
+ATOM 1204 O ASP B 67 -40.642 -15.233 -4.281 1.00 81.53 O
+ANISOU 1204 O ASP B 67 8742 12650 9585 940 1557 340 O
+ATOM 1205 CB ASP B 67 -42.050 -18.071 -3.552 1.00102.24 C
+ANISOU 1205 CB ASP B 67 10878 15858 12109 201 1632 735 C
+ATOM 1206 CG ASP B 67 -41.961 -19.594 -3.777 1.00110.12 C
+ANISOU 1206 CG ASP B 67 11890 16814 13135 -260 1502 895 C
+ATOM 1207 OD1 ASP B 67 -41.291 -20.027 -4.737 1.00 98.84 O
+ANISOU 1207 OD1 ASP B 67 10618 15101 11835 -390 1286 884 O
+ATOM 1208 OD2 ASP B 67 -42.569 -20.364 -2.992 1.00123.31 O
+ANISOU 1208 OD2 ASP B 67 13438 18728 14684 -494 1624 1033 O
+ATOM 1209 N GLU B 68 -40.822 -15.309 -2.066 1.00 91.45 N
+ANISOU 1209 N GLU B 68 10086 14137 10521 974 1859 301 N
+ATOM 1210 CA GLU B 68 -40.562 -13.877 -1.887 1.00 92.79 C
+ANISOU 1210 CA GLU B 68 10476 14135 10644 1350 1926 105 C
+ATOM 1211 C GLU B 68 -39.357 -13.490 -2.763 1.00 88.95 C
+ANISOU 1211 C GLU B 68 10277 13221 10296 1308 1700 12 C
+ATOM 1212 O GLU B 68 -39.451 -12.586 -3.592 1.00 86.77 O
+ANISOU 1212 O GLU B 68 10035 12811 10122 1529 1655 -46 O
+ATOM 1213 CB GLU B 68 -40.252 -13.581 -0.409 1.00103.28 C
+ANISOU 1213 CB GLU B 68 12042 15476 11725 1425 2090 -9 C
+ATOM 1214 CG GLU B 68 -39.658 -12.210 -0.110 1.00110.78 C
+ANISOU 1214 CG GLU B 68 13356 16139 12594 1717 2114 -242 C
+ATOM 1215 CD GLU B 68 -40.711 -11.114 -0.156 1.00127.27 C
+ANISOU 1215 CD GLU B 68 15344 18364 14648 2164 2303 -314 C
+ATOM 1216 OE1 GLU B 68 -41.594 -11.091 0.736 1.00128.34 O
+ANISOU 1216 OE1 GLU B 68 15322 18834 14608 2332 2547 -306 O
+ATOM 1217 OE2 GLU B 68 -40.658 -10.276 -1.086 1.00135.31 O
+ANISOU 1217 OE2 GLU B 68 16444 19164 15804 2367 2214 -371 O
+ATOM 1218 N GLN B 69 -38.246 -14.206 -2.567 1.00 72.49 N
+ANISOU 1218 N GLN B 69 8389 10950 8204 1029 1565 15 N
+ATOM 1219 CA GLN B 69 -36.950 -13.911 -3.200 1.00 73.21 C
+ANISOU 1219 CA GLN B 69 8740 10685 8389 958 1373 -72 C
+ATOM 1220 C GLN B 69 -36.830 -14.132 -4.727 1.00 65.48 C
+ANISOU 1220 C GLN B 69 7666 9593 7621 882 1203 -2 C
+ATOM 1221 O GLN B 69 -36.176 -13.383 -5.439 1.00 63.34 O
+ANISOU 1221 O GLN B 69 7557 9080 7428 951 1109 -83 O
+ATOM 1222 CB GLN B 69 -35.889 -14.744 -2.517 1.00 75.50 C
+ANISOU 1222 CB GLN B 69 9196 10892 8596 710 1285 -63 C
+ATOM 1223 CG GLN B 69 -35.602 -14.267 -1.103 1.00 78.45 C
+ANISOU 1223 CG GLN B 69 9777 11287 8741 786 1396 -180 C
+ATOM 1224 CD GLN B 69 -34.680 -15.215 -0.356 1.00 80.20 C
+ANISOU 1224 CD GLN B 69 10125 11490 8855 555 1301 -133 C
+ATOM 1225 OE1 GLN B 69 -34.695 -16.439 -0.569 1.00 76.67 O
+ANISOU 1225 OE1 GLN B 69 9569 11099 8460 360 1233 26 O
+ATOM 1226 NE2 GLN B 69 -33.869 -14.655 0.531 1.00 79.87 N
+ANISOU 1226 NE2 GLN B 69 10337 11359 8650 578 1283 -273 N
+ATOM 1227 N ILE B 70 -37.462 -15.169 -5.220 1.00 61.39 N
+ANISOU 1227 N ILE B 70 6901 9247 7174 715 1163 150 N
+ATOM 1228 CA ILE B 70 -37.598 -15.345 -6.623 1.00 62.15 C
+ANISOU 1228 CA ILE B 70 6889 9291 7432 668 1022 213 C
+ATOM 1229 C ILE B 70 -38.394 -14.186 -7.226 1.00 73.71 C
+ANISOU 1229 C ILE B 70 8249 10811 8945 974 1070 184 C
+ATOM 1230 O ILE B 70 -37.990 -13.601 -8.254 1.00 73.86 O
+ANISOU 1230 O ILE B 70 8375 10629 9058 1051 959 151 O
+ATOM 1231 CB ILE B 70 -38.275 -16.689 -6.902 1.00 63.18 C
+ANISOU 1231 CB ILE B 70 6790 9618 7596 406 976 375 C
+ATOM 1232 CG1 ILE B 70 -37.310 -17.798 -6.413 1.00 66.78 C
+ANISOU 1232 CG1 ILE B 70 7440 9927 8005 147 902 402 C
+ATOM 1233 CG2 ILE B 70 -38.638 -16.782 -8.387 1.00 57.25 C
+ANISOU 1233 CG2 ILE B 70 5905 8860 6984 377 830 431 C
+ATOM 1234 CD1 ILE B 70 -37.651 -19.227 -6.791 1.00 70.61 C
+ANISOU 1234 CD1 ILE B 70 7840 10465 8522 -155 814 547 C
+ATOM 1235 N GLY B 71 -39.521 -13.852 -6.588 1.00 75.76 N
+ANISOU 1235 N GLY B 71 8304 11355 9126 1166 1244 206 N
+ATOM 1236 CA GLY B 71 -40.376 -12.761 -7.036 1.00 72.95 C
+ANISOU 1236 CA GLY B 71 7834 11088 8796 1528 1307 188 C
+ATOM 1237 C GLY B 71 -39.624 -11.447 -7.147 1.00 76.38 C
+ANISOU 1237 C GLY B 71 8635 11163 9222 1770 1297 33 C
+ATOM 1238 O GLY B 71 -39.883 -10.642 -8.039 1.00 79.14 O
+ANISOU 1238 O GLY B 71 9008 11417 9641 1993 1244 36 O
+ATOM 1239 N GLU B 72 -38.660 -11.230 -6.267 1.00 77.34 N
+ANISOU 1239 N GLU B 72 9065 11073 9246 1700 1332 -94 N
+ATOM 1240 CA GLU B 72 -37.776 -10.071 -6.409 1.00 82.72 C
+ANISOU 1240 CA GLU B 72 10132 11378 9918 1818 1290 -240 C
+ATOM 1241 C GLU B 72 -36.680 -10.326 -7.459 1.00 73.65 C
+ANISOU 1241 C GLU B 72 9106 9983 8893 1567 1086 -215 C
+ATOM 1242 O GLU B 72 -35.725 -9.562 -7.537 1.00 70.35 O
+ANISOU 1242 O GLU B 72 8999 9266 8462 1543 1035 -321 O
+ATOM 1243 CB GLU B 72 -37.154 -9.705 -5.053 1.00 94.77 C
+ANISOU 1243 CB GLU B 72 11940 12798 11270 1810 1386 -397 C
+ATOM 1244 CG GLU B 72 -38.118 -9.911 -3.884 1.00110.12 C
+ANISOU 1244 CG GLU B 72 13720 15060 13058 1957 1598 -397 C
+ATOM 1245 CD GLU B 72 -37.932 -8.936 -2.746 1.00125.11 C
+ANISOU 1245 CD GLU B 72 15946 16831 14757 2160 1737 -591 C
+ATOM 1246 OE1 GLU B 72 -38.918 -8.231 -2.409 1.00134.61 O
+ANISOU 1246 OE1 GLU B 72 17112 18158 15874 2531 1921 -638 O
+ATOM 1247 OE2 GLU B 72 -36.813 -8.896 -2.185 1.00125.40 O
+ANISOU 1247 OE2 GLU B 72 16271 16663 14709 1956 1661 -698 O
+ATOM 1248 N GLY B 73 -36.799 -11.410 -8.233 1.00 65.49 N
+ANISOU 1248 N GLY B 73 7839 9083 7962 1362 977 -81 N
+ATOM 1249 CA GLY B 73 -35.815 -11.747 -9.280 1.00 62.64 C
+ANISOU 1249 CA GLY B 73 7570 8528 7700 1152 805 -56 C
+ATOM 1250 C GLY B 73 -34.511 -12.432 -8.913 1.00 64.69 C
+ANISOU 1250 C GLY B 73 7964 8676 7938 882 732 -95 C
+ATOM 1251 O GLY B 73 -33.621 -12.552 -9.759 1.00 61.13 O
+ANISOU 1251 O GLY B 73 7598 8075 7554 753 615 -91 O
+ATOM 1252 N PHE B 74 -34.380 -12.937 -7.687 1.00 63.75 N
+ANISOU 1252 N PHE B 74 7851 8656 7716 805 798 -121 N
+ATOM 1253 CA PHE B 74 -33.146 -13.627 -7.305 1.00 53.01 C
+ANISOU 1253 CA PHE B 74 6598 7217 6322 587 711 -142 C
+ATOM 1254 C PHE B 74 -32.988 -14.972 -7.975 1.00 47.15 C
+ANISOU 1254 C PHE B 74 5729 6525 5658 405 605 -25 C
+ATOM 1255 O PHE B 74 -33.925 -15.691 -8.210 1.00 47.19 O
+ANISOU 1255 O PHE B 74 5555 6679 5693 369 619 77 O
+ATOM 1256 CB PHE B 74 -33.033 -13.757 -5.799 1.00 57.58 C
+ANISOU 1256 CB PHE B 74 7252 7883 6742 571 795 -193 C
+ATOM 1257 CG PHE B 74 -32.721 -12.455 -5.116 1.00 62.39 C
+ANISOU 1257 CG PHE B 74 8094 8364 7244 697 859 -353 C
+ATOM 1258 CD1 PHE B 74 -31.451 -11.886 -5.228 1.00 64.10 C
+ANISOU 1258 CD1 PHE B 74 8521 8379 7455 591 755 -452 C
+ATOM 1259 CD2 PHE B 74 -33.694 -11.780 -4.360 1.00 68.55 C
+ANISOU 1259 CD2 PHE B 74 8895 9233 7917 917 1026 -411 C
+ATOM 1260 CE1 PHE B 74 -31.155 -10.674 -4.606 1.00 68.98 C
+ANISOU 1260 CE1 PHE B 74 9402 8846 7962 659 796 -610 C
+ATOM 1261 CE2 PHE B 74 -33.400 -10.578 -3.721 1.00 69.76 C
+ANISOU 1261 CE2 PHE B 74 9331 9224 7950 1040 1082 -581 C
+ATOM 1262 CZ PHE B 74 -32.132 -10.015 -3.852 1.00 73.33 C
+ANISOU 1262 CZ PHE B 74 10030 9434 8398 891 957 -683 C
+ATOM 1263 N VAL B 75 -31.754 -15.313 -8.293 1.00 47.62 N
+ANISOU 1263 N VAL B 75 5890 6460 5740 284 497 -46 N
+ATOM 1264 CA VAL B 75 -31.467 -16.527 -9.040 1.00 46.67 C
+ANISOU 1264 CA VAL B 75 5712 6336 5685 155 395 39 C
+ATOM 1265 C VAL B 75 -30.245 -17.245 -8.471 1.00 44.46 C
+ANISOU 1265 C VAL B 75 5526 6018 5347 63 327 28 C
+ATOM 1266 O VAL B 75 -29.283 -16.611 -8.088 1.00 45.81 O
+ANISOU 1266 O VAL B 75 5789 6141 5474 68 309 -55 O
+ATOM 1267 CB VAL B 75 -31.345 -16.225 -10.573 1.00 48.40 C
+ANISOU 1267 CB VAL B 75 5921 6459 6009 172 323 45 C
+ATOM 1268 CG1 VAL B 75 -30.229 -15.219 -10.891 1.00 49.82 C
+ANISOU 1268 CG1 VAL B 75 6236 6497 6194 190 302 -42 C
+ATOM 1269 CG2 VAL B 75 -31.192 -17.513 -11.372 1.00 52.32 C
+ANISOU 1269 CG2 VAL B 75 6386 6945 6547 57 228 117 C
+ATOM 1270 N LEU B 76 -30.313 -18.572 -8.356 1.00 47.02 N
+ANISOU 1270 N LEU B 76 5836 6371 5658 -24 284 120 N
+ATOM 1271 CA LEU B 76 -29.121 -19.328 -8.132 1.00 46.01 C
+ANISOU 1271 CA LEU B 76 5797 6192 5492 -56 197 127 C
+ATOM 1272 C LEU B 76 -28.512 -19.742 -9.476 1.00 40.71 C
+ANISOU 1272 C LEU B 76 5131 5424 4910 -54 113 128 C
+ATOM 1273 O LEU B 76 -29.048 -20.600 -10.147 1.00 46.45 O
+ANISOU 1273 O LEU B 76 5862 6109 5676 -101 81 191 O
+ATOM 1274 CB LEU B 76 -29.384 -20.509 -7.221 1.00 47.02 C
+ANISOU 1274 CB LEU B 76 5975 6357 5531 -120 195 227 C
+ATOM 1275 CG LEU B 76 -30.003 -20.207 -5.836 1.00 48.21 C
+ANISOU 1275 CG LEU B 76 6126 6635 5556 -128 299 239 C
+ATOM 1276 CD1 LEU B 76 -30.102 -21.517 -5.059 1.00 49.81 C
+ANISOU 1276 CD1 LEU B 76 6416 6849 5659 -217 281 368 C
+ATOM 1277 CD2 LEU B 76 -29.254 -19.158 -5.030 1.00 49.77 C
+ANISOU 1277 CD2 LEU B 76 6382 6864 5663 -57 312 121 C
+ATOM 1278 N THR B 77 -27.369 -19.136 -9.812 1.00 41.43 N
+ANISOU 1278 N THR B 77 5232 5494 5012 -17 79 55 N
+ATOM 1279 CA THR B 77 -26.727 -19.284 -11.128 1.00 40.67 C
+ANISOU 1279 CA THR B 77 5128 5343 4981 1 33 43 C
+ATOM 1280 C THR B 77 -26.271 -20.689 -11.435 1.00 44.46 C
+ANISOU 1280 C THR B 77 5663 5781 5447 32 -31 92 C
+ATOM 1281 O THR B 77 -26.273 -21.097 -12.621 1.00 45.14 O
+ANISOU 1281 O THR B 77 5776 5802 5573 48 -54 93 O
+ATOM 1282 CB THR B 77 -25.599 -18.252 -11.327 1.00 45.56 C
+ANISOU 1282 CB THR B 77 5722 5989 5598 -3 32 -32 C
+ATOM 1283 OG1 THR B 77 -24.616 -18.284 -10.248 1.00 43.74 O
+ANISOU 1283 OG1 THR B 77 5481 5849 5287 -11 -5 -59 O
+ATOM 1284 CG2 THR B 77 -26.220 -16.863 -11.400 1.00 41.29 C
+ANISOU 1284 CG2 THR B 77 5203 5403 5080 -24 94 -78 C
+ATOM 1285 N CYS B 78 -25.967 -21.485 -10.393 1.00 45.27 N
+ANISOU 1285 N CYS B 78 5822 5901 5476 54 -62 136 N
+ATOM 1286 CA CYS B 78 -25.538 -22.878 -10.640 1.00 40.58 C
+ANISOU 1286 CA CYS B 78 5341 5220 4856 123 -127 189 C
+ATOM 1287 C CYS B 78 -26.708 -23.807 -10.971 1.00 41.12 C
+ANISOU 1287 C CYS B 78 5522 5162 4939 26 -135 258 C
+ATOM 1288 O CYS B 78 -26.504 -24.884 -11.423 1.00 43.05 O
+ANISOU 1288 O CYS B 78 5913 5275 5166 63 -188 285 O
+ATOM 1289 CB CYS B 78 -24.806 -23.414 -9.415 1.00 46.97 C
+ANISOU 1289 CB CYS B 78 6199 6078 5566 196 -175 233 C
+ATOM 1290 SG CYS B 78 -25.953 -23.849 -8.071 1.00 49.40 S
+ANISOU 1290 SG CYS B 78 6603 6375 5792 77 -143 334 S
+ATOM 1291 N ALA B 79 -27.946 -23.393 -10.780 1.00 44.78 N
+ANISOU 1291 N ALA B 79 5918 5669 5425 -101 -84 285 N
+ATOM 1292 CA ALA B 79 -29.075 -24.281 -11.005 1.00 47.60 C
+ANISOU 1292 CA ALA B 79 6343 5956 5784 -250 -101 364 C
+ATOM 1293 C ALA B 79 -30.185 -23.636 -11.871 1.00 49.22 C
+ANISOU 1293 C ALA B 79 6406 6233 6061 -337 -80 350 C
+ATOM 1294 O ALA B 79 -31.381 -24.008 -11.779 1.00 50.46 O
+ANISOU 1294 O ALA B 79 6514 6441 6216 -497 -73 423 O
+ATOM 1295 CB ALA B 79 -29.642 -24.689 -9.663 1.00 51.35 C
+ANISOU 1295 CB ALA B 79 6846 6483 6181 -345 -59 459 C
+ATOM 1296 N ALA B 80 -29.766 -22.691 -12.710 1.00 47.73 N
+ANISOU 1296 N ALA B 80 6146 6065 5924 -239 -75 270 N
+ATOM 1297 CA ALA B 80 -30.656 -21.820 -13.483 1.00 47.79 C
+ANISOU 1297 CA ALA B 80 6019 6149 5986 -255 -60 260 C
+ATOM 1298 C ALA B 80 -30.291 -21.968 -14.960 1.00 45.38 C
+ANISOU 1298 C ALA B 80 5782 5759 5701 -235 -129 220 C
+ATOM 1299 O ALA B 80 -29.179 -21.667 -15.325 1.00 42.72 O
+ANISOU 1299 O ALA B 80 5492 5381 5359 -133 -121 162 O
+ATOM 1300 CB ALA B 80 -30.480 -20.367 -13.042 1.00 44.94 C
+ANISOU 1300 CB ALA B 80 5565 5866 5641 -146 20 209 C
+ATOM 1301 N TYR B 81 -31.241 -22.453 -15.772 1.00 45.42 N
+ANISOU 1301 N TYR B 81 5782 5764 5709 -349 -198 253 N
+ATOM 1302 CA TYR B 81 -31.175 -22.431 -17.214 1.00 43.03 C
+ANISOU 1302 CA TYR B 81 5534 5415 5397 -340 -266 217 C
+ATOM 1303 C TYR B 81 -31.816 -21.180 -17.774 1.00 44.38 C
+ANISOU 1303 C TYR B 81 5553 5705 5604 -286 -255 229 C
+ATOM 1304 O TYR B 81 -32.869 -20.780 -17.277 1.00 44.18 O
+ANISOU 1304 O TYR B 81 5365 5812 5607 -312 -236 284 O
+ATOM 1305 CB TYR B 81 -31.969 -23.595 -17.812 1.00 42.89 C
+ANISOU 1305 CB TYR B 81 5610 5343 5342 -522 -376 244 C
+ATOM 1306 CG TYR B 81 -31.528 -24.936 -17.365 1.00 42.13 C
+ANISOU 1306 CG TYR B 81 5733 5076 5198 -585 -404 245 C
+ATOM 1307 CD1 TYR B 81 -30.314 -25.445 -17.790 1.00 44.66 C
+ANISOU 1307 CD1 TYR B 81 6255 5239 5473 -442 -407 173 C
+ATOM 1308 CD2 TYR B 81 -32.339 -25.734 -16.540 1.00 48.75 C
+ANISOU 1308 CD2 TYR B 81 6588 5909 6023 -781 -423 329 C
+ATOM 1309 CE1 TYR B 81 -29.894 -26.718 -17.417 1.00 43.35 C
+ANISOU 1309 CE1 TYR B 81 6335 4883 5252 -447 -440 177 C
+ATOM 1310 CE2 TYR B 81 -31.956 -27.041 -16.215 1.00 49.19 C
+ANISOU 1310 CE2 TYR B 81 6919 5750 6019 -844 -464 343 C
+ATOM 1311 CZ TYR B 81 -30.702 -27.516 -16.640 1.00 48.71 C
+ANISOU 1311 CZ TYR B 81 7087 5502 5916 -648 -475 264 C
+ATOM 1312 OH TYR B 81 -30.184 -28.775 -16.265 1.00 52.95 O
+ANISOU 1312 OH TYR B 81 7931 5800 6387 -626 -510 278 O
+ATOM 1313 N PRO B 82 -31.222 -20.582 -18.851 1.00 42.24 N
+ANISOU 1313 N PRO B 82 5338 5394 5317 -199 -264 189 N
+ATOM 1314 CA PRO B 82 -31.916 -19.427 -19.426 1.00 43.63 C
+ANISOU 1314 CA PRO B 82 5410 5655 5512 -135 -271 223 C
+ATOM 1315 C PRO B 82 -33.193 -19.929 -20.110 1.00 42.47 C
+ANISOU 1315 C PRO B 82 5186 5607 5344 -243 -390 277 C
+ATOM 1316 O PRO B 82 -33.182 -21.018 -20.729 1.00 43.18 O
+ANISOU 1316 O PRO B 82 5392 5637 5378 -371 -481 256 O
+ATOM 1317 CB PRO B 82 -30.922 -18.885 -20.482 1.00 44.26 C
+ANISOU 1317 CB PRO B 82 5608 5658 5550 -62 -258 186 C
+ATOM 1318 CG PRO B 82 -29.978 -19.997 -20.799 1.00 44.00 C
+ANISOU 1318 CG PRO B 82 5714 5541 5462 -94 -268 127 C
+ATOM 1319 CD PRO B 82 -30.010 -20.955 -19.610 1.00 43.22 C
+ANISOU 1319 CD PRO B 82 5616 5415 5388 -148 -264 126 C
+ATOM 1320 N THR B 83 -34.264 -19.156 -20.049 1.00 43.35 N
+ANISOU 1320 N THR B 83 5114 5871 5484 -188 -400 342 N
+ATOM 1321 CA THR B 83 -35.417 -19.426 -20.932 1.00 48.62 C
+ANISOU 1321 CA THR B 83 5669 6684 6117 -276 -540 401 C
+ATOM 1322 C THR B 83 -35.748 -18.249 -21.876 1.00 46.65 C
+ANISOU 1322 C THR B 83 5378 6497 5848 -103 -583 444 C
+ATOM 1323 O THR B 83 -36.739 -18.269 -22.580 1.00 52.22 O
+ANISOU 1323 O THR B 83 5955 7366 6519 -132 -710 507 O
+ATOM 1324 CB THR B 83 -36.648 -19.794 -20.074 1.00 51.91 C
+ANISOU 1324 CB THR B 83 5841 7312 6568 -382 -542 472 C
+ATOM 1325 OG1 THR B 83 -36.869 -18.747 -19.119 1.00 51.49 O
+ANISOU 1325 OG1 THR B 83 5651 7343 6568 -184 -407 493 O
+ATOM 1326 CG2 THR B 83 -36.374 -21.131 -19.339 1.00 48.25 C
+ANISOU 1326 CG2 THR B 83 5482 6756 6094 -602 -531 453 C
+ATOM 1327 N SER B 84 -34.922 -17.220 -21.872 1.00 49.15 N
+ANISOU 1327 N SER B 84 5810 6685 6177 63 -486 421 N
+ATOM 1328 CA SER B 84 -34.968 -16.169 -22.893 1.00 47.46 C
+ANISOU 1328 CA SER B 84 5660 6452 5920 210 -525 469 C
+ATOM 1329 C SER B 84 -33.560 -15.596 -22.849 1.00 44.74 C
+ANISOU 1329 C SER B 84 5522 5905 5571 249 -408 413 C
+ATOM 1330 O SER B 84 -32.757 -15.991 -21.985 1.00 42.92 O
+ANISOU 1330 O SER B 84 5325 5604 5377 186 -319 344 O
+ATOM 1331 CB SER B 84 -35.999 -15.072 -22.468 1.00 52.98 C
+ANISOU 1331 CB SER B 84 6195 7271 6664 424 -504 546 C
+ATOM 1332 OG SER B 84 -35.478 -14.259 -21.372 1.00 56.24 O
+ANISOU 1332 OG SER B 84 6673 7559 7133 543 -346 502 O
+ATOM 1333 N ASP B 85 -33.263 -14.621 -23.694 1.00 42.09 N
+ANISOU 1333 N ASP B 85 5315 5491 5184 344 -407 456 N
+ATOM 1334 CA ASP B 85 -32.096 -13.779 -23.472 1.00 44.39 C
+ANISOU 1334 CA ASP B 85 5767 5616 5481 363 -284 426 C
+ATOM 1335 C ASP B 85 -32.367 -13.068 -22.174 1.00 44.33 C
+ANISOU 1335 C ASP B 85 5710 5574 5557 461 -200 408 C
+ATOM 1336 O ASP B 85 -33.473 -12.654 -21.914 1.00 44.74 O
+ANISOU 1336 O ASP B 85 5658 5704 5635 607 -226 457 O
+ATOM 1337 CB ASP B 85 -31.910 -12.741 -24.580 1.00 50.33 C
+ANISOU 1337 CB ASP B 85 6690 6279 6153 434 -297 505 C
+ATOM 1338 CG ASP B 85 -31.692 -13.380 -25.963 1.00 53.63 C
+ANISOU 1338 CG ASP B 85 7180 6749 6447 352 -376 524 C
+ATOM 1339 OD1 ASP B 85 -31.204 -14.529 -26.022 1.00 47.82 O
+ANISOU 1339 OD1 ASP B 85 6425 6053 5688 233 -377 444 O
+ATOM 1340 OD2 ASP B 85 -32.060 -12.736 -26.984 1.00 54.69 O
+ANISOU 1340 OD2 ASP B 85 7411 6877 6491 428 -443 619 O
+ATOM 1341 N VAL B 86 -31.347 -12.922 -21.361 1.00 40.17 N
+ANISOU 1341 N VAL B 86 5253 4953 5056 392 -100 335 N
+ATOM 1342 CA VAL B 86 -31.545 -12.627 -20.001 1.00 40.95 C
+ANISOU 1342 CA VAL B 86 5304 5044 5208 443 -28 288 C
+ATOM 1343 C VAL B 86 -30.338 -11.876 -19.512 1.00 40.30 C
+ANISOU 1343 C VAL B 86 5380 4811 5117 374 55 227 C
+ATOM 1344 O VAL B 86 -29.225 -12.135 -19.945 1.00 43.19 O
+ANISOU 1344 O VAL B 86 5796 5158 5455 238 66 208 O
+ATOM 1345 CB VAL B 86 -31.795 -13.954 -19.226 1.00 47.21 C
+ANISOU 1345 CB VAL B 86 5933 5975 6029 355 -41 254 C
+ATOM 1346 CG1 VAL B 86 -30.588 -14.864 -19.281 1.00 53.03 C
+ANISOU 1346 CG1 VAL B 86 6718 6685 6745 209 -38 201 C
+ATOM 1347 CG2 VAL B 86 -32.149 -13.690 -17.770 1.00 54.18 C
+ANISOU 1347 CG2 VAL B 86 6757 6889 6939 415 40 215 C
+ATOM 1348 N THR B 87 -30.567 -10.923 -18.633 1.00 40.44 N
+ANISOU 1348 N THR B 87 5478 4736 5147 466 116 194 N
+ATOM 1349 CA THR B 87 -29.526 -10.137 -17.998 1.00 44.61 C
+ANISOU 1349 CA THR B 87 6175 5117 5656 367 180 122 C
+ATOM 1350 C THR B 87 -29.555 -10.459 -16.518 1.00 45.83 C
+ANISOU 1350 C THR B 87 6259 5336 5818 364 223 34 C
+ATOM 1351 O THR B 87 -30.627 -10.480 -15.920 1.00 50.57 O
+ANISOU 1351 O THR B 87 6782 6002 6428 521 248 34 O
+ATOM 1352 CB THR B 87 -29.811 -8.653 -18.240 1.00 48.52 C
+ANISOU 1352 CB THR B 87 6913 5392 6126 483 206 148 C
+ATOM 1353 OG1 THR B 87 -29.766 -8.415 -19.647 1.00 50.14 O
+ANISOU 1353 OG1 THR B 87 7196 5550 6304 478 160 251 O
+ATOM 1354 CG2 THR B 87 -28.775 -7.748 -17.578 1.00 51.37 C
+ANISOU 1354 CG2 THR B 87 7497 5567 6453 330 258 66 C
+ATOM 1355 N ILE B 88 -28.383 -10.757 -15.950 1.00 46.15 N
+ANISOU 1355 N ILE B 88 6302 5394 5839 188 231 -31 N
+ATOM 1356 CA ILE B 88 -28.248 -11.202 -14.561 1.00 48.38 C
+ANISOU 1356 CA ILE B 88 6524 5758 6100 163 252 -105 C
+ATOM 1357 C ILE B 88 -27.148 -10.356 -13.868 1.00 49.51 C
+ANISOU 1357 C ILE B 88 6821 5800 6187 17 267 -195 C
+ATOM 1358 O ILE B 88 -26.006 -10.333 -14.336 1.00 50.31 O
+ANISOU 1358 O ILE B 88 6922 5912 6279 -155 240 -192 O
+ATOM 1359 CB ILE B 88 -27.854 -12.697 -14.495 1.00 47.16 C
+ANISOU 1359 CB ILE B 88 6193 5770 5956 88 209 -84 C
+ATOM 1360 CG1 ILE B 88 -29.028 -13.550 -14.899 1.00 45.49 C
+ANISOU 1360 CG1 ILE B 88 5857 5647 5780 178 185 -12 C
+ATOM 1361 CG2 ILE B 88 -27.449 -13.095 -13.075 1.00 50.06 C
+ANISOU 1361 CG2 ILE B 88 6533 6211 6275 43 217 -145 C
+ATOM 1362 CD1 ILE B 88 -28.663 -14.921 -15.331 1.00 44.53 C
+ANISOU 1362 CD1 ILE B 88 5652 5603 5664 105 128 18 C
+ATOM 1363 N GLU B 89 -27.473 -9.703 -12.758 1.00 53.87 N
+ANISOU 1363 N GLU B 89 7496 6283 6689 72 309 -278 N
+ATOM 1364 CA GLU B 89 -26.437 -9.087 -11.897 1.00 55.06 C
+ANISOU 1364 CA GLU B 89 7788 6369 6762 -106 296 -383 C
+ATOM 1365 C GLU B 89 -25.875 -10.173 -10.991 1.00 50.59 C
+ANISOU 1365 C GLU B 89 7047 6015 6159 -183 255 -407 C
+ATOM 1366 O GLU B 89 -26.632 -10.952 -10.372 1.00 53.81 O
+ANISOU 1366 O GLU B 89 7350 6536 6558 -58 279 -389 O
+ATOM 1367 CB GLU B 89 -26.978 -7.962 -10.983 1.00 64.61 C
+ANISOU 1367 CB GLU B 89 9255 7398 7894 -8 353 -489 C
+ATOM 1368 CG GLU B 89 -27.906 -6.925 -11.597 1.00 75.35 C
+ANISOU 1368 CG GLU B 89 10817 8537 9275 195 408 -466 C
+ATOM 1369 CD GLU B 89 -28.548 -5.964 -10.562 1.00 82.40 C
+ANISOU 1369 CD GLU B 89 11968 9264 10073 373 485 -588 C
+ATOM 1370 OE1 GLU B 89 -29.068 -6.404 -9.504 1.00 81.15 O
+ANISOU 1370 OE1 GLU B 89 11720 9254 9857 488 538 -645 O
+ATOM 1371 OE2 GLU B 89 -28.574 -4.751 -10.836 1.00 78.16 O
+ANISOU 1371 OE2 GLU B 89 11754 8436 9505 415 502 -623 O
+ATOM 1372 N THR B 90 -24.559 -10.217 -10.878 1.00 51.58 N
+ANISOU 1372 N THR B 90 7135 6210 6250 -392 193 -434 N
+ATOM 1373 CA THR B 90 -23.886 -11.258 -10.104 1.00 50.76 C
+ANISOU 1373 CA THR B 90 6862 6321 6103 -439 132 -438 C
+ATOM 1374 C THR B 90 -23.428 -10.795 -8.698 1.00 54.51 C
+ANISOU 1374 C THR B 90 7442 6820 6450 -544 93 -549 C
+ATOM 1375 O THR B 90 -23.592 -9.656 -8.337 1.00 56.29 O
+ANISOU 1375 O THR B 90 7894 6876 6618 -596 118 -640 O
+ATOM 1376 CB THR B 90 -22.680 -11.779 -10.880 1.00 51.05 C
+ANISOU 1376 CB THR B 90 6727 6500 6170 -558 78 -385 C
+ATOM 1377 OG1 THR B 90 -21.707 -10.743 -11.014 1.00 54.51 O
+ANISOU 1377 OG1 THR B 90 7235 6905 6570 -789 55 -432 O
+ATOM 1378 CG2 THR B 90 -23.111 -12.265 -12.264 1.00 50.66 C
+ANISOU 1378 CG2 THR B 90 6610 6424 6212 -455 115 -293 C
+ATOM 1379 N HIS B 91 -22.903 -11.730 -7.904 1.00 57.41 N
+ANISOU 1379 N HIS B 91 7670 7387 6755 -556 26 -538 N
+ATOM 1380 CA HIS B 91 -22.350 -11.451 -6.562 1.00 53.16 C
+ANISOU 1380 CA HIS B 91 7206 6925 6066 -666 -42 -633 C
+ATOM 1381 C HIS B 91 -23.379 -10.865 -5.635 1.00 52.82 C
+ANISOU 1381 C HIS B 91 7383 6755 5930 -566 36 -720 C
+ATOM 1382 O HIS B 91 -23.140 -9.839 -5.055 1.00 57.23 O
+ANISOU 1382 O HIS B 91 8152 7207 6385 -681 21 -845 O
+ATOM 1383 CB HIS B 91 -21.120 -10.564 -6.646 1.00 52.81 C
+ANISOU 1383 CB HIS B 91 7193 6894 5976 -939 -126 -702 C
+ATOM 1384 CG HIS B 91 -19.981 -11.185 -7.409 1.00 56.19 C
+ANISOU 1384 CG HIS B 91 7349 7534 6464 -1027 -193 -617 C
+ATOM 1385 ND1 HIS B 91 -20.029 -11.423 -8.768 1.00 58.74 N
+ANISOU 1385 ND1 HIS B 91 7574 7829 6914 -972 -131 -528 N
+ATOM 1386 CD2 HIS B 91 -18.759 -11.596 -7.006 1.00 57.11 C
+ANISOU 1386 CD2 HIS B 91 7263 7919 6514 -1145 -312 -608 C
+ATOM 1387 CE1 HIS B 91 -18.883 -11.936 -9.173 1.00 56.30 C
+ANISOU 1387 CE1 HIS B 91 7023 7755 6612 -1044 -186 -477 C
+ATOM 1388 NE2 HIS B 91 -18.094 -12.046 -8.123 1.00 61.01 N
+ANISOU 1388 NE2 HIS B 91 7535 8546 7100 -1142 -299 -520 N
+ATOM 1389 N LYS B 92 -24.532 -11.528 -5.533 1.00 51.89 N
+ANISOU 1389 N LYS B 92 7218 6656 5842 -359 126 -655 N
+ATOM 1390 CA LYS B 92 -25.686 -11.045 -4.764 1.00 55.84 C
+ANISOU 1390 CA LYS B 92 7874 7083 6259 -208 243 -719 C
+ATOM 1391 C LYS B 92 -25.938 -11.835 -3.472 1.00 58.34 C
+ANISOU 1391 C LYS B 92 8162 7572 6430 -160 255 -708 C
+ATOM 1392 O LYS B 92 -26.959 -11.637 -2.823 1.00 58.98 O
+ANISOU 1392 O LYS B 92 8322 7655 6430 -18 378 -739 O
+ATOM 1393 CB LYS B 92 -26.964 -11.067 -5.656 1.00 58.46 C
+ANISOU 1393 CB LYS B 92 8144 7346 6720 -12 355 -640 C
+ATOM 1394 CG LYS B 92 -26.997 -9.991 -6.743 1.00 61.75 C
+ANISOU 1394 CG LYS B 92 8682 7550 7230 -3 369 -662 C
+ATOM 1395 CD LYS B 92 -26.411 -8.664 -6.237 1.00 67.88 C
+ANISOU 1395 CD LYS B 92 9757 8134 7899 -115 352 -813 C
+ATOM 1396 CE LYS B 92 -26.933 -7.436 -6.946 1.00 70.75 C
+ANISOU 1396 CE LYS B 92 10351 8225 8305 -10 414 -844 C
+ATOM 1397 NZ LYS B 92 -28.067 -6.929 -6.119 1.00 81.14 N
+ANISOU 1397 NZ LYS B 92 11822 9481 9525 253 540 -928 N
+ATOM 1398 N GLU B 93 -25.011 -12.712 -3.102 1.00 57.86 N
+ANISOU 1398 N GLU B 93 7989 7669 6322 -262 135 -655 N
+ATOM 1399 CA GLU B 93 -25.136 -13.464 -1.883 1.00 65.82 C
+ANISOU 1399 CA GLU B 93 9004 8833 7172 -230 128 -625 C
+ATOM 1400 C GLU B 93 -25.494 -12.505 -0.726 1.00 69.11 C
+ANISOU 1400 C GLU B 93 9655 9212 7388 -218 194 -777 C
+ATOM 1401 O GLU B 93 -26.466 -12.735 -0.015 1.00 63.37 O
+ANISOU 1401 O GLU B 93 8970 8546 6562 -93 320 -761 O
+ATOM 1402 CB GLU B 93 -23.834 -14.222 -1.595 1.00 65.64 C
+ANISOU 1402 CB GLU B 93 8876 8968 7096 -333 -46 -573 C
+ATOM 1403 CG GLU B 93 -23.788 -14.779 -0.175 1.00 79.13 C
+ANISOU 1403 CG GLU B 93 10652 10826 8585 -318 -84 -555 C
+ATOM 1404 CD GLU B 93 -22.987 -16.055 -0.039 1.00 76.96 C
+ANISOU 1404 CD GLU B 93 10243 10705 8292 -298 -222 -415 C
+ATOM 1405 OE1 GLU B 93 -21.780 -16.023 -0.371 1.00 79.66 O
+ANISOU 1405 OE1 GLU B 93 10469 11135 8663 -371 -367 -426 O
+ATOM 1406 OE2 GLU B 93 -23.601 -17.080 0.373 1.00 67.00 O
+ANISOU 1406 OE2 GLU B 93 8994 9478 6985 -203 -176 -287 O
+ATOM 1407 N GLU B 94 -24.725 -11.432 -0.566 1.00 69.03 N
+ANISOU 1407 N GLU B 94 9811 9108 7309 -360 117 -926 N
+ATOM 1408 CA GLU B 94 -24.928 -10.483 0.552 1.00 77.95 C
+ANISOU 1408 CA GLU B 94 11229 10170 8216 -366 159 -1102 C
+ATOM 1409 C GLU B 94 -26.428 -10.119 0.763 1.00 81.07 C
+ANISOU 1409 C GLU B 94 11734 10485 8584 -108 385 -1134 C
+ATOM 1410 O GLU B 94 -26.904 -10.013 1.908 1.00 85.54 O
+ANISOU 1410 O GLU B 94 12445 11120 8935 -23 471 -1211 O
+ATOM 1411 CB GLU B 94 -24.036 -9.252 0.313 1.00 87.19 C
+ANISOU 1411 CB GLU B 94 12594 11164 9368 -580 56 -1254 C
+ATOM 1412 CG GLU B 94 -24.432 -7.953 1.012 1.00106.45 C
+ANISOU 1412 CG GLU B 94 15427 13387 11633 -560 129 -1466 C
+ATOM 1413 CD GLU B 94 -23.735 -7.773 2.341 1.00110.68 C
+ANISOU 1413 CD GLU B 94 16139 14025 11889 -732 8 -1602 C
+ATOM 1414 OE1 GLU B 94 -22.649 -8.362 2.521 1.00117.37 O
+ANISOU 1414 OE1 GLU B 94 16802 15085 12706 -936 -180 -1543 O
+ATOM 1415 OE2 GLU B 94 -24.273 -7.047 3.196 1.00115.53 O
+ANISOU 1415 OE2 GLU B 94 17075 14520 12301 -644 98 -1769 O
+ATOM 1416 N ALA B 95 -27.170 -9.967 -0.337 1.00 78.47 N
+ANISOU 1416 N ALA B 95 11311 10048 8454 26 480 -1068 N
+ATOM 1417 CA ALA B 95 -28.574 -9.572 -0.290 1.00 77.65 C
+ANISOU 1417 CA ALA B 95 11250 9907 8344 296 683 -1084 C
+ATOM 1418 C ALA B 95 -29.499 -10.685 0.182 1.00 81.60 C
+ANISOU 1418 C ALA B 95 11531 10661 8809 409 797 -947 C
+ATOM 1419 O ALA B 95 -30.560 -10.398 0.728 1.00 86.75 O
+ANISOU 1419 O ALA B 95 12220 11380 9361 612 978 -982 O
+ATOM 1420 CB ALA B 95 -29.025 -9.052 -1.654 1.00 73.64 C
+ANISOU 1420 CB ALA B 95 10698 9230 8050 400 717 -1040 C
+ATOM 1421 N ILE B 96 -29.102 -11.941 -0.054 1.00 86.66 N
+ANISOU 1421 N ILE B 96 11957 11441 9527 280 698 -787 N
+ATOM 1422 CA ILE B 96 -29.871 -13.143 0.330 1.00 86.56 C
+ANISOU 1422 CA ILE B 96 11762 11641 9485 314 780 -627 C
+ATOM 1423 C ILE B 96 -29.477 -13.617 1.721 1.00 84.77 C
+ANISOU 1423 C ILE B 96 11641 11556 9011 242 759 -633 C
+ATOM 1424 O ILE B 96 -29.685 -14.761 2.056 1.00 83.12 O
+ANISOU 1424 O ILE B 96 11324 11491 8764 195 764 -478 O
+ATOM 1425 CB ILE B 96 -29.623 -14.323 -0.663 1.00 90.19 C
+ANISOU 1425 CB ILE B 96 12007 12122 10139 213 673 -451 C
+ATOM 1426 CG1 ILE B 96 -30.006 -13.941 -2.082 1.00 90.30 C
+ANISOU 1426 CG1 ILE B 96 11917 12018 10374 272 679 -433 C
+ATOM 1427 CG2 ILE B 96 -30.408 -15.587 -0.291 1.00 96.15 C
+ANISOU 1427 CG2 ILE B 96 12623 13049 10858 195 743 -278 C
+ATOM 1428 CD1 ILE B 96 -31.453 -13.513 -2.211 1.00 91.73 C
+ANISOU 1428 CD1 ILE B 96 12017 12259 10577 456 854 -422 C
+ATOM 1429 N MET B 97 -28.867 -12.760 2.519 1.00 96.04 N
+ANISOU 1429 N MET B 97 13305 12930 10255 212 718 -806 N
+ATOM 1430 CA MET B 97 -28.752 -13.030 3.959 1.00108.10 C
+ANISOU 1430 CA MET B 97 14968 14612 11491 186 733 -832 C
+ATOM 1431 C MET B 97 -29.333 -11.852 4.784 1.00112.54 C
+ANISOU 1431 C MET B 97 15786 15132 11839 327 893 -1037 C
+ATOM 1432 O MET B 97 -30.047 -12.090 5.759 1.00113.07 O
+ANISOU 1432 O MET B 97 15896 15370 11696 422 1051 -1023 O
+ATOM 1433 CB MET B 97 -27.301 -13.410 4.291 1.00103.41 C
+ANISOU 1433 CB MET B 97 14414 14054 10823 -6 483 -827 C
+ATOM 1434 CG MET B 97 -26.722 -14.327 3.206 1.00102.45 C
+ANISOU 1434 CG MET B 97 14057 13920 10946 -76 347 -664 C
+ATOM 1435 SD MET B 97 -25.246 -15.322 3.559 1.00117.34 S
+ANISOU 1435 SD MET B 97 15877 15943 12762 -203 84 -561 S
+ATOM 1436 CE MET B 97 -24.043 -14.027 3.907 1.00103.96 C
+ANISOU 1436 CE MET B 97 14327 14224 10946 -367 -80 -786 C
+ATOM 1437 N LEU B 98 -29.087 -10.604 4.344 1.00119.26 N
+ANISOU 1437 N LEU B 98 16822 15748 12742 354 871 -1217 N
+ATOM 1438 CA LEU B 98 -29.639 -9.356 4.952 1.00123.66 C
+ANISOU 1438 CA LEU B 98 17689 16180 13115 531 1024 -1437 C
+ATOM 1439 C LEU B 98 -30.866 -9.535 5.875 1.00124.53 C
+ANISOU 1439 C LEU B 98 17792 16500 13023 769 1286 -1430 C
+ATOM 1440 O LEU B 98 -32.001 -9.708 5.420 1.00113.44 O
+ANISOU 1440 O LEU B 98 16173 15192 11737 973 1471 -1329 O
+ATOM 1441 CB LEU B 98 -29.945 -8.322 3.862 1.00113.25 C
+ANISOU 1441 CB LEU B 98 16446 14588 11996 658 1065 -1512 C
+TER 1442 LEU B 98
+HETATM 1443 FE1 FES A 201 -15.271 -14.172 -26.506 1.00 44.84 FE
+ANISOU 1443 FE1 FES A 201 6513 5131 5392 -266 1479 -131 FE
+HETATM 1444 FE2 FES A 201 -13.886 -13.246 -28.774 1.00 43.12 FE
+ANISOU 1444 FE2 FES A 201 6178 4976 5230 -316 1145 -235 FE
+HETATM 1445 S1 FES A 201 -13.297 -13.107 -26.664 1.00 54.52 S
+ANISOU 1445 S1 FES A 201 7773 6436 6506 -96 1188 -102 S
+HETATM 1446 S2 FES A 201 -15.933 -14.020 -28.613 1.00 59.15 S
+ANISOU 1446 S2 FES A 201 8119 7001 7354 -510 1368 -300 S
+HETATM 1447 CL CL A 202 -7.271 -6.453 -50.333 1.00 66.75 CL
+ANISOU 1447 CL CL A 202 8476 9756 7127 -15 320 384 CL
+HETATM 1448 FE1 FES B 201 -24.764 -23.326 -3.870 1.00 41.78 FE
+ANISOU 1448 FE1 FES B 201 5702 5769 4400 126 -205 391 FE
+HETATM 1449 FE2 FES B 201 -25.332 -22.283 -6.421 1.00 37.10 FE
+ANISOU 1449 FE2 FES B 201 4925 5056 4113 76 -116 248 FE
+HETATM 1450 S1 FES B 201 -23.427 -22.583 -5.443 1.00 50.74 S
+ANISOU 1450 S1 FES B 201 6641 6936 5699 218 -266 253 S
+HETATM 1451 S2 FES B 201 -26.631 -22.784 -4.792 1.00 52.36 S
+ANISOU 1451 S2 FES B 201 6974 7030 5890 -29 -34 366 S
+HETATM 1452 CL CL B 202 -35.655 -14.036 -25.892 1.00 63.11 CL
+ANISOU 1452 CL CL B 202 7828 8449 7699 533 -737 677 CL
+HETATM 1453 O HOH A 301 -5.604 9.621 -30.726 1.00 71.67 O
+ANISOU 1453 O HOH A 301 9741 6570 10921 -503 1286 -1155 O
+HETATM 1454 O HOH A 302 -9.976 -2.053 -46.606 1.00 60.80 O
+ANISOU 1454 O HOH A 302 7211 8696 7192 404 154 904 O
+HETATM 1455 O HOH A 303 -25.242 -15.543 -37.047 1.00 85.19 O
+ANISOU 1455 O HOH A 303 9346 12270 10750 -2562 894 -1311 O
+HETATM 1456 O HOH A 304 -8.615 -1.310 -44.946 1.00 51.68 O
+ANISOU 1456 O HOH A 304 6188 7004 6442 421 264 856 O
+HETATM 1457 O HOH A 305 -6.495 -20.103 -36.227 1.00 66.33 O
+ANISOU 1457 O HOH A 305 9914 6783 8504 -320 2093 -239 O
+HETATM 1458 O HOH A 306 -15.756 -22.203 -33.220 1.00 75.41 O
+ANISOU 1458 O HOH A 306 10813 7895 9944 -1695 2618 -965 O
+HETATM 1459 O HOH A 307 -29.136 -5.336 -24.489 1.00 68.01 O
+ANISOU 1459 O HOH A 307 7381 9218 9240 419 2448 230 O
+HETATM 1460 O HOH A 308 -31.273 -2.568 -37.684 1.00 80.28 O
+ANISOU 1460 O HOH A 308 6166 13841 10493 472 476 1418 O
+HETATM 1461 O HOH A 309 -12.248 -4.951 -30.108 1.00 43.84 O
+ANISOU 1461 O HOH A 309 5908 5247 5501 5 448 -372 O
+HETATM 1462 O HOH A 310 1.254 -8.613 -35.928 1.00 55.59 O
+ANISOU 1462 O HOH A 310 7059 6744 7319 249 231 444 O
+HETATM 1463 O HOH A 311 -14.907 -5.701 -24.000 1.00 59.32 O
+ANISOU 1463 O HOH A 311 8290 7265 6981 168 940 -557 O
+HETATM 1464 O HOH A 312 -10.817 -7.018 -29.284 1.00 41.62 O
+ANISOU 1464 O HOH A 312 5784 4984 5045 -27 423 -341 O
+HETATM 1465 O HOH A 313 2.334 -6.045 -37.941 1.00 48.64 O
+ANISOU 1465 O HOH A 313 5952 5811 6716 139 202 488 O
+HETATM 1466 O HOH A 314 -15.179 -4.981 -27.668 1.00 53.48 O
+ANISOU 1466 O HOH A 314 7171 6503 6643 87 768 -437 O
+HETATM 1467 O HOH A 315 -0.012 -13.050 -38.710 1.00 53.80 O
+ANISOU 1467 O HOH A 315 7374 6131 6936 327 934 389 O
+HETATM 1468 O HOH A 316 -4.588 7.953 -34.979 1.00 55.02 O
+ANISOU 1468 O HOH A 316 7176 4879 8848 -164 1054 -241 O
+HETATM 1469 O HOH A 317 -7.401 1.030 -46.099 1.00 71.07 O
+ANISOU 1469 O HOH A 317 8592 9256 9152 695 478 1286 O
+HETATM 1470 O HOH B 301 -17.227 -5.370 -20.274 1.00 67.76 O
+ANISOU 1470 O HOH B 301 9358 8307 8078 -2373 512 237 O
+HETATM 1471 O HOH B 302 -16.773 -19.622 -11.270 1.00 63.07 O
+ANISOU 1471 O HOH B 302 7080 9333 7548 271 -261 -62 O
+HETATM 1472 O HOH B 303 -33.187 -25.431 -12.986 1.00 63.64 O
+ANISOU 1472 O HOH B 303 8214 8071 7895 -876 -197 526 O
+HETATM 1473 O HOH B 304 -33.633 -10.672 -27.113 1.00 59.09 O
+ANISOU 1473 O HOH B 304 8015 7375 7058 804 -526 819 O
+HETATM 1474 O HOH B 305 -29.987 -6.037 -4.511 1.00 66.34 O
+ANISOU 1474 O HOH B 305 10207 7566 7433 765 801 -1097 O
+HETATM 1475 O HOH B 306 -13.899 -20.518 -11.569 1.00 81.57 O
+ANISOU 1475 O HOH B 306 8854 12357 9778 587 -327 -7 O
+HETATM 1476 O HOH B 307 -22.312 -17.195 -9.418 1.00 47.15 O
+ANISOU 1476 O HOH B 307 5812 6486 5616 -124 -89 -163 O
+HETATM 1477 O HOH B 308 -34.144 -23.559 -20.590 1.00 51.64 O
+ANISOU 1477 O HOH B 308 6612 6627 6378 -778 -651 271 O
+HETATM 1478 O HOH B 309 -24.795 -27.082 -17.164 1.00 48.12 O
+ANISOU 1478 O HOH B 309 7064 5473 5745 466 -276 10 O
+HETATM 1479 O HOH B 310 -32.217 -13.054 4.356 1.00 88.41 O
+ANISOU 1479 O HOH B 310 12239 12424 8929 628 1337 -721 O
+HETATM 1480 O HOH B 311 -23.165 -14.400 -5.121 1.00 48.01 O
+ANISOU 1480 O HOH B 311 6333 6580 5329 -351 -63 -448 O
+HETATM 1481 O HOH B 312 -20.108 -19.770 -22.685 1.00 54.43 O
+ANISOU 1481 O HOH B 312 6815 7445 6419 397 344 -109 O
+HETATM 1482 O HOH B 313 -29.379 -10.101 -22.915 1.00 62.52 O
+ANISOU 1482 O HOH B 313 8624 7375 7757 322 17 426 O
+HETATM 1483 O HOH B 314 -23.815 -23.224 -24.077 1.00 46.69 O
+ANISOU 1483 O HOH B 314 6623 5782 5333 479 -2 -224 O
+HETATM 1484 O HOH B 315 -31.917 -9.402 -21.408 1.00 63.89 O
+ANISOU 1484 O HOH B 315 8654 7581 8038 758 -17 436 O
+HETATM 1485 O HOH B 316 -43.034 -22.451 -5.025 1.00 82.32 O
+ANISOU 1485 O HOH B 316 8131 13423 9723 -1213 1232 1263 O
+HETATM 1486 O HOH B 317 -13.942 -19.466 -15.267 1.00 82.69 O
+ANISOU 1486 O HOH B 317 8966 12435 10017 416 49 -55 O
+HETATM 1487 O HOH B 318 -23.364 -14.585 -8.816 1.00 50.88 O
+ANISOU 1487 O HOH B 318 6512 6761 6060 -288 14 -313 O
+HETATM 1488 O HOH B 319 -41.794 -18.985 0.026 0.50 60.91 O
+ANISOU 1488 O HOH B 319 5945 10874 6323 -9 2050 811 O
+HETATM 1489 O HOH B 320 -29.672 -24.828 -29.742 1.00 55.49 O
+ANISOU 1489 O HOH B 320 8618 6605 5859 -263 -781 -333 O
+HETATM 1490 O HOH B 321 -38.215 -20.833 -12.380 1.00 58.66 O
+ANISOU 1490 O HOH B 321 6197 8706 7384 -584 159 654 O
+CONECT 301 1443
+CONECT 333 1443
+CONECT 351 1444
+CONECT 569 1444
+CONECT 1022 1448
+CONECT 1054 1448
+CONECT 1072 1449
+CONECT 1290 1449
+CONECT 1443 301 333 1445 1446
+CONECT 1444 351 569 1445 1446
+CONECT 1445 1443 1444
+CONECT 1446 1443 1444
+CONECT 1448 1022 1054 1450 1451
+CONECT 1449 1072 1290 1450 1451
+CONECT 1450 1448 1449
+CONECT 1451 1448 1449
+MASTER 410 0 4 7 14 0 6 6 1488 2 16 18
+END
--- /dev/null
+package jalview.ext.rbvi.chimera;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+public class AtomSpecModelTest
+{
+ @Test(groups = "Functional")
+ public void testGetAtomSpec()
+ {
+ AtomSpecModel model = new AtomSpecModel();
+ assertEquals(model.getAtomSpec(), "");
+ model.addRange(1, 2, 4, "A");
+ assertEquals(model.getAtomSpec(), "#1:2-4.A");
+ model.addRange(1, 8, 8, "A");
+ assertEquals(model.getAtomSpec(), "#1:2-4.A,8.A");
+ model.addRange(1, 5, 7, "B");
+ assertEquals(model.getAtomSpec(), "#1:2-4.A,8.A,5-7.B");
+ model.addRange(1, 3, 5, "A");
+ assertEquals(model.getAtomSpec(), "#1:2-5.A,8.A,5-7.B");
+ model.addRange(0, 1, 4, "B");
+ assertEquals(model.getAtomSpec(), "#0:1-4.B|#1:2-5.A,8.A,5-7.B");
+ model.addRange(0, 5, 9, "C");
+ assertEquals(model.getAtomSpec(), "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-7.B");
+ model.addRange(1, 8, 10, "B");
+ assertEquals(model.getAtomSpec(), "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
+ model.addRange(1, 8, 9, "B");
+ assertEquals(model.getAtomSpec(), "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
+ model.addRange(0, 3, 10, "C"); // subsumes 5-9
+ assertEquals(model.getAtomSpec(), "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B");
+ }
+
+}
*/
package jalview.ext.rbvi.chimera;
-import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertTrue;
-
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
import jalview.gui.JvOptionPane;
+import jalview.gui.SequenceRenderer;
+import jalview.schemes.JalviewColourScheme;
+import jalview.structure.StructureMapping;
+import jalview.structure.StructureMappingcommandSet;
+import jalview.structure.StructureSelectionManager;
import java.awt.Color;
-import java.util.Arrays;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.SortedMap;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
}
@Test(groups = { "Functional" })
- public void testAddColourRange()
- {
- Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> map = new LinkedHashMap<Color, SortedMap<Integer, Map<String, List<int[]>>>>();
- ChimeraCommands.addColourRange(map, Color.pink, 1, 2, 4, "A");
- ChimeraCommands.addColourRange(map, Color.pink, 1, 8, 8, "A");
- ChimeraCommands.addColourRange(map, Color.pink, 1, 5, 7, "B");
- ChimeraCommands.addColourRange(map, Color.red, 1, 3, 5, "A");
- ChimeraCommands.addColourRange(map, Color.red, 0, 1, 4, "B");
- ChimeraCommands.addColourRange(map, Color.orange, 0, 5, 9, "C");
-
- // three colours mapped
- assertEquals(3, map.keySet().size());
-
- // Red has two models, Pink and Orange one each
- assertEquals(2, map.get(Color.red).keySet().size());
- assertEquals(1, map.get(Color.orange).keySet().size());
- assertEquals(1, map.get(Color.pink).keySet().size());
-
- // pink model 1 has two chains, red.0 / red.1 / orange.0 one each
- assertEquals(2, map.get(Color.pink).get(1).keySet().size());
- assertEquals(1, map.get(Color.red).get(0).keySet().size());
- assertEquals(1, map.get(Color.red).get(1).keySet().size());
- assertEquals(1, map.get(Color.orange).get(0).keySet().size());
-
- // inspect positions
- List<int[]> posList = map.get(Color.pink).get(1).get("A");
- assertEquals(2, posList.size());
- assertTrue(Arrays.equals(new int[] { 2, 4 }, posList.get(0)));
- assertTrue(Arrays.equals(new int[] { 8, 8 }, posList.get(1)));
-
- posList = map.get(Color.pink).get(1).get("B");
- assertEquals(1, posList.size());
- assertTrue(Arrays.equals(new int[] { 5, 7 }, posList.get(0)));
-
- posList = map.get(Color.red).get(0).get("B");
- assertEquals(1, posList.size());
- assertTrue(Arrays.equals(new int[] { 1, 4 }, posList.get(0)));
-
- posList = map.get(Color.red).get(1).get("A");
- assertEquals(1, posList.size());
- assertTrue(Arrays.equals(new int[] { 3, 5 }, posList.get(0)));
-
- posList = map.get(Color.orange).get(0).get("C");
- assertEquals(1, posList.size());
- assertTrue(Arrays.equals(new int[] { 5, 9 }, posList.get(0)));
- }
-
- @Test(groups = { "Functional" })
public void testBuildColourCommands()
{
- Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> map = new LinkedHashMap<Color, SortedMap<Integer, Map<String, List<int[]>>>>();
+ Map<Object, AtomSpecModel> map = new LinkedHashMap<Object, AtomSpecModel>();
ChimeraCommands.addColourRange(map, Color.blue, 0, 2, 5, "A");
ChimeraCommands.addColourRange(map, Color.blue, 0, 7, 7, "B");
ChimeraCommands.addColourRange(map, Color.blue, 0, 9, 23, "A");
ChimeraCommands.addColourRange(map, Color.yellow, 1, 8, 8, "A");
ChimeraCommands.addColourRange(map, Color.yellow, 1, 3, 5, "A");
ChimeraCommands.addColourRange(map, Color.red, 0, 3, 5, "A");
+ ChimeraCommands.addColourRange(map, Color.red, 0, 6, 9, "A");
// Colours should appear in the Chimera command in the order in which
- // they were added; within colour, by model, by chain, and positions as
- // added
+ // they were added; within colour, by model, by chain, ranges in start order
String command = ChimeraCommands.buildColourCommands(map).get(0);
assertEquals(
- "color #0000ff #0:2-5.A,9-23.A,7.B|#1:1.A,4-7.B; color #ffff00 #1:8.A,3-5.A; color #ff0000 #0:3-5.A",
- command);
+ command,
+ "color #0000ff #0:2-5.A,9-23.A,7.B|#1:1.A,4-7.B; color #ffff00 #1:3-5.A,8.A; color #ff0000 #0:3-9.A");
+ }
+
+ @Test(groups = { "Functional" })
+ public void testBuildSetAttributeCommands()
+ {
+ /*
+ * make a map of { featureType, {featureValue, {residue range specification } } }
+ */
+ Map<String, Map<Object, AtomSpecModel>> featuresMap = new LinkedHashMap<String, Map<Object, AtomSpecModel>>();
+ Map<Object, AtomSpecModel> featureValues = new HashMap<Object, AtomSpecModel>();
+
+ /*
+ * start with just one feature/value...
+ */
+ featuresMap.put("chain", featureValues);
+ ChimeraCommands.addColourRange(featureValues, "X", 0, 8, 20, "A");
+
+ List<String> commands = ChimeraCommands
+ .buildSetAttributeCommands(featuresMap);
+ assertEquals(1, commands.size());
+
+ /*
+ * feature name gets a jv_ namespace prefix
+ * feature value is quoted in case it contains spaces
+ */
+ assertEquals(commands.get(0), "setattr r jv_chain 'X' #0:8-20.A");
+
+ // add same feature value, overlapping range
+ ChimeraCommands.addColourRange(featureValues, "X", 0, 3, 9, "A");
+ // same feature value, contiguous range
+ ChimeraCommands.addColourRange(featureValues, "X", 0, 21, 25, "A");
+ commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+ assertEquals(1, commands.size());
+ assertEquals(commands.get(0), "setattr r jv_chain 'X' #0:3-25.A");
+
+ // same feature value and model, different chain
+ ChimeraCommands.addColourRange(featureValues, "X", 0, 21, 25, "B");
+ // same feature value and chain, different model
+ ChimeraCommands.addColourRange(featureValues, "X", 1, 26, 30, "A");
+ commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+ assertEquals(1, commands.size());
+ assertEquals(commands.get(0),
+ "setattr r jv_chain 'X' #0:3-25.A,21-25.B|#1:26-30.A");
+
+ // same feature, different value
+ ChimeraCommands.addColourRange(featureValues, "Y", 0, 40, 50, "A");
+ commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+ assertEquals(2, commands.size());
+ // commands are ordered by feature type but not by value
+ // so use contains to test for the expected command:
+ assertTrue(commands
+ .contains("setattr r jv_chain 'X' #0:3-25.A,21-25.B|#1:26-30.A"));
+ assertTrue(commands.contains("setattr r jv_chain 'Y' #0:40-50.A"));
+
+ featuresMap.clear();
+ featureValues.clear();
+ featuresMap.put("side-chain binding!", featureValues);
+ ChimeraCommands.addColourRange(featureValues,
+ "<html>metal <a href=\"http:a.b.c/x\"> 'ion!", 0, 7, 15,
+ "A");
+ // feature names are sanitised to change non-alphanumeric to underscore
+ // feature values are sanitised to encode single quote characters
+ commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+ assertTrue(commands
+ .contains("setattr r jv_side_chain_binding_ '<html>metal <a href=\"http:a.b.c/x\"> 'ion!' #0:7-15.A"));
+ }
+
+ /**
+ * Tests for the method that prefixes and sanitises a feature name so it can
+ * be used as a valid, namespaced attribute name in Chimera
+ */
+ @Test(groups = { "Functional" })
+ public void testMakeAttributeName()
+ {
+ assertEquals(ChimeraCommands.makeAttributeName(null), "jv_");
+ assertEquals(ChimeraCommands.makeAttributeName(""), "jv_");
+ assertEquals(ChimeraCommands.makeAttributeName("helix"), "jv_helix");
+ assertEquals(ChimeraCommands.makeAttributeName("Hello World 24"),
+ "jv_Hello_World_24");
+ assertEquals(
+ ChimeraCommands.makeAttributeName("!this is-a_very*{odd(name"),
+ "jv__this_is_a_very__odd_name");
+ // name ending in color gets underscore appended
+ assertEquals(ChimeraCommands.makeAttributeName("helixColor"),
+ "jv_helixColor_");
+ }
+
+ @Test(groups = { "Functional" })
+ public void testGetColourBySequenceCommands_hiddenColumns()
+ {
+ /*
+ * load these sequences, coloured by Strand propensity,
+ * with columns 2-4 hidden
+ */
+ SequenceI seq1 = new Sequence("seq1", "MHRSQSSSGG");
+ SequenceI seq2 = new Sequence("seq2", "MVRSNGGSSS");
+ AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
+ AlignFrame af = new AlignFrame(al, 800, 500);
+ af.changeColour_actionPerformed(JalviewColourScheme.Strand.toString());
+ ColumnSelection cs = new ColumnSelection();
+ cs.addElement(2);
+ cs.addElement(3);
+ cs.addElement(4);
+ af.getViewport().setColumnSelection(cs);
+ af.hideSelColumns_actionPerformed(null);
+ SequenceRenderer sr = new SequenceRenderer(af.getViewport());
+ SequenceI[][] seqs = new SequenceI[][] { { seq1 }, { seq2 } };
+ String[] files = new String[] { "seq1.pdb", "seq2.pdb" };
+ StructureSelectionManager ssm = new StructureSelectionManager();
+
+ /*
+ * map residues 1-10 to residues 21-30 (atoms 105-150) in structures
+ */
+ HashMap<Integer, int[]> map = new HashMap<Integer, int[]>();
+ for (int pos = 1; pos <= seq1.getLength(); pos++)
+ {
+ map.put(pos, new int[] { 20 + pos, 5 * (20 + pos) });
+ }
+ StructureMapping sm1 = new StructureMapping(seq1, "seq1.pdb", "pdb1",
+ "A", map, null);
+ ssm.addStructureMapping(sm1);
+ StructureMapping sm2 = new StructureMapping(seq2, "seq2.pdb", "pdb2",
+ "B", map, null);
+ ssm.addStructureMapping(sm2);
+
+ StructureMappingcommandSet[] commands = ChimeraCommands
+ .getColourBySequenceCommand(ssm, files, seqs, sr, af.alignPanel);
+ assertEquals(1, commands.length);
+ assertEquals(1, commands[0].commands.length);
+ String theCommand = commands[0].commands[0];
+ // M colour is #82827d (see strand.html help page)
+ assertTrue(theCommand.contains("color #82827d #0:21.A|#1:21.B"));
+ // H colour is #60609f
+ assertTrue(theCommand.contains("color #60609f #0:22.A"));
+ // V colour is #ffff00
+ assertTrue(theCommand.contains("color #ffff00 #1:22.B"));
+ // hidden columns are Gray (128, 128, 128)
+ assertTrue(theCommand.contains("color #808080 #0:23-25.A|#1:23-25.B"));
+ // S and G are both coloured #4949b6
+ assertTrue(theCommand.contains("color #4949b6 #0:26-30.A|#1:26-30.B"));
}
}
*/
package jalview.ext.rbvi.chimera;
-import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import jalview.api.FeatureRenderer;
import jalview.api.structures.JalviewStructureDisplayI;
import jalview.bin.Cache;
+import jalview.bin.Jalview;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
import jalview.gui.JvOptionPane;
import jalview.gui.Preferences;
import jalview.gui.StructureViewer;
import jalview.gui.StructureViewer.ViewerType;
+import jalview.io.FileLoader;
+import jalview.structure.StructureMapping;
+import jalview.structure.StructureSelectionManager;
+import jalview.ws.sifts.SiftsClient;
+import jalview.ws.sifts.SiftsException;
+import jalview.ws.sifts.SiftsSettings;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Vector;
import jalview.io.DataSourceType;
import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
}
+ private JalviewStructureDisplayI chimeraViewer;
+
/**
* @throws java.lang.Exception
*/
@BeforeClass(alwaysRun = true)
public static void setUpBeforeClass() throws Exception
{
- jalview.bin.Jalview.main(new String[] {
- "-noquestionnaire -nonews -props",
+ Jalview.main(new String[] { "-noquestionnaire", "-nonews", "-props",
"test/jalview/ext/rbvi/chimera/testProps.jvprops" });
+ Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
+ ViewerType.CHIMERA.name());
+ Cache.setProperty("SHOW_ANNOTATIONS", "false");
+ Cache.setProperty(Preferences.STRUCT_FROM_PDB, "false");
+ Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
+ ViewerType.CHIMERA.name());
+ Cache.setProperty("MAP_WITH_SIFTS", "true");
+ // TODO this should not be necessary!
+ SiftsSettings.setMapWithSifts(true);
}
/**
@AfterClass(alwaysRun = true)
public static void tearDownAfterClass() throws Exception
{
- jalview.gui.Desktop.instance.closeAll_actionPerformed(null);
+ Desktop.instance.closeAll_actionPerformed(null);
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void tearDownAfterTest() throws Exception
+ {
+ SiftsClient.setMockSiftsFile(null);
+ if (chimeraViewer != null)
+ {
+ chimeraViewer.closeViewer(true);
+ }
}
- @Test(groups = { "Functional" })
+ /**
+ * Load 1GAQ and view the first structure for which a PDB id is found. Note no
+ * network connection is needed - PDB file is read locally, SIFTS fetch fails
+ * so mapping falls back to Needleman-Wunsch - ok for this test.
+ */
+ // External as local install of Chimera required
+ @Test(groups = { "External" })
public void testSingleSeqViewChimera()
{
- Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
- ViewerType.CHIMERA.name());
String inFile = "examples/1gaq.txt";
- AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
- inFile, DataSourceType.FILE);
- assertTrue("Didn't read input file " + inFile, af != null);
- for (SequenceI sq : af.getViewport().getAlignment().getSequences())
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
+ DataSourceType.FILE);
+ assertNotNull(af, "Failed to create AlignFrame");
+ SequenceI sq = af.getViewport().getAlignment().getSequenceAt(0);
+ assertEquals(sq.getName(), "1GAQ|A");
+ SequenceI dsq = sq.getDatasetSequence();
+ Vector<PDBEntry> pdbIds = dsq.getAllPDBEntries();
+ assertEquals(pdbIds.size(), 1);
+ PDBEntry pdbEntry = pdbIds.get(0);
+ assertEquals(pdbEntry.getId(), "1GAQ");
+ StructureViewer structureViewer = new StructureViewer(af.getViewport()
+ .getStructureSelectionManager());
+ chimeraViewer = structureViewer.viewStructures(pdbEntry,
+ new SequenceI[] { sq }, af.getCurrentView().getAlignPanel());
+ JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
+ .getBinding();
+
+ /*
+ * Wait for viewer load thread to complete
+ */
+ while (!binding.isFinishedInit())
{
- System.out.println("** sq=" + sq.getName());
- SequenceI dsq = sq.getDatasetSequence();
- while (dsq.getDatasetSequence() != null)
+ try
+ {
+ Thread.sleep(500);
+ } catch (InterruptedException e)
{
- dsq = dsq.getDatasetSequence();
}
- if (dsq.getAllPDBEntries() != null
- && dsq.getAllPDBEntries().size() > 0)
+ }
+
+ assertTrue(binding.isChimeraRunning(), "Failed to start Chimera");
+
+ assertEquals(chimeraViewer.getBinding().getPdbCount(), 1);
+ chimeraViewer.closeViewer(true);
+ chimeraViewer = null;
+ return;
+ }
+
+ /**
+ * Test for writing Jalview features as attributes on mapped residues in
+ * Chimera. Note this uses local copies of PDB and SIFTS file, no network
+ * connection required.
+ *
+ * @throws IOException
+ * @throws SiftsException
+ */
+ // External as this requires a local install of Chimera
+ @Test(groups = { "External" })
+ public void testTransferFeatures() throws IOException, SiftsException
+ {
+ String inFile = "examples/uniref50.fa";
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
+ DataSourceType.FILE);
+ assertNotNull(af, "Failed to create AlignFrame");
+ SequenceI sq = af.getViewport().getAlignment().findName("FER2_ARATH");
+ assertNotNull(sq, "Didn't find FER2_ARATH");
+
+ /*
+ * need a Uniprot dbref for SIFTS mapping to work!!
+ */
+ sq.addDBRef(new DBRefEntry("UNIPROT", "0", "P16972", null));
+
+ /*
+ * use local test PDB and SIFTS files
+ */
+ String pdbFilePath = new File(
+ "test/jalview/ext/rbvi/chimera/4zho.pdb").getPath();
+ PDBEntry pdbEntry = new PDBEntry("4ZHO", null, null, pdbFilePath);
+ String siftsFilePath = new File(
+ "test/jalview/ext/rbvi/chimera/4zho.xml.gz")
+ .getPath();
+ SiftsClient.setMockSiftsFile(new File(siftsFilePath));
+
+ StructureViewer structureViewer = new StructureViewer(af.getViewport()
+ .getStructureSelectionManager());
+ chimeraViewer = structureViewer.viewStructures(pdbEntry,
+ new SequenceI[] { sq }, af.getCurrentView().getAlignPanel());
+
+ JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
+ .getBinding();
+ do
+ {
+ try
+ {
+ Thread.sleep(500);
+ } catch (InterruptedException e)
+ {
+ }
+ } while (!binding.isFinishedInit());
+
+ assertTrue(binding.isChimeraRunning(), "Failed to launch Chimera");
+
+ assertEquals(binding.getPdbCount(), 1);
+
+ /*
+ * check mapping is (sequence) 53-145 to (structure) 2-94 A/B
+ * (or possibly 52-145 to 1-94 - see JAL-2319)
+ */
+ StructureSelectionManager ssm = binding.getSsm();
+ String pdbFile = binding.getStructureFiles()[0];
+ StructureMapping[] mappings = ssm.getMapping(pdbFile);
+ assertTrue(mappings[0].getMappingDetailsOutput().contains("SIFTS"),
+ "Failed to perform SIFTS mapping");
+ assertEquals(mappings.length, 2);
+ assertEquals(mappings[0].getChain(), "A");
+ assertEquals(mappings[0].getPDBResNum(53), 2);
+ assertEquals(mappings[0].getPDBResNum(145), 94);
+ assertEquals(mappings[1].getChain(), "B");
+ assertEquals(mappings[1].getPDBResNum(53), 2);
+ assertEquals(mappings[1].getPDBResNum(145), 94);
+
+ /*
+ * now add some features to FER2_ARATH
+ */
+ // feature on a sequence region not mapped to structure:
+ sq.addSequenceFeature(new SequenceFeature("transit peptide",
+ "chloroplast", 1, 51, Float.NaN, null));
+ // feature on a region mapped to structure:
+ sq.addSequenceFeature(new SequenceFeature("domain",
+ "2Fe-2S ferredoxin-type", 55, 145, Float.NaN, null));
+ // on sparse positions of the sequence
+ sq.addSequenceFeature(new SequenceFeature("metal ion-binding site",
+ "Iron-Sulfur (2Fe-2S)", 91, 91, Float.NaN, null));
+ sq.addSequenceFeature(new SequenceFeature("metal ion-binding site",
+ "Iron-Sulfur (2Fe-2S)", 96, 96, Float.NaN, null));
+ // on a sequence region that is partially mapped to structure:
+ sq.addSequenceFeature(new SequenceFeature("helix", null, 50, 60,
+ Float.NaN, null));
+ // and again:
+ sq.addSequenceFeature(new SequenceFeature("chain", null, 50, 70,
+ Float.NaN, null));
+ // add numeric valued features - score is set as attribute value
+ sq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 62,
+ 62, -2.1f, null));
+ sq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 65,
+ 65, 3.6f, null));
+ sq.addSequenceFeature(new SequenceFeature("RESNUM", "ALA: 2 4zhoA",
+ 53, 53, Float.NaN, null));
+
+ /*
+ * set all features visible except for chain
+ */
+ af.setShowSeqFeatures(true);
+ FeatureRenderer fr = af.getFeatureRenderer();
+ fr.setVisible("transit peptide");
+ fr.setVisible("domain");
+ fr.setVisible("metal ion-binding site");
+ fr.setVisible("helix");
+ fr.setVisible("kd");
+ fr.setVisible("RESNUM");
+
+ /*
+ * 'perform' menu action to copy visible features to
+ * attributes in Chimera
+ */
+ // TODO rename and pull up method to binding interface
+ // once functionality is added for Jmol as well
+ binding.sendFeaturesToViewer(af.getViewport().getAlignPanel());
+
+ /*
+ * give Chimera time to open the commands file and execute it
+ */
+ try
+ {
+ Thread.sleep(1000);
+ } catch (InterruptedException e)
+ {
+ }
+
+ /*
+ * ask Chimera for its residue attribute names
+ */
+ List<String> reply = binding.sendChimeraCommand("list resattr", true);
+ // prefixed and sanitised attribute names for Jalview features:
+ assertTrue(reply.contains("resattr jv_domain"));
+ assertTrue(reply.contains("resattr jv_metal_ion_binding_site"));
+ assertTrue(reply.contains("resattr jv_helix"));
+ assertTrue(reply.contains("resattr jv_kd"));
+ assertTrue(reply.contains("resattr jv_RESNUM"));
+ // feature is not on a mapped region - no attribute created
+ assertFalse(reply.contains("resattr jv_transit_peptide"));
+ // feature is not visible - no attribute created
+ assertFalse(reply.contains("resattr jv_chain"));
+
+ /*
+ * ask Chimera for residues with an attribute
+ * 91 and 96 on sequence --> residues 40 and 45 on chains A and B
+ */
+ reply = binding.sendChimeraCommand(
+ "list resi att jv_metal_ion_binding_site", true);
+ assertEquals(reply.size(), 4);
+ assertTrue(reply
+ .contains("residue id #0:40.A jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 40"));
+ assertTrue(reply
+ .contains("residue id #0:45.A jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 45"));
+ assertTrue(reply
+ .contains("residue id #0:40.B jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 40"));
+ assertTrue(reply
+ .contains("residue id #0:45.B jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 45"));
+
+ /*
+ * check attributes with score values
+ * sequence positions 62 and 65 --> residues 11 and 14 on chains A and B
+ */
+ reply = binding.sendChimeraCommand("list resi att jv_kd", true);
+ assertEquals(reply.size(), 4);
+ assertTrue(reply.contains("residue id #0:11.A jv_kd -2.1 index 11"));
+ assertTrue(reply.contains("residue id #0:14.A jv_kd 3.6 index 14"));
+ assertTrue(reply.contains("residue id #0:11.B jv_kd -2.1 index 11"));
+ assertTrue(reply.contains("residue id #0:14.B jv_kd 3.6 index 14"));
+
+ /*
+ * list residues with positive kd score
+ */
+ reply = binding.sendChimeraCommand(
+ "list resi spec :*/jv_kd>0 attr jv_kd", true);
+ assertEquals(reply.size(), 2);
+ assertTrue(reply.contains("residue id #0:14.A jv_kd 3.6 index 14"));
+ assertTrue(reply.contains("residue id #0:14.B jv_kd 3.6 index 14"));
+
+ SiftsClient.setMockSiftsFile(null);
+ chimeraViewer.closeViewer(true);
+ chimeraViewer = null;
+ }
+
+ /**
+ * Test for creating Jalview features from attributes on mapped residues in
+ * Chimera. Note this uses local copies of PDB and SIFTS file, no network
+ * connection required.
+ *
+ * @throws IOException
+ * @throws SiftsException
+ */
+ // External as this requires a local install of Chimera
+ @Test(groups = { "External" })
+ public void testGetAttributes() throws IOException, SiftsException
+ {
+ String inFile = "examples/uniref50.fa";
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
+ DataSourceType.FILE);
+ assertNotNull(af, "Failed to create AlignFrame");
+ SequenceI fer2Arath = af.getViewport().getAlignment()
+ .findName("FER2_ARATH");
+ assertNotNull(fer2Arath, "Didn't find FER2_ARATH");
+
+ /*
+ * need a Uniprot dbref for SIFTS mapping to work!!
+ */
+ fer2Arath.addDBRef(new DBRefEntry("UNIPROT", "0", "P16972", null));
+
+ /*
+ * use local test PDB and SIFTS files
+ */
+ String pdbFilePath = new File(
+ "test/jalview/ext/rbvi/chimera/4zho.pdb").getPath();
+ PDBEntry pdbEntry = new PDBEntry("4ZHO", null, null, pdbFilePath);
+ String siftsFilePath = new File(
+ "test/jalview/ext/rbvi/chimera/4zho.xml.gz")
+ .getPath();
+ SiftsClient.setMockSiftsFile(new File(siftsFilePath));
+
+ StructureViewer structureViewer = new StructureViewer(af.getViewport()
+ .getStructureSelectionManager());
+ chimeraViewer = structureViewer.viewStructures(pdbEntry,
+ new SequenceI[] { fer2Arath }, af.getCurrentView()
+ .getAlignPanel());
+
+ JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
+ .getBinding();
+ do
+ {
+ try
+ {
+ Thread.sleep(500);
+ } catch (InterruptedException e)
{
- for (int q = 0; q < dsq.getAllPDBEntries().size(); q++)
- {
- final StructureViewer structureViewer = new StructureViewer(af
- .getViewport().getStructureSelectionManager());
- structureViewer.setViewerType(ViewerType.CHIMERA);
- JalviewStructureDisplayI chimeraViewer = structureViewer
- .viewStructures(dsq.getAllPDBEntries().elementAt(q),
- new SequenceI[] { sq }, af.getCurrentView()
- .getAlignPanel());
- /*
- * Wait for viewer load thread to complete
- */
- while (!chimeraViewer.getBinding().isFinishedInit())
- {
- try
- {
- Thread.sleep(500);
- } catch (InterruptedException e)
- {
- }
- }
- assertEquals(1, chimeraViewer.getBinding().getPdbCount());
- chimeraViewer.closeViewer(true);
- // todo: break here means only once through this loop?
- break;
- }
- break;
}
+ } while (!binding.isFinishedInit());
+
+ assertTrue(binding.isChimeraRunning(), "Failed to launch Chimera");
+
+ assertEquals(binding.getPdbCount(), 1);
+
+ /*
+ * 'perform' menu action to copy visible features to
+ * attributes in Chimera
+ */
+ // TODO rename and pull up method to binding interface
+ // once functionality is added for Jmol as well
+ binding.copyStructureAttributesToFeatures("isHelix", af.getViewport()
+ .getAlignPanel());
+
+ /*
+ * verify 22 residues have isHelix feature
+ * (may merge into ranges in future)
+ */
+ af.setShowSeqFeatures(true);
+ FeatureRenderer fr = af.getFeatureRenderer();
+ fr.setVisible("isHelix");
+ for (int res = 75; res <= 83; res++)
+ {
+ checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
}
+ for (int res = 117; res <= 123; res++)
+ {
+ checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
+ }
+ for (int res = 129; res <= 131; res++)
+ {
+ checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
+ }
+ for (int res = 143; res <= 145; res++)
+ {
+ checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
+ }
+
+ /*
+ * fetch a numeric valued attribute
+ */
+ binding.copyStructureAttributesToFeatures("phi", af.getViewport()
+ .getAlignPanel());
+ fr.setVisible("phi");
+ List<SequenceFeature> fs = fr.findFeaturesAtRes(fer2Arath, 54);
+ assertEquals(fs.size(), 3);
+ assertEquals(fs.get(0).getType(), "RESNUM");
+ assertEquals(fs.get(1).getType(), "phi");
+ assertEquals(fs.get(2).getType(), "phi");
+ assertEquals(fs.get(1).getDescription(), "A"); // chain
+ assertEquals(fs.get(2).getDescription(), "B");
+ assertEquals(fs.get(1).getScore(), -131.0713f, 0.001f);
+ assertEquals(fs.get(2).getScore(), -127.39512, 0.001f);
+
+ /*
+ * tear down - also in AfterMethod
+ */
+ SiftsClient.setMockSiftsFile(null);
+ chimeraViewer.closeViewer(true);
+ chimeraViewer = null;
+ }
+
+ /**
+ * Helper method to verify new feature at a sequence position
+ *
+ * @param seq
+ * @param fr
+ * @param res
+ * @param featureType
+ */
+ protected void checkFeaturesAtRes(SequenceI seq, FeatureRenderer fr,
+ int res, String featureType)
+ {
+ String where = "at position " + res;
+ List<SequenceFeature> fs = fr.findFeaturesAtRes(seq, res);
+ assertEquals(fs.size(), 2, where);
+ assertEquals(fs.get(0).getType(), "RESNUM", where);
+ SequenceFeature sf = fs.get(1);
+ assertEquals(sf.getType(), featureType, where);
+ assertEquals(sf.getFeatureGroup(), "Chimera", where);
+ assertEquals(sf.getDescription(), "True", where);
+ assertEquals(sf.getScore(), Float.NaN, where);
}
}
-#---JalviewX Properties File---
-#Fri Apr 25 09:54:25 BST 2014
-SCREEN_Y=768
-SCREEN_X=936
-SHOW_WSDISCOVERY_ERRORS=true
-LATEST_VERSION=2.8.0b1
-SHOW_CONSERVATION=true
+ANNOTATIONCOLOUR_MAX=ff0000
+ANNOTATIONCOLOUR_MIN=ffc800
+ANTI_ALIAS=false
+AUTHORFNAMES=Jim Procter, Andrew Waterhouse, Jan Engelhardt, Lauren Lui, Michele Clamp, James Cuff, Steve Searle, David Martin & Geoff Barton
+AUTHORS=J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
+AUTO_CALC_CONSENSUS=true
+BLC_JVSUFFIX=true
+BUILD_DATE=01 November 2013
+CLUSTAL_JVSUFFIX=true
+DAS_ACTIVE_SOURCE=uniprot\t
+DAS_LOCAL_SOURCE=
+DAS_REGISTRY_URL=http\://www.ebi.ac.uk/das-srv/registry/das/
+DEFAULT_COLOUR=None
+DEFAULT_FILE_FORMAT=FASTA
+FASTA_JVSUFFIX=true
+FIGURE_AUTOIDWIDTH=false
+FIGURE_USERIDWIDTH=
+FONT_NAME=SansSerif
+FONT_SIZE=10
+FONT_STYLE=plain
+GAP_SYMBOL=-
+ID_ITALICS=true
+JALVIEW_NEWS_RSS_LASTMODIFIED=Apr 23, 2014 2\:53\:26 PM
+JALVIEW_RSS_WINDOW_SCREEN_HEIGHT=328
JALVIEW_RSS_WINDOW_SCREEN_WIDTH=550
+JALVIEW_RSS_WINDOW_SCREEN_X=0
+JALVIEW_RSS_WINDOW_SCREEN_Y=0
+JAVA_CONSOLE_SCREEN_HEIGHT=162
JAVA_CONSOLE_SCREEN_WIDTH=450
+JAVA_CONSOLE_SCREEN_X=830
+JAVA_CONSOLE_SCREEN_Y=475
+JWS2HOSTURLS=http\://www.compbio.dundee.ac.uk/jabaws
LAST_DIRECTORY=/Volumes/Data/Users/jimp/Documents/testing/Jalview/examples
-ID_ITALICS=true
-SORT_ALIGNMENT=No sort
-SHOW_IDENTITY=true
-WSMENU_BYHOST=false
-SEQUENCE_LINKS=EMBL-EBI Search|http\://www.ebi.ac.uk/ebisearch/search.ebi?db\=allebi&query\=$SEQUENCE_ID$
-SHOW_FULLSCREEN=false
-RECENT_URL=http\://www.jalview.org/examples/exampleFile_2_7.jar
-FONT_NAME=SansSerif
-BLC_JVSUFFIX=true
-VERSION_CHECK=false
-YEAR=2011
-SHOW_DBREFS_TOOLTIP=true
+LATEST_VERSION=2.8.0b1
MSF_JVSUFFIX=true
-SCREENGEOMETRY_HEIGHT=1600
-JAVA_CONSOLE_SCREEN_Y=475
-JAVA_CONSOLE_SCREEN_X=830
+NOQUESTIONNAIRES=true
+PAD_GAPS=false
PFAM_JVSUFFIX=true
+PILEUP_JVSUFFIX=true
PIR_JVSUFFIX=true
-STARTUP_FILE=http\://www.jalview.org/examples/exampleFile_2_3.jar
-JAVA_CONSOLE_SCREEN_HEIGHT=162
PIR_MODELLER=false
-GAP_SYMBOL=-
-SHOW_QUALITY=true
+RECENT_FILE=examples/uniref50.fa\t/Volumes/Data/Users/jimp/Documents/testing/Jalview/examples/RF00031_folded.stk\t/Volumes/Data/Users/jimp/bs_ig_mult.out
+RECENT_URL=http\://www.jalview.org/examples/exampleFile_2_7.jar
+RIGHT_ALIGN_IDS=false
+RSBS_SERVICES=|Multi-Harmony|Analysis|Sequence Harmony and Multi-Relief (Brandt et al. 2010)|hseparable,gapCharacter\='-',returns\='ANNOTATION'|?tool\=jalview|http\://zeus.few.vu.nl/programs/shmrwww/index.php?tool\=jalview&groups\=$PARTITION\:min\='2',minsize\='2',sep\=' '$&ali_file\=$ALIGNMENT\:format\='FASTA',writeasfile$
+SCREEN_HEIGHT=650
+SCREEN_WIDTH=900
+SCREEN_X=936
+SCREEN_Y=768
+SCREENGEOMETRY_HEIGHT=1600
+SCREENGEOMETRY_WIDTH=2560
+SEQUENCE_LINKS=EMBL-EBI Search|http\://www.ebi.ac.uk/ebisearch/search.ebi?db\=allebi&query\=$SEQUENCE_ID$
+SHOW_ANNOTATIONS=true
+SHOW_CONSENSUS_HISTOGRAM=true
+SHOW_CONSENSUS_LOGO=false
+SHOW_CONSERVATION=true
+SHOW_DBREFS_TOOLTIP=true
+SHOW_ENFIN_SERVICES=true
+SHOW_FULLSCREEN=false
+SHOW_GROUP_CONSENSUS=false
SHOW_GROUP_CONSERVATION=false
+SHOW_IDENTITY=true
+SHOW_JAVA_CONSOLE=false
+SHOW_JVSUFFIX=true
SHOW_JWS2_SERVICES=true
SHOW_NPFEATS_TOOLTIP=true
-FONT_STYLE=plain
-ANTI_ALIAS=false
-SORT_BY_TREE=false
-RSBS_SERVICES=|Multi-Harmony|Analysis|Sequence Harmony and Multi-Relief (Brandt et al. 2010)|hseparable,gapCharacter\='-',returns\='ANNOTATION'|?tool\=jalview|http\://zeus.few.vu.nl/programs/shmrwww/index.php?tool\=jalview&groups\=$PARTITION\:min\='2',minsize\='2',sep\=' '$&ali_file\=$ALIGNMENT\:format\='FASTA',writeasfile$
-AUTHORFNAMES=Jim Procter, Andrew Waterhouse, Jan Engelhardt, Lauren Lui, Michele Clamp, James Cuff, Steve Searle, David Martin & Geoff Barton
-JALVIEW_RSS_WINDOW_SCREEN_HEIGHT=328
-SHOW_GROUP_CONSENSUS=false
-SHOW_CONSENSUS_HISTOGRAM=true
SHOW_OVERVIEW=false
-AUTHORS=J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
-FIGURE_AUTOIDWIDTH=false
-SCREEN_WIDTH=900
-ANNOTATIONCOLOUR_MIN=ffc800
+SHOW_QUALITY=true
SHOW_STARTUP_FILE=false
-RECENT_FILE=examples/uniref50.fa\t/Volumes/Data/Users/jimp/Documents/testing/Jalview/examples/RF00031_folded.stk\t/Volumes/Data/Users/jimp/bs_ig_mult.out
-DEFAULT_FILE_FORMAT=FASTA
-SHOW_JAVA_CONSOLE=false
-VERSION=2.8b1
-FIGURE_USERIDWIDTH=
-WSMENU_BYTYPE=false
-DEFAULT_COLOUR=None
-NOQUESTIONNAIRES=true
-JALVIEW_NEWS_RSS_LASTMODIFIED=Apr 23, 2014 2\:53\:26 PM
-BUILD_DATE=01 November 2013
-PILEUP_JVSUFFIX=true
-SHOW_CONSENSUS_LOGO=false
-SCREENGEOMETRY_WIDTH=2560
-SHOW_ANNOTATIONS=true
-JALVIEW_RSS_WINDOW_SCREEN_Y=0
-USAGESTATS=false
-JALVIEW_RSS_WINDOW_SCREEN_X=0
SHOW_UNCONSERVED=false
-SHOW_JVSUFFIX=true
-DAS_LOCAL_SOURCE=
-SCREEN_HEIGHT=650
-ANNOTATIONCOLOUR_MAX=ff0000
-AUTO_CALC_CONSENSUS=true
-FASTA_JVSUFFIX=true
-DAS_ACTIVE_SOURCE=uniprot\t
-JWS2HOSTURLS=http\://www.compbio.dundee.ac.uk/jabaws
-PAD_GAPS=false
-CLUSTAL_JVSUFFIX=true
-SHOW_ENFIN_SERVICES=true
-FONT_SIZE=10
-RIGHT_ALIGN_IDS=false
+SHOW_WSDISCOVERY_ERRORS=true
+SORT_ALIGNMENT=No sort
+SORT_BY_TREE=false
+STARTUP_FILE=
+USAGESTATS=false
USE_PROXY=false
+VERSION_CHECK=false
+VERSION=2.8b1
WRAP_ALIGNMENT=false
-#DAS_REGISTRY_URL=http\://www.dasregistry.org/das/ # retired 01/05/2015
-DAS_REGISTRY_URL=http\://www.ebi.ac.uk/das-srv/registry/das/
+WSMENU_BYHOST=false
+WSMENU_BYTYPE=false
+YEAR=2011
import jalview.gui.JvOptionPane;
+import javax.swing.JComboBox;
import javax.swing.JInternalFrame;
-import javax.swing.JTextField;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
assertEquals(expectedString, outcome);
}
- @Test(groups = { "External" }, timeOut = 7000)
+ @Test(groups = { "External" }, timeOut = 8000)
public void txt_search_ActionPerformedTest()
{
PDBFTSPanel searchPanel = new PDBFTSPanel(null);
JInternalFrame mainFrame = searchPanel.getMainFrame();
- JTextField txt_search = searchPanel.getTxtSearch();
+ JComboBox<String> txt_search = searchPanel.getTxtSearch();
assertTrue(mainFrame.getTitle().length() == 20);
assertTrue(mainFrame.getTitle()
.equalsIgnoreCase("PDB Sequence Fetcher"));
- txt_search.setText("ABC");
+ txt_search.setSelectedItem("ABC");
try
{
// wait for web-service to handle response
*/
assertFalse(alignFrame.hideFeatureColumns("exon", true));
assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
- assertTrue(alignFrame.getViewport().getColumnSelection().getHiddenColumns()
+ assertTrue(alignFrame.getViewport().getAlignment().getHiddenColumns()
+ .getHiddenRegions()
.isEmpty());
assertFalse(alignFrame.hideFeatureColumns("exon", false));
assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
- assertTrue(alignFrame.getViewport().getColumnSelection().getHiddenColumns()
+ assertTrue(alignFrame.getViewport().getAlignment().getHiddenColumns()
+ .getHiddenRegions()
.isEmpty());
/*
*/
assertFalse(alignFrame.hideFeatureColumns("Metal", true));
assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
- List<int[]> hidden = alignFrame.getViewport().getColumnSelection()
- .getHiddenColumns();
+ List<int[]> hidden = alignFrame.getViewport().getAlignment()
+ .getHiddenColumns()
+ .getHiddenRegions();
assertTrue(hidden.isEmpty());
/*
* [1-3], [6-8] base zero
*/
assertTrue(alignFrame.hideFeatureColumns("Turn", true));
- hidden = alignFrame.getViewport().getColumnSelection().getHiddenColumns();
+ hidden = alignFrame.getViewport().getAlignment().getHiddenColumns()
+ .getHiddenRegions();
assertEquals(hidden.size(), 2);
assertEquals(hidden.get(0)[0], 1);
assertEquals(hidden.get(0)[1], 3);
import java.util.ArrayList;
import java.util.List;
+import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
acf2.addMap(s1, s1, new MapList(new int[] { 1, 4 }, new int[] { 4, 1 },
1, 1));
- List<AlignedCodonFrame> mappings = new ArrayList<AlignedCodonFrame>();
+ List<AlignedCodonFrame> mappings = new ArrayList<>();
mappings.add(acf1);
mappings.add(acf2);
af1.getViewport().getAlignment().setCodonFrames(mappings);
acf3.addMap(cs2, cs2, new MapList(new int[] { 1, 12 }, new int[] { 1,
12 }, 1, 1));
- List<AlignedCodonFrame> mappings1 = new ArrayList<AlignedCodonFrame>();
+ List<AlignedCodonFrame> mappings1 = new ArrayList<>();
mappings1.add(acf1);
af1.getViewport().getAlignment().setCodonFrames(mappings1);
- List<AlignedCodonFrame> mappings2 = new ArrayList<AlignedCodonFrame>();
+ List<AlignedCodonFrame> mappings2 = new ArrayList<>();
mappings2.add(acf2);
mappings2.add(acf3);
af2.getViewport().getAlignment().setCodonFrames(mappings2);
acf3.addMap(cs2, cs2, new MapList(new int[] { 1, 12 }, new int[] { 1,
12 }, 1, 1));
- List<AlignedCodonFrame> mappings1 = new ArrayList<AlignedCodonFrame>();
+ List<AlignedCodonFrame> mappings1 = new ArrayList<>();
mappings1.add(acf1);
mappings1.add(acf2);
af1.getViewport().getAlignment().setCodonFrames(mappings1);
- List<AlignedCodonFrame> mappings2 = new ArrayList<AlignedCodonFrame>();
+ List<AlignedCodonFrame> mappings2 = new ArrayList<>();
mappings2.add(acf2);
mappings2.add(acf3);
af2.getViewport().getAlignment().setCodonFrames(mappings2);
Boolean.TRUE.toString());
Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
Boolean.FALSE.toString());
+ Cache.applicationProperties.setProperty("SHOW_OCCUPANCY",
+ Boolean.FALSE.toString());
Cache.applicationProperties.setProperty("SHOW_IDENTITY",
Boolean.FALSE.toString());
AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
/**
* Verify that setting the selection group has the side-effect of setting the
- * context on the group, unless it already has one
+ * context on the group, unless it already has one, but does not change
+ * whether the group is defined or not.
*/
@Test(groups = { "Functional" })
public void testSetSelectionGroup()
AlignViewport av = af.getViewport();
SequenceGroup sg1 = new SequenceGroup();
SequenceGroup sg2 = new SequenceGroup();
+ SequenceGroup sg3 = new SequenceGroup();
av.setSelectionGroup(sg1);
assertSame(sg1.getContext(), av.getAlignment()); // context set
+ assertFalse(sg1.isDefined()); // group not defined
- sg2.setContext(sg1);
+ sg2.setContext(sg1, false);
av.setSelectionGroup(sg2);
+ assertFalse(sg2.isDefined()); // unchanged
assertSame(sg2.getContext(), sg1); // unchanged
+
+ // create a defined group
+ sg3.setContext(av.getAlignment(), true);
+ av.setSelectionGroup(sg3);
+ assertTrue(sg3.isDefined()); // unchanged
+ }
+ /**
+ * Verify that setting/clearing SHOW_OCCUPANCY preference adds or omits occupancy row from viewport
+ */
+ @Test(groups = { "Functional" })
+ public void testShowOrDontShowOccupancy()
+ {
+ // disable occupancy
+ jalview.bin.Cache.setProperty("SHOW_OCCUPANCY", Boolean.FALSE.toString());
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+ "examples/uniref50.fa", DataSourceType.FILE);
+ AlignViewport av = af.getViewport();
+ Assert.assertNull(av.getAlignmentGapAnnotation(), "Preference did not disable occupancy row.");
+ int c = 0;
+ for (AlignmentAnnotation aa : av.getAlignment().findAnnotations(null,
+ null, "Occupancy"))
+ {
+ c++;
+ }
+ Assert.assertEquals(c, 0, "Expected zero occupancy rows.");
+
+ // enable occupancy
+ jalview.bin.Cache.setProperty("SHOW_OCCUPANCY", Boolean.TRUE.toString());
+ af = new FileLoader().LoadFileWaitTillLoaded(
+ "examples/uniref50.fa", DataSourceType.FILE);
+ av = af.getViewport();
+ Assert.assertNotNull(av.getAlignmentGapAnnotation(), "Preference did not enable occupancy row.");
+ c = 0;
+ for (AlignmentAnnotation aa : av.getAlignment().findAnnotations(null,
+ null, av.getAlignmentGapAnnotation().label))
+ {
+ c++;
+ }
+ ;
+ Assert.assertEquals(c, 1, "Expected to find one occupancy row.");
+
}
}
--- /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.
+ */
+package jalview.gui;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.bin.Cache;
+import jalview.bin.Jalview;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+import jalview.viewmodel.ViewportRanges;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class AlignmentPanelTest
+{
+ SequenceI seq1 = new Sequence(
+ "Seq1",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq2 = new Sequence(
+ "Seq2",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq3 = new Sequence(
+ "Seq3",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq4 = new Sequence(
+ "Seq4",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq5 = new Sequence(
+ "Seq5",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq6 = new Sequence(
+ "Seq6",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq7 = new Sequence(
+ "Seq7",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq8 = new Sequence(
+ "Seq8",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq9 = new Sequence(
+ "Seq9",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq10 = new Sequence(
+ "Seq10",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq11 = new Sequence(
+ "Seq11",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq12 = new Sequence(
+ "Seq12",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq13 = new Sequence(
+ "Seq13",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq14 = new Sequence(
+ "Seq14",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq15 = new Sequence(
+ "Seq15",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq16 = new Sequence(
+ "Seq16",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq17 = new Sequence(
+ "Seq17",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq18 = new Sequence(
+ "Seq18",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq19 = new Sequence(
+ "Seq19",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq20 = new Sequence(
+ "Seq20",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq21 = new Sequence(
+ "Seq21",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq22 = new Sequence(
+ "Seq22",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ SequenceI seq23 = new Sequence(
+ "Seq23",
+ "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ AlignFrame af;
+
+ @BeforeMethod(alwaysRun = true)
+ public void setUp()
+ {
+ Jalview.main(new String[] { "-nonews", "-props",
+ "test/jalview/testProps.jvprops" });
+
+ Cache.applicationProperties.setProperty("SHOW_IDENTITY",
+ Boolean.TRUE.toString());
+ af = new FileLoader().LoadFileWaitTillLoaded("examples/uniref50.fa",
+ DataSourceType.FILE);
+
+ /*
+ * wait for Consensus thread to complete
+ */
+ synchronized (this)
+ {
+ while (af.getViewport().getConsensusSeq() == null)
+ {
+ try
+ {
+ wait(50);
+ } catch (InterruptedException e)
+ {
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Test side effect that end residue is set correctly by setScrollValues, with
+ * or without hidden columns
+ */
+ @Test(groups = "Functional")
+ public void TestSetScrollValues()
+ {
+ ViewportRanges ranges = af.getViewport().getRanges();
+ af.alignPanel.setScrollValues(0, 0);
+
+ int oldres = ranges.getEndRes();
+ af.alignPanel.setScrollValues(-1, 5);
+
+ // setting -ve x value does not change residue
+ assertEquals(ranges.getEndRes(), oldres);
+
+ af.alignPanel.setScrollValues(0, 5);
+
+ // setting 0 as x value does not change residue
+ assertEquals(ranges.getEndRes(), oldres);
+
+ af.alignPanel.setScrollValues(5, 5);
+ // setting x value to 5 extends endRes by 5 residues
+ assertEquals(ranges.getEndRes(), oldres + 5);
+
+ // scroll to position after hidden columns sets endres to oldres (width) +
+ // position
+ int scrollpos = 60;
+ af.getViewport().hideColumns(30, 50);
+ af.alignPanel.setScrollValues(scrollpos, 5);
+ assertEquals(ranges.getEndRes(), oldres + scrollpos);
+
+ // scroll to position within hidden columns, still sets endres to oldres +
+ // position
+ // not sure if this is actually correct behaviour but this is what Jalview
+ // currently does
+ scrollpos = 40;
+ af.getViewport().showAllHiddenColumns();
+ af.getViewport().hideColumns(30, 50);
+ af.alignPanel.setScrollValues(scrollpos, 5);
+ assertEquals(ranges.getEndRes(), oldres + scrollpos);
+
+ // scroll to position within <width> distance of the end of the alignment
+ // endRes should be set to width of alignment - 1
+ scrollpos = 130;
+ af.getViewport().showAllHiddenColumns();
+ af.alignPanel.setScrollValues(scrollpos, 5);
+ assertEquals(ranges.getEndRes(), af.getViewport()
+ .getAlignment().getWidth() - 1);
+
+ // now hide some columns, and scroll to position within <width>
+ // distance of the end of the alignment
+ // endRes should be set to width of alignment - 1 - the number of hidden
+ // columns
+ af.getViewport().hideColumns(30, 50);
+ af.alignPanel.setScrollValues(scrollpos, 5);
+ assertEquals(ranges.getEndRes(), af.getViewport()
+ .getAlignment().getWidth() - 1 - 21); // 21 is the number of hidden
+ // columns
+ }
+}
types = AnnotationChooser.getAnnotationTypes(
parentPanel.getAlignment(), false);
- assertEquals("Not six annotation types", 6, types.size());
+ assertEquals("Not six annotation types", 7, types.size());
assertTrue("IUPRED missing", types.contains("IUPRED"));
assertTrue("JMol missing", types.contains("JMol"));
assertTrue("Beauty missing", types.contains("Beauty"));
assertTrue("Consensus missing", types.contains("Consensus"));
assertTrue("Quality missing", types.contains("Quality"));
assertTrue("Conservation missing", types.contains("Conservation"));
+ assertTrue("Occupancy missing", types.contains("Occupancy"));
}
/**
AlignmentAnnotation[] anns = parentPanel.getAlignment()
.getAlignmentAnnotation();
- assertTrue(anns[5].visible); // JMol for seq3
- assertTrue(anns[7].visible); // JMol for seq1
+ int autocalc = countAutocalc(anns);
+ assertTrue(anns[autocalc + 2].visible); // JMol for seq3
+ assertTrue(anns[autocalc + 4].visible); // JMol for seq1
setSelected(getTypeCheckbox("JMol"), true);
assertTrue(anns[0].visible); // Conservation
assertTrue(anns[1].visible); // Quality
assertTrue(anns[2].visible); // Consensus
- assertTrue(anns[3].visible); // IUPred for seq0
- assertTrue(anns[4].visible); // Beauty
- assertFalse(anns[5].visible); // JMol for seq3 - not selected but hidden
- assertTrue(anns[6].visible); // IUPRED for seq2
- assertFalse(anns[7].visible); // JMol for seq1 - selected and hidden
+ assertTrue(anns[3].visible); // Occupancy
+ assertTrue(anns[4].visible); // IUPred for seq0
+ assertTrue(anns[5].visible); // Beauty
+ assertFalse(anns[6].visible); // JMol for seq3 - not selected but hidden
+ assertTrue(anns[7].visible); // IUPRED for seq2
+ assertFalse(anns[8].visible); // JMol for seq1 - selected and hidden
}
/**
AlignmentAnnotation[] anns = parentPanel.getAlignment()
.getAlignmentAnnotation();
- assertTrue(anns[7].visible); // JMol for seq1
+ int autocalc = countAutocalc(anns);
+ assertTrue(anns[autocalc + 4].visible); // JMol for seq1
setSelected(getTypeCheckbox("JMol"), true);
assertTrue(anns[0].visible); // Conservation
assertTrue(anns[1].visible); // Quality
assertTrue(anns[2].visible); // Consensus
- assertTrue(anns[3].visible); // IUPred for seq0
- assertTrue(anns[4].visible); // Beauty
- assertTrue(anns[5].visible); // JMol for seq3 not in selection group
- assertTrue(anns[6].visible); // IUPRED for seq2
- assertFalse(anns[7].visible); // JMol for seq1 in selection group
+ assertTrue(anns[3].visible); // Occupancy
+ assertTrue(anns[4].visible); // IUPred for seq0
+ assertTrue(anns[5].visible); // Beauty
+ assertTrue(anns[6].visible); // JMol for seq3 not in selection group
+ assertTrue(anns[7].visible); // IUPRED for seq2
+ assertFalse(anns[8].visible); // JMol for seq1 in selection group
}
/**
// select JMol - all hidden
setSelected(typeCheckbox, true);
- assertFalse(anns[5].visible); // JMol for seq3
- assertFalse(anns[7].visible); // JMol for seq1
+ int autocalc = countAutocalc(anns);
+ assertFalse(anns[autocalc + 2].visible); // JMol for seq3
+ assertFalse(anns[autocalc + 4].visible); // JMol for seq1
// deselect JMol - all unhidden
setSelected(typeCheckbox, false);
- assertTrue(anns[0].visible); // Conservation
- assertTrue(anns[1].visible); // Quality
- assertTrue(anns[2].visible); // Consensus
- assertTrue(anns[3].visible); // IUPred for seq0
- assertTrue(anns[4].visible); // Beauty
- assertTrue(anns[5].visible); // JMol for seq3
- assertTrue(anns[6].visible); // IUPRED for seq2
- assertTrue(anns[7].visible); // JMol for seq1
+ for (AlignmentAnnotation ann : anns)
+ {
+ assertTrue(ann.visible);
+ }
+ }
+
+ /**
+ * Returns a count of autocalculated annotations in the set provided
+ *
+ * @param anns
+ * @return
+ */
+ private int countAutocalc(AlignmentAnnotation[] anns)
+ {
+ int count = 0;
+ for (AlignmentAnnotation ann : anns)
+ {
+ if (ann.autoCalculated)
+ {
+ count++;
+ }
+ }
+ return count;
}
/**
setSelected(allSequencesCheckbox, true);
setSelected(hideCheckbox, true);
setSelected(getTypeCheckbox("JMol"), true);
- assertFalse(anns[5].visible); // JMol for seq3
- assertFalse(anns[7].visible); // JMol for seq1
+ int autocalc = countAutocalc(anns);
+ assertFalse(anns[autocalc + 2].visible); // JMol for seq3
+ assertFalse(anns[autocalc + 4].visible); // JMol for seq1
// ...now show them...
setSelected(showCheckbox, true);
- assertTrue(anns[0].visible); // Conservation
- assertTrue(anns[1].visible); // Quality
- assertTrue(anns[2].visible); // Consensus
- assertTrue(anns[3].visible); // IUPred for seq0
- assertTrue(anns[4].visible); // Beauty
- assertTrue(anns[5].visible); // JMol for seq3
- assertTrue(anns[6].visible); // IUPRED for seq2
- assertTrue(anns[7].visible); // JMol for seq1
+ for (AlignmentAnnotation ann : anns)
+ {
+ assertTrue(ann.visible);
+ }
}
/**
setSelected(hideCheckbox, true);
setSelected(getTypeCheckbox("JMol"), true);
- assertTrue(anns[5].visible); // JMol for seq3
- assertFalse(anns[7].visible); // JMol for seq1
+ int autocalc = countAutocalc(anns);
+ assertTrue(anns[autocalc + 2].visible); // JMol for seq3
+ assertFalse(anns[autocalc + 4].visible); // JMol for seq1
// ...now show them...
setSelected(showCheckbox, true);
- assertTrue(anns[0].visible); // Conservation
- assertTrue(anns[1].visible); // Quality
- assertTrue(anns[2].visible); // Consensus
- assertTrue(anns[3].visible); // IUPred for seq0
- assertTrue(anns[4].visible); // Beauty
- assertTrue(anns[5].visible); // JMol for seq3
- assertTrue(anns[6].visible); // IUPRED for seq2
- assertTrue(anns[7].visible); // JMol for seq1
+ for (AlignmentAnnotation ann : anns)
+ {
+ assertTrue(ann.visible);
+ }
}
/**
final Checkbox typeCheckbox = getTypeCheckbox("JMol");
// select JMol - all shown
setSelected(typeCheckbox, true);
- assertTrue(anns[5].visible); // JMol for seq3
- assertTrue(anns[7].visible); // JMol for seq1
+ int autocalc = countAutocalc(anns);
+ assertTrue(anns[autocalc + 2].visible); // JMol for seq3
+ assertTrue(anns[autocalc + 4].visible); // JMol for seq1
// deselect JMol - all hidden
setSelected(typeCheckbox, false);
assertTrue(anns[0].visible); // Conservation
assertTrue(anns[1].visible); // Quality
assertTrue(anns[2].visible); // Consensus
- assertTrue(anns[3].visible); // IUPred for seq0
- assertTrue(anns[4].visible); // Beauty
- assertFalse(anns[5].visible); // JMol for seq3
- assertTrue(anns[6].visible); // IUPRED for seq2
- assertFalse(anns[7].visible); // JMol for seq1
+ assertTrue(anns[3].visible); // Occupancy
+ assertTrue(anns[4].visible); // IUPred for seq0
+ assertTrue(anns[5].visible); // Beauty
+ assertFalse(anns[6].visible); // JMol for seq3
+ assertTrue(anns[7].visible); // IUPRED for seq2
+ assertFalse(anns[8].visible); // JMol for seq1
}
/**
// select JMol - should remain visible
setSelected(getTypeCheckbox("JMol"), true);
- assertTrue(anns[5].visible); // JMol for seq3
- assertTrue(anns[7].visible); // JMol for seq1
+ int autocalc = countAutocalc(anns);
+ assertTrue(anns[autocalc + 2].visible); // JMol for seq3
+ assertTrue(anns[autocalc + 4].visible); // JMol for seq1
// deselect JMol - should be hidden for selected sequences only
setSelected(getTypeCheckbox("JMol"), false);
assertTrue(anns[0].visible); // Conservation
assertTrue(anns[1].visible); // Quality
assertTrue(anns[2].visible); // Consensus
- assertTrue(anns[3].visible); // IUPred for seq0
- assertTrue(anns[4].visible); // Beauty
- assertTrue(anns[5].visible); // JMol for seq3 not in selection group
- assertTrue(anns[6].visible); // IUPRED for seq2
- assertFalse(anns[7].visible); // JMol for seq1 in selection group
+ assertTrue(anns[3].visible); // Occupancy
+ assertTrue(anns[4].visible); // IUPred for seq0
+ assertTrue(anns[5].visible); // Beauty
+ assertTrue(anns[6].visible); // JMol for seq3 not in selection group
+ assertTrue(anns[7].visible); // IUPRED for seq2
+ assertFalse(anns[8].visible); // JMol for seq1 in selection group
}
/**
AlignmentAnnotation[] anns = parentPanel.getAlignment()
.getAlignmentAnnotation();
- // remember 3 annotations to skip (Conservation/Quality/Consensus)
- assertFalse(testee.isInActionScope(anns[3]));
- assertFalse(testee.isInActionScope(anns[4]));
- assertFalse(testee.isInActionScope(anns[5]));
- assertTrue(testee.isInActionScope(anns[6]));
- assertTrue(testee.isInActionScope(anns[7]));
+ int autocalc = countAutocalc(anns);
+ assertFalse(testee.isInActionScope(anns[autocalc]));
+ assertFalse(testee.isInActionScope(anns[autocalc + 1]));
+ assertFalse(testee.isInActionScope(anns[autocalc + 2]));
+ assertTrue(testee.isInActionScope(anns[autocalc + 3]));
+ assertTrue(testee.isInActionScope(anns[autocalc + 4]));
}
/**
AlignmentAnnotation[] anns = parentPanel.getAlignment()
.getAlignmentAnnotation();
- // remember 3 annotations to skip (Conservation/Quality/Consensus)
- assertTrue(testee.isInActionScope(anns[3]));
- assertTrue(testee.isInActionScope(anns[4]));
- assertTrue(testee.isInActionScope(anns[5]));
- assertFalse(testee.isInActionScope(anns[6]));
- assertFalse(testee.isInActionScope(anns[7]));
+ int autocalc = countAutocalc(anns);
+ assertTrue(testee.isInActionScope(anns[autocalc]));
+ assertTrue(testee.isInActionScope(anns[autocalc + 1]));
+ assertTrue(testee.isInActionScope(anns[autocalc + 2]));
+ assertFalse(testee.isInActionScope(anns[autocalc + 3]));
+ assertFalse(testee.isInActionScope(anns[autocalc + 4]));
}
/**
assertTrue(anns[0].visible); // Conservation
assertTrue(anns[1].visible); // Quality
assertTrue(anns[2].visible); // Consensus
- assertFalse(anns[3].visible); // IUPRED
- assertTrue(anns[4].visible); // Beauty (not seq-related)
- assertFalse(anns[5].visible); // JMol
- assertFalse(anns[6].visible); // IUPRED
- assertFalse(anns[7].visible); // JMol
+ assertTrue(anns[3].visible); // Occupancy
+ assertFalse(anns[4].visible); // IUPRED
+ assertTrue(anns[5].visible); // Beauty (not seq-related)
+ assertFalse(anns[6].visible); // JMol
+ assertFalse(anns[7].visible); // IUPRED
+ assertFalse(anns[8].visible); // JMol
// reset - should all be visible
testee.resetOriginalState();
--- /dev/null
+package jalview.gui;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.bin.Cache;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+
+import java.util.Vector;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Tests for methods of base class of annotation column or colour chooser
+ */
+public class AnnotationRowFilterTest
+{
+ AlignFrame af;
+
+ private AnnotationRowFilter testee;
+
+ @BeforeClass(alwaysRun = true)
+ public void setUp()
+ {
+ Cache.loadProperties("test/jalview/io/testProps.jvprops");
+ Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS",
+ Boolean.TRUE.toString());
+ Cache.applicationProperties.setProperty(
+ Preferences.SHOW_AUTOCALC_ABOVE, Boolean.TRUE.toString());
+ af = new FileLoader().LoadFileWaitTillLoaded("examples/uniref50.fa",
+ DataSourceType.FILE);
+ testee = new AnnotationRowFilter(af.viewport, af.alignPanel)
+ {
+ @Override
+ public void valueChanged(boolean updateAllAnnotation)
+ {
+ }
+
+ @Override
+ public void updateView()
+ {
+ }
+
+ @Override
+ public void reset()
+ {
+ }
+ };
+ }
+
+ /**
+ * Test the method that builds the drop-down list of annotations to choose
+ * from for colour by annotation or select columns by annotation
+ */
+ @Test(groups = "Functional")
+ public void testGetAnnotationItems()
+ {
+ AlignmentI al = af.getViewport().getAlignment();
+ SequenceI seq1 = al.findSequenceMatch("FER_CAPAA")[0];
+ SequenceI seq2 = al.findSequenceMatch("FER_BRANA")[0];
+
+ AlignmentAnnotation ann1 = new AlignmentAnnotation("ann1Label", "ann1",
+ null);
+ al.addAnnotation(ann1);
+ AlignmentAnnotation ann2 = new AlignmentAnnotation("Significance",
+ "ann2", null);
+ al.addAnnotation(ann2);
+ /*
+ * a second Significance alignment annotation
+ */
+ AlignmentAnnotation ann2a = new AlignmentAnnotation("Significance",
+ "ann2", null);
+ al.addAnnotation(ann2a);
+
+ AlignmentAnnotation ann3 = new AlignmentAnnotation("Jronn", "Jronn",
+ null);
+ ann3.setSequenceRef(seq1);
+ al.addAnnotation(ann3);
+ AlignmentAnnotation ann4 = new AlignmentAnnotation("Jronn", "Jronn",
+ null);
+ ann4.setSequenceRef(seq2);
+ al.addAnnotation(ann4);
+ AlignmentAnnotation ann5 = new AlignmentAnnotation("Jnet", "Jnet", null);
+ ann5.setSequenceRef(seq2);
+ al.addAnnotation(ann5);
+ /*
+ * a second Jnet annotation for FER_BRANA
+ */
+ AlignmentAnnotation ann6 = new AlignmentAnnotation("Jnet", "Jnet", null);
+ ann6.setSequenceRef(seq2);
+ al.addAnnotation(ann6);
+
+ /*
+ * drop-down items with 'Per-sequence only' not checked
+ */
+ Vector<String> items = testee.getAnnotationItems(false);
+ assertEquals(
+ items.toString(),
+ "[Conservation, Quality, Consensus, Occupancy, ann1Label, Significance, Significance_1, Jronn_FER_CAPAA, Jronn_FER_BRANA, Jnet_FER_BRANA, Jnet_FER_BRANA_2]");
+ assertEquals(testee.getAnnotationMenuLabel(ann1), "ann1Label");
+ assertEquals(testee.getAnnotationMenuLabel(ann2), "Significance");
+ assertEquals(testee.getAnnotationMenuLabel(ann2a), "Significance_1");
+ assertEquals(testee.getAnnotationMenuLabel(ann3), "Jronn_FER_CAPAA");
+ assertEquals(testee.getAnnotationMenuLabel(ann4), "Jronn_FER_BRANA");
+ assertEquals(testee.getAnnotationMenuLabel(ann5), "Jnet_FER_BRANA");
+ assertEquals(testee.getAnnotationMenuLabel(ann6), "Jnet_FER_BRANA_2");
+
+ /*
+ * drop-down items with 'Per-sequence only' checked
+ */
+ items = testee.getAnnotationItems(true);
+ assertEquals(items.toString(), "[Jronn, Jnet]");
+ // the first annotation of the type is associated with the menu item
+ assertEquals(testee.getAnnotationMenuLabel(ann3), "Jronn");
+ assertEquals(testee.getAnnotationMenuLabel(ann5), "Jnet");
+ }
+}
--- /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.
+ */
+package jalview.gui;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class SeqPanelTest
+{
+ AlignFrame af;
+
+ @BeforeClass(alwaysRun = true)
+ public void setUpJvOptionPane()
+ {
+ JvOptionPane.setInteractiveMode(false);
+ JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+ }
+ @Test(groups = "Functional")
+ public void testSetStatusReturnsPosOrMinusOne()
+ {
+ SequenceI seq1 = new Sequence("Seq1", "AACDE");
+ SequenceI seq2 = new Sequence("Seq2", "AA--E");
+ AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
+ AlignFrame alignFrame = new AlignFrame(al, al.getWidth(),
+ al.getHeight());
+ AlignmentI visAl = alignFrame.getViewport().getAlignment();
+ // Test either side of gap
+ // This first assert fails due to JAL-2563
+ assertEquals(
+ alignFrame.alignPanel.getSeqPanel().setStatusMessage(
+ visAl.getSequenceAt(1), 1, 1), 2);
+ assertEquals(
+ alignFrame.alignPanel.getSeqPanel().setStatusMessage(
+ visAl.getSequenceAt(1), 4, 1), 3);
+ // Test gaps are -1
+ assertEquals(
+ alignFrame.alignPanel.getSeqPanel().setStatusMessage(
+ visAl.getSequenceAt(1), 2, 1), -1);
+ assertEquals(
+ alignFrame.alignPanel.getSeqPanel().setStatusMessage(
+ visAl.getSequenceAt(1), 3, 1), -1);
+ }
+
+ @Test(groups = "Functional")
+ public void testAmbiguousAminoAcidGetsStatusMessage()
+ {
+ SequenceI seq1 = new Sequence("Seq1", "ABCDE");
+ SequenceI seq2 = new Sequence("Seq2", "AB--E");
+ AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
+ AlignFrame alignFrame = new AlignFrame(al, al.getWidth(),
+ al.getHeight());
+ AlignmentI visAl = alignFrame.getViewport().getAlignment();
+ // Test either side of gap
+ // This first assert fails due to JAL-2563
+ assertEquals(
+ alignFrame.alignPanel.getSeqPanel().setStatusMessage(
+ visAl.getSequenceAt(1), 1, 1), 2);
+ assertTrue(alignFrame.statusBar.getText().contains("(2)"));
+ }
+}
av.setGlobalColourScheme(new ZappoColourScheme());
// @see ResidueProperties.zappo
- assertEquals(Color.pink, sr.getResidueColour(seq, 0, null)); // M
- assertEquals(Color.green, sr.getResidueColour(seq, 2, null)); // T
- assertEquals(Color.magenta, sr.getResidueColour(seq, 5, null)); // G
- assertEquals(Color.orange, sr.getResidueColour(seq, 12, null)); // F
+ assertEquals(Color.pink, sr.getResidueBoxColour(seq, 0)); // M
+ assertEquals(Color.green, sr.getResidueBoxColour(seq, 2)); // T
+ 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...
StructureChooser sc = new StructureChooser(selectedSeqs, seq, null);
sc.populateFilterComboBox(false, false);
int optionsSize = sc.getCmbFilterOption().getItemCount();
- assertEquals(3, optionsSize); // if structures are not discovered then don't
+ assertEquals(2, optionsSize); // if structures are not discovered then don't
// populate filter options
sc.populateFilterComboBox(true, false);
assertEquals("Cached PDB Entries", filterOpt.getName());
}
- @Test(groups = { "Functional" })
+ @Test(groups = { "Network" })
public void fetchStructuresInfoTest()
{
SequenceI[] selectedSeqs = new SequenceI[] { seq };
import static org.testng.AssertJUnit.assertTrue;
import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.gui.JvOptionPane;
import jalview.io.AnnotationFile.ViewDef;
try
{
AlignmentI al = readAlignmentFile(f);
- ColumnSelection cs = new ColumnSelection();
+ HiddenColumns cs = new HiddenColumns();
assertTrue(
"Test "
+ testname
DataSourceType.FILE));
AnnotationFile aff = new AnnotationFile();
+ // ViewDef is not used by Jalview
ViewDef v = aff.new ViewDef(null, al.getHiddenSequences(), cs,
new Hashtable());
String anfileout = new AnnotationFile().printAnnotations(
DataSourceType.PASTE));
// test for consistency in io
- StockholmFileTest.testAlignmentEquivalence(al, al_new, false);
+ StockholmFileTest.testAlignmentEquivalence(al, al_new, false, false,
+ false);
return;
} catch (Exception e)
{
--- /dev/null
+package jalview.io;
+
+import org.junit.Assert;
+import org.testng.annotations.Test;
+
+public class FileLoaderTest
+{
+
+ @Test(groups = { "Network" })
+ public void testDownloadStructuresIfInputFromURL()
+ {
+ String urlFile = "http://www.jalview.org/builds/develop/examples/3W5V.pdb";
+ FileLoader fileLoader = new FileLoader();
+ fileLoader.LoadFileWaitTillLoaded(urlFile, DataSourceType.URL,
+ FileFormat.PDB);
+ Assert.assertNotNull(fileLoader.file);
+ // The FileLoader's file is expected to be same as the original URL.
+ Assert.assertEquals(urlFile, fileLoader.file);
+ // Data source type expected to be DataSourceType.URL
+ Assert.assertEquals(DataSourceType.URL, fileLoader.protocol);
+ }
+}
{
"examples/testdata/cullpdb_pc25_res3.0_R0.3_d150729_chains9361.fasta.15316",
FileFormat.Fasta },
-
+ { "resources/scoreModel/pam250.scm", FileFormat.ScoreMatrix },
+ { "resources/scoreModel/blosum80.scm", FileFormat.ScoreMatrix }
// { "examples/testdata/test.amsa", "AMSA" },
// { "examples/test.jnet", "JnetFile" },
};
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.Annotation;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceGroup;
import jalview.gui.JvOptionPane;
import jalview.json.binding.biojson.v1.ColourSchemeMapper;
import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ResidueColourScheme;
import java.io.IOException;
import java.util.ArrayList;
private HashMap<String, SequenceGroup> expectedGrps = new HashMap<String, SequenceGroup>();
- private ColumnSelection expectedColSel = new ColumnSelection();
+ private HiddenColumns expectedColSel = new HiddenColumns();
private SequenceI[] expectedHiddenSeqs = new SequenceI[1];
private JSONFile jf;
+ private AlignExportSettingI exportSettings;
+
@BeforeTest(alwaysRun = true)
public void setup() throws Exception
{
expectedSeqs.put(seq.getName(), seq);
}
- // create and add sequence groups
- ArrayList<SequenceI> grpSeqs = new ArrayList<SequenceI>();
+ // create and add a sequence group
+ List<SequenceI> grpSeqs = new ArrayList<SequenceI>();
grpSeqs.add(seqs[1]);
grpSeqs.add(seqs[2]);
grpSeqs.add(seqs[3]);
grpSeqs.add(seqs[4]);
- SequenceGroup seqGrp = new SequenceGroup(grpSeqs, "JGroup:1883305585",
+ SequenceGroup seqGrp = new SequenceGroup(grpSeqs,
+ "JGroup:1883305585",
null, true, true, false, 21, 29);
ColourSchemeI scheme = ColourSchemeMapper.getJalviewColourScheme(
"zappo", seqGrp);
TEST_SEQ_HEIGHT = expectedSeqs.size();
TEST_GRP_HEIGHT = expectedGrps.size();
TEST_ANOT_HEIGHT = expectedAnnots.size();
- TEST_CS_HEIGHT = expectedColSel.getHiddenColumns().size();
+ TEST_CS_HEIGHT = expectedColSel.getHiddenRegions().size();
- AlignExportSettingI exportSettings = new AlignExportSettingI()
+ exportSettings = new AlignExportSettingI()
{
@Override
public boolean isExportHiddenSequences()
jf = (JSONFile) formatAdapter.getAlignFile();
AlignFrame af = new AlignFrame(alignment, jf.getHiddenSequences(),
- jf.getColumnSelection(), AlignFrame.DEFAULT_WIDTH,
+ jf.getHiddenColumns(), AlignFrame.DEFAULT_WIDTH,
AlignFrame.DEFAULT_HEIGHT);
af.getViewport().setShowSequenceFeatures(jf.isShowSeqFeatures());
String colourSchemeName = jf.getGlobalColourScheme();
@Test(groups = { "Functional" })
public void hiddenColsTest()
{
- ColumnSelection cs = testJsonFile.getColumnSelection();
+ HiddenColumns cs = testJsonFile.getHiddenColumns();
Assert.assertNotNull(cs);
- Assert.assertNotNull(cs.getHiddenColumns());
- List<int[]> hiddenCols = cs.getHiddenColumns();
+ Assert.assertNotNull(cs.getHiddenRegions());
+ List<int[]> hiddenCols = cs.getHiddenRegions();
Assert.assertEquals(hiddenCols.size(), TEST_CS_HEIGHT);
Assert.assertEquals(hiddenCols.get(0), expectedColSel
- .getHiddenColumns().get(0),
+ .getHiddenRegions().get(0),
"Mismatched hidden columns!");
}
"Zappo colour scheme expected!");
}
+ /**
+ * Test for bug JAL-2489, NPE when exporting BioJSON with global colour
+ * scheme, and a group colour scheme, set as 'None'
+ */
+ @Test(groups = { "Functional" })
+ public void testBioJSONRoundTripWithColourSchemeNone()
+ {
+ AppletFormatAdapter formatAdapter = new AppletFormatAdapter();
+
+ Alignment _alignment;
+ try
+ {
+ // load example BioJSON file
+ _alignment = (Alignment) formatAdapter.readFile(TEST_JSON_FILE,
+ DataSourceType.FILE, FileFormat.Json);
+ JSONFile bioJsonFile = (JSONFile) formatAdapter.getAlignFile();
+ AlignFrame alignFrame = new AlignFrame(_alignment,
+ bioJsonFile.getHiddenSequences(),
+ bioJsonFile.getHiddenColumns(), AlignFrame.DEFAULT_WIDTH,
+ AlignFrame.DEFAULT_HEIGHT);
+
+ /*
+ * Create a group on the alignment;
+ * Change global and group colour scheme to 'None' and perform round trip
+ */
+ SequenceGroup sg = new SequenceGroup();
+ sg.addSequence(_alignment.getSequenceAt(0), false);
+ sg.setColourScheme(null);
+ ColourSchemeI cs = ColourSchemeMapper.getJalviewColourScheme(
+ ResidueColourScheme.NONE, _alignment);
+ alignFrame.changeColour(cs);
+ alignFrame.getViewport().setFeaturesDisplayed(
+ bioJsonFile.getDisplayedFeatures());
+ formatAdapter = new AppletFormatAdapter(alignFrame.alignPanel,
+ exportSettings);
+ // export BioJSON string
+ String jsonOutput = formatAdapter.formatSequences(FileFormat.Json,
+ alignFrame.alignPanel.getAlignment(), false);
+ // read back Alignment from BioJSON string
+ formatAdapter = new AppletFormatAdapter();
+ formatAdapter.readFile(jsonOutput, DataSourceType.PASTE,
+ FileFormat.Json);
+ // assert 'None' colour scheme is retained after round trip
+ JSONFile _bioJsonFile = (JSONFile) formatAdapter.getAlignFile();
+ Assert.assertEquals(_bioJsonFile.getGlobalColourScheme(),
+ ResidueColourScheme.NONE);
+ } catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
@Test(groups = { "Functional" })
public void isShowSeqFeaturesSet()
{
// System.out.println(">>>>>>>>>>>>>> features matched : " + matched);
return matched;
}
+
+ /**
+ * Test group roundtrip with null (None) group colour scheme
+ *
+ * @throws IOException
+ */
+ @Test(groups = { "Functional" })
+ public void testGrpParsed_colourNone() throws IOException
+ {
+ AlignmentI copy = new Alignment(testAlignment);
+ SequenceGroup sg = testAlignment.getGroups().get(0);
+ SequenceGroup copySg = new SequenceGroup(new ArrayList<SequenceI>(),
+ sg.getName(),
+ null, sg.getDisplayBoxes(), sg.getDisplayText(),
+ sg.getColourText(), sg.getStartRes(), sg.getEndRes());
+ for (SequenceI seq : sg.getSequences())
+ {
+ int seqIndex = testAlignment.findIndex(seq);
+ copySg.addSequence(copy.getSequenceAt(seqIndex), false);
+ }
+ copy.addGroup(copySg);
+
+ AlignFrame af = new AlignFrame(copy, copy.getWidth(), copy.getHeight());
+ AppletFormatAdapter formatAdapter = new AppletFormatAdapter(
+ af.alignPanel);
+ String jsonOutput = formatAdapter.formatSequences(FileFormat.Json,
+ copy, false);
+ formatAdapter = new AppletFormatAdapter();
+ AlignmentI newAlignment = formatAdapter.readFile(jsonOutput,
+ DataSourceType.PASTE, FileFormat.Json);
+
+ Assert.assertNotNull(newAlignment.getGroups());
+ for (SequenceGroup seqGrp : newAlignment.getGroups())
+ {
+ SequenceGroup expectedGrp = expectedGrps.get(seqGrp.getName());
+ AssertJUnit.assertTrue(
+ "Failed SequenceGroup Test for >>> " + seqGrp.getName(),
+ isGroupMatched(expectedGrp, seqGrp));
+ passedCount++;
+ }
+ AssertJUnit.assertEquals("Some SequenceGroups did not pass the test",
+ TEST_GRP_HEIGHT, passedCount);
+ }
}
import static org.testng.ConversionUtils.wrapDataProvider;
-import jalview.analysis.NJTree;
import jalview.analysis.SequenceIdMatcher;
+import jalview.analysis.TreeModel;
import jalview.datamodel.SequenceI;
import jalview.datamodel.SequenceNode;
import jalview.gui.JvOptionPane;
stage = "Compare original and generated tree" + treename;
Vector<SequenceNode> oseqs, nseqs;
- oseqs = new NJTree(new SequenceI[0], nf).findLeaves(nf.getTree());
+ oseqs = new TreeModel(new SequenceI[0], null, nf).findLeaves(nf
+ .getTree());
AssertJUnit.assertTrue(stage + "No nodes in original tree.",
oseqs.size() > 0);
SequenceI[] olsqs = new SequenceI[oseqs.size()];
{
olsqs[i] = (SequenceI) oseqs.get(i).element();
}
- nseqs = new NJTree(new SequenceI[0], nf_regen).findLeaves(nf_regen
+ nseqs = new TreeModel(new SequenceI[0], null, nf_regen)
+ .findLeaves(nf_regen
.getTree());
AssertJUnit.assertTrue(stage + "No nodes in regerated tree.",
nseqs.size() > 0);
DataSourceType.PASTE, FileFormat.Phylip);
assertNotNull("Couldn't parse reimported alignment data.", al_input);
- StockholmFileTest.testAlignmentEquivalence(al, al_input, false);
+ StockholmFileTest.testAlignmentEquivalence(al, al_input, false, false,
+ false);
}
}
{
StockholmFileTest.testFileIOwithFormat(new File(
"examples/testdata/rna-alignment.xml"), FileFormat.Stockholm,
- -1, -1);
+ -1, -1, true, true, true);
}
--- /dev/null
+package jalview.io;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import jalview.analysis.scoremodels.ScoreMatrix;
+import jalview.analysis.scoremodels.ScoreModels;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import org.testng.annotations.Test;
+
+public class ScoreMatrixFileTest
+{
+
+ /**
+ * Test a successful parse of a (small) score matrix file
+ *
+ * @throws IOException
+ * @throws MalformedURLException
+ */
+ @Test(groups = "Functional")
+ public void testParseMatrix_ncbiMixedDelimiters()
+ throws MalformedURLException,
+ IOException
+ {
+ /*
+ * some messy but valid input data, with comma, space
+ * or tab (or combinations) as score value delimiters
+ * this example includes 'guide' symbols on score rows
+ */
+ String data = "ScoreMatrix MyTest (example)\n" + "A\tT\tU\tt\tx\t-\n"
+ + "A,1.1,1.2,1.3,1.4, 1.5, 1.6\n"
+ + "T,2.1 2.2 2.3 2.4 2.5 2.6\n"
+ + "U\t3.1\t3.2\t3.3\t3.4\t3.5\t3.6\t\n"
+ + "t, 5.1,5.3,5.3,5.4,5.5, 5.6\n"
+ + "x\t6.1, 6.2 6.3 6.4 6.5 6.6\n"
+ + "-, \t7.1\t7.2 7.3, 7.4, 7.5\t,7.6\n";
+ FileParse fp = new FileParse(data, DataSourceType.PASTE);
+ ScoreMatrixFile parser = new ScoreMatrixFile(fp);
+ ScoreMatrix sm = parser.parseMatrix();
+
+ assertNotNull(sm);
+ assertEquals(sm.getName(), "MyTest (example)");
+ assertEquals(sm.getSize(), 6);
+ assertNull(sm.getDescription());
+ assertTrue(sm.isDNA());
+ assertFalse(sm.isProtein());
+ assertEquals(sm.getMinimumScore(), 1.1f);
+ assertEquals(sm.getPairwiseScore('A', 'A'), 1.1f);
+ assertEquals(sm.getPairwiseScore('A', 'T'), 1.2f);
+ assertEquals(sm.getPairwiseScore('a', 'T'), 1.2f); // A/a equivalent
+ assertEquals(sm.getPairwiseScore('A', 't'), 1.4f); // T/t not equivalent
+ assertEquals(sm.getPairwiseScore('a', 't'), 1.4f);
+ assertEquals(sm.getPairwiseScore('U', 'x'), 3.5f);
+ assertEquals(sm.getPairwiseScore('u', 'x'), 3.5f);
+ // X (upper) and '.' unmapped - get minimum score
+ assertEquals(sm.getPairwiseScore('U', 'X'), 1.1f);
+ assertEquals(sm.getPairwiseScore('A', '.'), 1.1f);
+ assertEquals(sm.getPairwiseScore('-', '-'), 7.6f);
+ assertEquals(sm.getPairwiseScore('A', (char) 128), 0f); // out of range
+ }
+
+ @Test(groups = "Functional")
+ public void testParseMatrix_headerMissing()
+ {
+ String data;
+
+ data = "X Y\n1 2\n3 4\n";
+ try
+ {
+ new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
+ .parseMatrix();
+ fail("expected exception");
+ } catch (IOException e)
+ {
+ assertEquals(e.getMessage(),
+ "Format error: 'ScoreMatrix <name>' should be the first non-comment line");
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testParseMatrix_ncbiNotEnoughRows()
+ {
+ String data = "ScoreMatrix MyTest\nX Y Z\n1 2 3\n4 5 6\n";
+ try
+ {
+ new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
+ .parseMatrix();
+ fail("expected exception");
+ } catch (IOException e)
+ {
+ assertEquals(e.getMessage(),
+ "Expected 3 rows of score data in score matrix but only found 2");
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testParseMatrix_ncbiNotEnoughColumns()
+ {
+ String data = "ScoreMatrix MyTest\nX Y Z\n1 2 3\n4 5\n7 8 9\n";
+ try
+ {
+ new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
+ .parseMatrix();
+ fail("expected exception");
+ } catch (IOException e)
+ {
+ assertEquals(e.getMessage(),
+ "Expected 3 scores at line 4: '4 5' but found 2");
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testParseMatrix_ncbiTooManyColumns()
+ {
+ /*
+ * with two too many columns:
+ */
+ String data = "ScoreMatrix MyTest\nX\tY\tZ\n1 2 3\n4 5 6 7\n8 9 10\n";
+ try
+ {
+ new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
+ .parseMatrix();
+ fail("expected exception");
+ } catch (IOException e)
+ {
+ assertEquals(e.getMessage(),
+ "Expected 3 scores at line 4: '4 5 6 7' but found 4");
+ }
+
+ /*
+ * with guide character and one too many columns:
+ */
+ data = "ScoreMatrix MyTest\nX Y\nX 1 2\nY 3 4 5\n";
+ try
+ {
+ new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
+ .parseMatrix();
+ fail("expected exception");
+ } catch (IOException e)
+ {
+ assertEquals(e.getMessage(),
+ "Expected 2 scores at line 4: 'Y 3 4 5' but found 3");
+ }
+
+ /*
+ * with no guide character and one too many columns
+ */
+ data = "ScoreMatrix MyTest\nX Y\n1 2\n3 4 5\n";
+ try
+ {
+ new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
+ .parseMatrix();
+ fail("expected exception");
+ } catch (IOException e)
+ {
+ assertEquals(e.getMessage(),
+ "Expected 2 scores at line 4: '3 4 5' but found 3");
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testParseMatrix_ncbiTooManyRows()
+ {
+ String data = "ScoreMatrix MyTest\n\tX\tY\tZ\n1 2 3\n4 5 6\n7 8 9\n10 11 12\n";
+ try
+ {
+ new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
+ .parseMatrix();
+ fail("expected exception");
+ } catch (IOException e)
+ {
+ assertEquals(e.getMessage(),
+ "Unexpected extra input line in score model file: '10 11 12'");
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testParseMatrix_ncbiBadDelimiter()
+ {
+ String data = "ScoreMatrix MyTest\n X Y Z\n1|2|3\n4|5|6\n";
+ try
+ {
+ new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
+ .parseMatrix();
+ fail("expected exception");
+ } catch (IOException e)
+ {
+ assertEquals(e.getMessage(),
+ "Invalid score value '1|2|3' at line 3 column 0");
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testParseMatrix_ncbiBadFloat()
+ {
+ String data = "ScoreMatrix MyTest\n\tX\tY\tZ\n1 2 3\n4 five 6\n7 8 9\n";
+ try
+ {
+ new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
+ .parseMatrix();
+ fail("expected exception");
+ } catch (IOException e)
+ {
+ assertEquals(e.getMessage(),
+ "Invalid score value 'five' at line 4 column 1");
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testParseMatrix_ncbiBadGuideCharacter()
+ {
+ String data = "ScoreMatrix MyTest\n\tX Y\nX 1 2\ny 3 4\n";
+ try
+ {
+ new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
+ .parseMatrix();
+ fail("expected exception");
+ } catch (IOException e)
+ {
+ assertEquals(e.getMessage(),
+ "Error parsing score matrix at line 4, expected 'Y' but found 'y'");
+ }
+
+ data = "ScoreMatrix MyTest\n\tX Y\nXX 1 2\nY 3 4\n";
+ try
+ {
+ new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
+ .parseMatrix();
+ fail("expected exception");
+ } catch (IOException e)
+ {
+ assertEquals(e.getMessage(),
+ "Error parsing score matrix at line 3, expected 'X' but found 'XX'");
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testParseMatrix_ncbiNameMissing()
+ {
+ /*
+ * Name missing on ScoreMatrix header line
+ */
+ String data = "ScoreMatrix\nX Y\n1 2\n3 4\n";
+ try
+ {
+ new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
+ .parseMatrix();
+ fail("expected exception");
+ } catch (IOException e)
+ {
+ assertEquals(
+ e.getMessage(),
+ "Format error: expected 'ScoreMatrix <name>', found 'ScoreMatrix' at line 1");
+ }
+ }
+
+ /**
+ * Test a successful parse of a (small) score matrix file
+ *
+ * @throws IOException
+ * @throws MalformedURLException
+ */
+ @Test(groups = "Functional")
+ public void testParseMatrix_ncbiFormat() throws MalformedURLException,
+ IOException
+ {
+ // input including comment and blank lines
+ String data = "ScoreMatrix MyTest\n#comment\n\n" + "\tA\tB\tC\n"
+ + "A\t1.0\t2.0\t3.0\n" + "B\t4.0\t5.0\t6.0\n"
+ + "C\t7.0\t8.0\t9.0\n";
+ FileParse fp = new FileParse(data, DataSourceType.PASTE);
+ ScoreMatrixFile parser = new ScoreMatrixFile(fp);
+ ScoreMatrix sm = parser.parseMatrix();
+
+ assertNotNull(sm);
+ assertEquals(sm.getName(), "MyTest");
+ assertEquals(parser.getMatrixName(), "MyTest");
+ assertEquals(sm.getPairwiseScore('A', 'A'), 1.0f);
+ assertEquals(sm.getPairwiseScore('B', 'c'), 6.0f);
+ assertEquals(sm.getSize(), 3);
+ }
+
+ /**
+ * Test a successful parse of a (small) score matrix file
+ *
+ * @throws IOException
+ * @throws MalformedURLException
+ */
+ @Test(groups = "Functional")
+ public void testParseMatrix_aaIndexBlosum80()
+ throws MalformedURLException,
+ IOException
+ {
+ FileParse fp = new FileParse("resources/scoreModel/blosum80.scm",
+ DataSourceType.FILE);
+ ScoreMatrixFile parser = new ScoreMatrixFile(fp);
+ ScoreMatrix sm = parser.parseMatrix();
+
+ assertNotNull(sm);
+ assertEquals(sm.getName(), "HENS920103");
+ assertEquals(sm.getDescription(),
+ "BLOSUM80 substitution matrix (Henikoff-Henikoff, 1992)");
+ assertFalse(sm.isDNA());
+ assertTrue(sm.isProtein());
+ assertEquals(20, sm.getSize());
+
+ assertEquals(sm.getPairwiseScore('A', 'A'), 7f);
+ assertEquals(sm.getPairwiseScore('A', 'R'), -3f);
+ assertEquals(sm.getPairwiseScore('r', 'a'), -3f); // A/a equivalent
+ }
+
+ /**
+ * Test a successful parse of a (small) score matrix file
+ *
+ * @throws IOException
+ * @throws MalformedURLException
+ */
+ @Test(groups = "Functional")
+ public void testParseMatrix_aaindexFormat() throws MalformedURLException,
+ IOException
+ {
+ /*
+ * aaindex format has scores for diagonal and below only
+ */
+ String data = "H MyTest\n" + "D My description\n" + "R PMID:1438297\n"
+ + "A Authors, names\n" + "T Journal title\n"
+ + "J Journal reference\n" + "* matrix in 1/3 Bit Units\n"
+ + "M rows = ABC, cols = ABC\n" + "A\t1.0\n"
+ + "B\t4.0\t5.0\n"
+ + "C\t7.0\t8.0\t9.0\n";
+ FileParse fp = new FileParse(data, DataSourceType.PASTE);
+ ScoreMatrixFile parser = new ScoreMatrixFile(fp);
+ ScoreMatrix sm = parser.parseMatrix();
+
+ assertNotNull(sm);
+ assertEquals(sm.getSize(), 3);
+ assertEquals(sm.getName(), "MyTest");
+ assertEquals(sm.getDescription(), "My description");
+ assertEquals(sm.getPairwiseScore('A', 'A'), 1.0f);
+ assertEquals(sm.getPairwiseScore('A', 'B'), 4.0f);
+ assertEquals(sm.getPairwiseScore('A', 'C'), 7.0f);
+ assertEquals(sm.getPairwiseScore('B', 'A'), 4.0f);
+ assertEquals(sm.getPairwiseScore('B', 'B'), 5.0f);
+ assertEquals(sm.getPairwiseScore('B', 'C'), 8.0f);
+ assertEquals(sm.getPairwiseScore('C', 'C'), 9.0f);
+ assertEquals(sm.getPairwiseScore('C', 'B'), 8.0f);
+ assertEquals(sm.getPairwiseScore('C', 'A'), 7.0f);
+ }
+
+ @Test(groups = "Functional")
+ public void testParseMatrix_aaindex_mMissing()
+ throws MalformedURLException,
+ IOException
+ {
+ /*
+ * aaindex format but M cols=, rows= is missing
+ */
+ String data = "H MyTest\n" + "A\t1.0\n"
+ + "B\t4.0\t5.0\n"
+ + "C\t7.0\t8.0\t9.0\n";
+ FileParse fp = new FileParse(data, DataSourceType.PASTE);
+ ScoreMatrixFile parser = new ScoreMatrixFile(fp);
+ try
+ {
+ parser.parseMatrix();
+ fail("Expected exception");
+ } catch (FileFormatException e)
+ {
+ assertEquals(e.getMessage(), "No alphabet specified in matrix file");
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testParseMatrix_aaindex_rowColMismatch()
+ throws MalformedURLException,
+ IOException
+ {
+ String data = "H MyTest\n" + "M rows=ABC, cols=ABD\n" + "A\t1.0\n"
+ + "B\t4.0\t5.0\n"
+ + "C\t7.0\t8.0\t9.0\n";
+ FileParse fp = new FileParse(data, DataSourceType.PASTE);
+ ScoreMatrixFile parser = new ScoreMatrixFile(fp);
+ try
+ {
+ parser.parseMatrix();
+ fail("Expected exception");
+ } catch (FileFormatException e)
+ {
+ assertEquals(
+ e.getMessage(),
+ "Unexpected aaIndex score matrix data at line 2: M rows=ABC, cols=ABD rows != cols");
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testParseMatrix_ncbiHeaderRepeated()
+ {
+ String data = "ScoreMatrix BLOSUM\nScoreMatrix PAM250\nX Y\n1 2\n3 4\n";
+ try
+ {
+ new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
+ .parseMatrix();
+ fail("expected exception");
+ } catch (IOException e)
+ {
+ assertEquals(e.getMessage(),
+ "Error: 'ScoreMatrix' repeated in file at line 2");
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testParseMatrix_aaindex_tooManyRows()
+ throws MalformedURLException,
+ IOException
+ {
+ String data = "H MyTest\n" + "M rows=ABC, cols=ABC\n" + "A\t1.0\n"
+ + "B\t4.0\t5.0\n" + "C\t7.0\t8.0\t9.0\n" + "C\t7.0\t8.0\t9.0\n";
+ FileParse fp = new FileParse(data, DataSourceType.PASTE);
+ ScoreMatrixFile parser = new ScoreMatrixFile(fp);
+ try
+ {
+ parser.parseMatrix();
+ fail("Expected exception");
+ } catch (FileFormatException e)
+ {
+ assertEquals(e.getMessage(), "Too many data rows in matrix file");
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testParseMatrix_aaindex_extraDataLines()
+ throws MalformedURLException,
+ IOException
+ {
+ String data = "H MyTest\n" + "M rows=ABC, cols=ABC\n" + "A\t1.0\n"
+ + "B\t4.0\t5.0\n" + "C\t7.0\t8.0\t9.0\n" + "something extra\n";
+ FileParse fp = new FileParse(data, DataSourceType.PASTE);
+ ScoreMatrixFile parser = new ScoreMatrixFile(fp);
+ try
+ {
+ parser.parseMatrix();
+ fail("Expected exception");
+ } catch (FileFormatException e)
+ {
+ assertEquals(e.getMessage(), "Too many data rows in matrix file");
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testParseMatrix_aaindex_tooFewColumns()
+ throws MalformedURLException,
+ IOException
+ {
+ String data = "H MyTest\n" + "M rows=ABC, cols=ABC\n" + "A\t1.0\n"
+ + "B\t4.0\t5.0\n" + "C\t7.0\t8.0\n";
+ FileParse fp = new FileParse(data, DataSourceType.PASTE);
+ ScoreMatrixFile parser = new ScoreMatrixFile(fp);
+ try
+ {
+ parser.parseMatrix();
+ fail("Expected exception");
+ } catch (FileFormatException e)
+ {
+ assertEquals(
+ e.getMessage(),
+ "Expected 3 scores at line 5: 'C\t7.0\t8.0' but found 2");
+ }
+ }
+
+ /**
+ * Test a successful parse and register of a score matrix file
+ *
+ * @throws IOException
+ * @throws MalformedURLException
+ */
+ @Test(groups = "Functional")
+ public void testParse_ncbiFormat() throws MalformedURLException,
+ IOException
+ {
+ assertNull(ScoreModels.getInstance().getScoreModel("MyNewTest", null));
+
+ String data = "ScoreMatrix MyNewTest\n" + "\tA\tB\tC\n"
+ + "A\t1.0\t2.0\t3.0\n" + "B\t4.0\t5.0\t6.0\n"
+ + "C\t7.0\t8.0\t9.0\n";
+ FileParse fp = new FileParse(data, DataSourceType.PASTE);
+ ScoreMatrixFile parser = new ScoreMatrixFile(fp);
+
+ parser.parse();
+
+ ScoreMatrix sm = (ScoreMatrix) ScoreModels.getInstance().getScoreModel(
+ "MyNewTest", null);
+ assertNotNull(sm);
+ assertEquals(sm.getName(), "MyNewTest");
+ assertEquals(parser.getMatrixName(), "MyNewTest");
+ assertEquals(sm.getPairwiseScore('A', 'A'), 1.0f);
+ assertEquals(sm.getPairwiseScore('B', 'c'), 6.0f);
+ assertEquals(sm.getSize(), 3);
+ }
+}
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;
@Test(groups = { "Functional" })
public void pfamFileIO() throws Exception
{
- testFileIOwithFormat(new File(PfamFile), FileFormat.Stockholm, -1, 0);
+ testFileIOwithFormat(new File(PfamFile), FileFormat.Stockholm, -1, 0,
+ false, false, false);
}
@Test(groups = { "Functional" })
@Test(groups = { "Functional" })
public void rfamFileIO() throws Exception
{
- testFileIOwithFormat(new File(RfamFile), FileFormat.Stockholm, 2, 1);
+ testFileIOwithFormat(new File(RfamFile), FileFormat.Stockholm, 2, 1,
+ false, false, false);
}
/**
* @param ioformat
* - label for IO class used to write and read back in the data from
* f
+ * @param ignoreFeatures
+ * @param ignoreRowVisibility
+ * @param allowNullAnnotations
*/
public static void testFileIOwithFormat(File f, FileFormatI ioformat,
- int naliannot, int nminseqann)
+ int naliannot, int nminseqann, boolean ignoreFeatures,
+ boolean ignoreRowVisibility, boolean allowNullAnnotations)
{
System.out.println("Reading file: " + f);
String ff = f.getPath();
"Identify routine could not recognise output generated by '"
+ ioformat + "' writer",
ioformat.equals(identifyoutput));
- testAlignmentEquivalence(al, al_input, false);
+ testAlignmentEquivalence(al, al_input, ignoreFeatures,
+ ignoreRowVisibility, allowNullAnnotations);
int numaliannot = 0, numsqswithali = 0;
for (AlignmentAnnotation ala : al_input.getAlignmentAnnotation())
{
public static void testAlignmentEquivalence(AlignmentI al,
AlignmentI al_input, boolean ignoreFeatures)
{
+ testAlignmentEquivalence(al, al_input, ignoreFeatures, false, false);
+ }
+
+ /**
+ * assert alignment equivalence - uses special comparators for RNA structure
+ * annotation rows.
+ *
+ * @param al
+ * 'original'
+ * @param al_input
+ * 'secondary' or generated alignment from some datapreserving
+ * transformation
+ * @param ignoreFeatures
+ * when true, differences in sequence feature annotation are ignored
+ *
+ * @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 allowNullAnnotation)
+ {
assertNotNull("Original alignment was null", al);
assertNotNull("Generated alignment was null", al_input);
{
if (aa_new.length > i)
{
- assertTrue("Different alignment annotation at position " + i,
- equalss(aa_original[i], aa_new[i]));
+ assertEqualSecondaryStructure(
+ "Different alignment annotation at position " + 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);
- assertEquals("Visibility not identical.", aa_original[i].visible,
+ if (!ignoreRowVisibility)
+ {
+ assertEquals("Visibility not identical.",
+ aa_original[i].visible,
aa_new[i].visible);
+ }
assertEquals("Threshold line not identical.",
aa_original[i].threshold, aa_new[i].threshold);
// graphGroup may differ, but pattern should be the same
{
annot_original = al.getSequenceAt(i).getAnnotation()[j];
annot_new = al_input.getSequenceAt(in).getAnnotation()[j];
- assertTrue("Different annotation elements",
- equalss(annot_original, annot_new));
+ assertEqualSecondaryStructure(
+ "Different annotation elements", annot_original,
+ annot_new, allowNullAnnotation);
}
}
}
}
}
- /*
- * compare annotations
+ /**
+ * 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 boolean equalss(AlignmentAnnotation annot_or,
- AlignmentAnnotation annot_new)
+ private static void assertEqualSecondaryStructure(String message,
+ 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 (annot_or.annotations.length != annot_new.annotations.length)
{
- System.err.println("Different lengths for annotation row elements: "
+ fail("Different lengths for annotation row elements: "
+ annot_or.annotations.length + "!="
+ annot_new.annotations.length);
- return false;
}
+ boolean isRna = annot_or.isRNA();
+ assertTrue("Expected " + (isRna ? " valid RNA " : " no RNA ")
+ + " secondary structure in the row.",
+ isRna == annot_new.isRNA());
for (int i = 0; i < annot_or.annotations.length; i++)
{
Annotation an_or = annot_or.annotations[i], an_new = annot_new.annotations[i];
if (an_or != null && an_new != null)
{
- if (!an_or.displayCharacter.trim().equals(
- an_new.displayCharacter.trim())
- || !("" + an_or.secondaryStructure).trim().equals(
- ("" + an_new.secondaryStructure).trim())
- || (an_or.description != an_new.description && !((an_or.description == null && an_new.description
- .trim().length() == 0)
- || (an_new.description == null && an_or.description
- .trim().length() == 0) || an_or.description
- .trim().equals(an_new.description.trim()))))
+
+ if (isRna)
{
- System.err.println("Annotation Element Mismatch\nElement " + i
- + " in original: " + annot_or.annotations[i].toString()
- + "\nElement " + i + " in new: "
- + annot_new.annotations[i].toString());
- return false;
+ if (an_or.secondaryStructure != an_new.secondaryStructure
+ || ((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()
+ + "] but got: [" + annot_new.annotations[i].toString()
+ + "]");
+ }
+ }
+ else
+ {
+ // not RNA secondary structure, so expect all elements to match...
+ 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())
+ || (an_or.description != an_new.description && !((an_or.description == null && an_new.description
+ .trim().length() == 0)
+ || (an_new.description == null && an_or.description
+ .trim().length() == 0) || an_or.description
+ .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()
+ + "\nElement " + i + " in new: "
+ + annot_new.annotations[i].toString());
+ }
}
}
else if (annot_or.annotations[i] == null
}
else
{
- System.err.println("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()));
- return false;
+ 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);
+ }
}
}
- return 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);
+
}
}
--- /dev/null
+package jalview.io.cache;
+
+import java.util.LinkedHashSet;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class AppCacheTest
+{
+ private AppCache appCache;
+
+ private static final String TEST_CACHE_KEY = "CACHE.UNIT_TEST";
+
+ private static final String TEST_FAKE_CACHE_KEY = "CACHE.UNIT_TEST_FAKE";
+
+ @BeforeClass(alwaysRun = true)
+ public void setUpCache()
+ {
+ appCache = AppCache.getInstance();
+ }
+
+ public void generateTestCacheItems()
+ {
+ LinkedHashSet<String> testCacheItems = new LinkedHashSet<String>();
+ for (int x = 0; x < 10; x++)
+ {
+ testCacheItems.add("TestCache" + x);
+ }
+ appCache.putCache(TEST_CACHE_KEY, testCacheItems);
+ appCache.persistCache(TEST_CACHE_KEY);
+ }
+
+ @Test(groups = { "Functional" })
+ public void appCacheTest()
+ {
+ LinkedHashSet<String> cacheItems = appCache
+ .getAllCachedItemsFor(TEST_FAKE_CACHE_KEY);
+ Assert.assertEquals(cacheItems.size(), 0);
+ generateTestCacheItems();
+ cacheItems = appCache.getAllCachedItemsFor(TEST_CACHE_KEY);
+ Assert.assertEquals(cacheItems.size(), 10);
+ appCache.deleteCacheItems(TEST_CACHE_KEY);
+ cacheItems = appCache.getAllCachedItemsFor(TEST_CACHE_KEY);
+ Assert.assertEquals(cacheItems.size(), 0);
+ }
+
+ @Test(groups = { "Functional" })
+ public void appCacheLimitTest()
+ {
+ String limit = appCache.getCacheLimit(TEST_CACHE_KEY);
+ Assert.assertEquals(limit, "99");
+ limit = String.valueOf(appCache.updateCacheLimit(TEST_CACHE_KEY, 20));
+ Assert.assertEquals(limit, "20");
+ limit = appCache.getCacheLimit(TEST_CACHE_KEY);
+ Assert.assertEquals(limit, "20");
+ appCache.updateCacheLimit(TEST_CACHE_KEY, 99);
+ }
+
+
+}
--- /dev/null
+package jalview.io.cache;
+
+import java.util.LinkedHashSet;
+
+import org.junit.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class JvCacheableInputBoxTest
+{
+
+ private AppCache appCache;
+
+ private static final String TEST_CACHE_KEY = "CACHE.UNIT_TEST";
+
+ private JvCacheableInputBox<String> cacheBox = new JvCacheableInputBox<String>(
+ TEST_CACHE_KEY);
+
+ @BeforeClass(alwaysRun = true)
+ private void setUpCache()
+ {
+ appCache = AppCache.getInstance();
+ }
+
+ @Test(groups = { "Functional" })
+ public void getUserInputTest()
+ {
+ String userInput = cacheBox.getUserInput();
+ Assert.assertEquals("", userInput);
+
+ String testInput = "TestInput";
+ cacheBox.addItem(testInput);
+ cacheBox.setSelectedItem(testInput);
+
+ try
+ {
+ // This 1ms delay is essential to prevent the
+ // assertion below from executing before
+ // swing thread finishes updating the combo-box
+ Thread.sleep(100);
+ } catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ userInput = cacheBox.getUserInput();
+ Assert.assertEquals(testInput, userInput);
+ }
+
+ @Test(groups = { "Functional" })
+ public void updateCacheTest()
+ {
+ String testInput = "TestInput";
+ cacheBox.addItem(testInput);
+ cacheBox.setSelectedItem(testInput);
+ cacheBox.updateCache();
+ try
+ {
+ // This 1ms delay is essential to prevent the
+ // assertion below from executing before
+ // cacheBox.updateCache() finishes updating the cache
+ Thread.sleep(100);
+ } catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ LinkedHashSet<String> foundCache = appCache
+ .getAllCachedItemsFor(TEST_CACHE_KEY);
+ Assert.assertTrue(foundCache.contains(testInput));
+ }
+}
PIR_MODELLER=false
GAP_SYMBOL=-
SHOW_QUALITY=true
+SHOW_OCCUPANCY=true
SHOW_GROUP_CONSERVATION=false
SHOW_JWS2_SERVICES=true
SHOW_NPFEATS_TOOLTIP=true
package jalview.math;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotSame;
+import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.util.Random;
import org.testng.annotations.Test;
+import org.testng.internal.junit.ArrayAsserts;
public class MatrixTest
{
+ final static double DELTA = 0.000001d;
+
@Test(groups = "Timing")
public void testPreMultiply_timing()
{
- int rows = 500;
- int cols = 1000;
+ int rows = 50; // increase to stress test timing
+ int cols = 100;
double[][] d1 = new double[rows][cols];
double[][] d2 = new double[cols][rows];
Matrix m1 = new Matrix(d1);
* 1x3 times 3x1 is 1x1
* 2x5 + 3x6 + 4*7 = 56
*/
- Matrix m3 = m2.preMultiply(m1);
- assertEquals(m3.rows, 1);
- assertEquals(m3.cols, 1);
- assertEquals(m3.value[0][0], 56d);
+ MatrixI m3 = m2.preMultiply(m1);
+ assertEquals(m3.height(), 1);
+ assertEquals(m3.width(), 1);
+ assertEquals(m3.getValue(0, 0), 56d);
/*
* 3x1 times 1x3 is 3x3
*/
m3 = m1.preMultiply(m2);
- assertEquals(m3.rows, 3);
- assertEquals(m3.cols, 3);
- assertEquals(Arrays.toString(m3.value[0]), "[10.0, 15.0, 20.0]");
- assertEquals(Arrays.toString(m3.value[1]), "[12.0, 18.0, 24.0]");
- assertEquals(Arrays.toString(m3.value[2]), "[14.0, 21.0, 28.0]");
+ assertEquals(m3.height(), 3);
+ assertEquals(m3.width(), 3);
+ assertEquals(Arrays.toString(m3.getRow(0)), "[10.0, 15.0, 20.0]");
+ assertEquals(Arrays.toString(m3.getRow(1)), "[12.0, 18.0, 24.0]");
+ assertEquals(Arrays.toString(m3.getRow(2)), "[14.0, 21.0, 28.0]");
}
@Test(
private boolean matrixEquals(Matrix m1, Matrix m2) {
- return Arrays.deepEquals(m1.value, m2.value);
+ if (m1.width() != m2.width() || m1.height() != m2.height())
+ {
+ return false;
+ }
+ for (int i = 0; i < m1.height(); i++)
+ {
+ if (!Arrays.equals(m1.getRow(i), m2.getRow(i)))
+ {
+ return false;
+ }
+ }
+ return true;
}
@Test(groups = "Functional")
* (3020 30200)
* (5040 50400)
*/
- Matrix m1 = new Matrix(new double[][] { { 2, 3 }, { 4, 5 } });
- Matrix m2 = new Matrix(new double[][] { { 10, 100 }, { 1000, 10000 } });
- Matrix m3 = m1.postMultiply(m2);
- assertEquals(Arrays.toString(m3.value[0]), "[3020.0, 30200.0]");
- assertEquals(Arrays.toString(m3.value[1]), "[5040.0, 50400.0]");
+ MatrixI m1 = new Matrix(new double[][] { { 2, 3 }, { 4, 5 } });
+ MatrixI m2 = new Matrix(new double[][] { { 10, 100 }, { 1000, 10000 } });
+ MatrixI m3 = m1.postMultiply(m2);
+ assertEquals(Arrays.toString(m3.getRow(0)), "[3020.0, 30200.0]");
+ assertEquals(Arrays.toString(m3.getRow(1)), "[5040.0, 50400.0]");
/*
* also check m2.preMultiply(m1) - should be same as m1.postMultiply(m2)
*/
m3 = m2.preMultiply(m1);
- assertEquals(Arrays.toString(m3.value[0]), "[3020.0, 30200.0]");
- assertEquals(Arrays.toString(m3.value[1]), "[5040.0, 50400.0]");
+ assertEquals(Arrays.toString(m3.getRow(0)), "[3020.0, 30200.0]");
+ assertEquals(Arrays.toString(m3.getRow(1)), "[5040.0, 50400.0]");
/*
* m1 has more rows than columns
m1 = new Matrix(new double[][] { { 2 }, { 3 } });
m2 = new Matrix(new double[][] { { 10, 100, 1000 } });
m3 = m1.postMultiply(m2);
- assertEquals(m3.rows, 2);
- assertEquals(m3.cols, 3);
- assertEquals(Arrays.toString(m3.value[0]), "[20.0, 200.0, 2000.0]");
- assertEquals(Arrays.toString(m3.value[1]), "[30.0, 300.0, 3000.0]");
+ assertEquals(m3.height(), 2);
+ assertEquals(m3.width(), 3);
+ assertEquals(Arrays.toString(m3.getRow(0)), "[20.0, 200.0, 2000.0]");
+ assertEquals(Arrays.toString(m3.getRow(1)), "[30.0, 300.0, 3000.0]");
m3 = m2.preMultiply(m1);
- assertEquals(m3.rows, 2);
- assertEquals(m3.cols, 3);
- assertEquals(Arrays.toString(m3.value[0]), "[20.0, 200.0, 2000.0]");
- assertEquals(Arrays.toString(m3.value[1]), "[30.0, 300.0, 3000.0]");
+ assertEquals(m3.height(), 2);
+ assertEquals(m3.width(), 3);
+ assertEquals(Arrays.toString(m3.getRow(0)), "[20.0, 200.0, 2000.0]");
+ assertEquals(Arrays.toString(m3.getRow(1)), "[30.0, 300.0, 3000.0]");
/*
* m1 has more columns than rows
m1 = new Matrix(new double[][] { { 2, 3, 4 } });
m2 = new Matrix(new double[][] { { 5, 4 }, { 6, 3 }, { 7, 2 } });
m3 = m1.postMultiply(m2);
- assertEquals(m3.rows, 1);
- assertEquals(m3.cols, 2);
- assertEquals(m3.value[0][0], 56d);
- assertEquals(m3.value[0][1], 25d);
+ assertEquals(m3.height(), 1);
+ assertEquals(m3.width(), 2);
+ assertEquals(m3.getRow(0)[0], 56d);
+ assertEquals(m3.getRow(0)[1], 25d);
/*
* and check premultiply equivalent
*/
m3 = m2.preMultiply(m1);
- assertEquals(m3.rows, 1);
- assertEquals(m3.cols, 2);
- assertEquals(m3.value[0][0], 56d);
- assertEquals(m3.value[0][1], 25d);
+ assertEquals(m3.height(), 1);
+ assertEquals(m3.width(), 2);
+ assertEquals(m3.getRow(0)[0], 56d);
+ assertEquals(m3.getRow(0)[1], 25d);
}
@Test(groups = "Functional")
}
}
Matrix m1 = new Matrix(in);
- Matrix m2 = m1.copy();
+ Matrix m2 = (Matrix) m1.copy();
+ assertNotSame(m1, m2);
assertTrue(matrixEquals(m1, m2));
}
// / origmat.print(System.out);
// System.out.println();
// System.out.println(" --- transpose matrix ---- ");
- Matrix trans = origmat.transpose();
+ MatrixI trans = origmat.transpose();
// trans.print(System.out);
// System.out.println();
// System.out.println(" --- OrigT * Orig ---- ");
- Matrix symm = trans.postMultiply(origmat);
+ MatrixI symm = trans.postMultiply(origmat);
// symm.print(System.out);
// System.out.println();
// }
// System.out.println();
}
+
+ @Test(groups = "Timing")
+ public void testSign()
+ {
+ assertEquals(Matrix.sign(-1, -2), -1d);
+ assertEquals(Matrix.sign(-1, 2), 1d);
+ assertEquals(Matrix.sign(-1, 0), 1d);
+ assertEquals(Matrix.sign(1, -2), -1d);
+ assertEquals(Matrix.sign(1, 2), 1d);
+ assertEquals(Matrix.sign(1, 0), 1d);
+ }
+
+ /**
+ * Helper method to make values for a sparse, pseudo-random symmetric matrix
+ *
+ * @param rows
+ * @param cols
+ * @param occupancy
+ * one in 'occupancy' entries will be non-zero
+ * @return
+ */
+ public double[][] getSparseValues(int rows, int cols, int occupancy)
+ {
+ Random r = new Random(1729);
+
+ /*
+ * generate whole number values between -12 and +12
+ * (to mimic score matrices used in Jalview)
+ */
+ double[][] d = new double[rows][cols];
+ int m = 0;
+ for (int i = 0; i < rows; i++)
+ {
+ if (++m % occupancy == 0)
+ {
+ d[i][i] = r.nextInt() % 13; // diagonal
+ }
+ for (int j = 0; j < i; j++)
+ {
+ if (++m % occupancy == 0)
+ {
+ d[i][j] = r.nextInt() % 13;
+ d[j][i] = d[i][j];
+ }
+ }
+ }
+ return d;
+
+ }
+
+ /**
+ * Verify that the results of method tred() are the same if the calculation is
+ * redone
+ */
+ @Test(groups = "Functional")
+ public void testTred_reproducible()
+ {
+ /*
+ * make a pseudo-random symmetric matrix as required for tred/tqli
+ */
+ int rows = 10;
+ int cols = rows;
+ double[][] d = getSparseValues(rows, cols, 3);
+
+ /*
+ * make a copy of the values so m1, m2 are not
+ * sharing arrays!
+ */
+ double[][] d1 = new double[rows][cols];
+ for (int row = 0; row < rows; row++)
+ {
+ for (int col = 0; col < cols; col++)
+ {
+ d1[row][col] = d[row][col];
+ }
+ }
+ Matrix m1 = new Matrix(d);
+ Matrix m2 = new Matrix(d1);
+ assertMatricesMatch(m1, m2); // sanity check
+ m1.tred();
+ m2.tred();
+ assertMatricesMatch(m1, m2);
+ }
+
+ private void assertMatricesMatch(MatrixI m1, MatrixI m2)
+ {
+ if (m1.height() != m2.height())
+ {
+ fail("height mismatch");
+ }
+ if (m1.width() != m2.width())
+ {
+ fail("width mismatch");
+ }
+ for (int row = 0; row < m1.height(); row++)
+ {
+ for (int col = 0; col < m1.width(); col++)
+ {
+ double v2 = m2.getValue(row, col);
+ double v1 = m1.getValue(row, col);
+ if (Math.abs(v1 - v2) > DELTA)
+ {
+ fail(String.format("At [%d, %d] %f != %f", row, col, v1, v2));
+ }
+ }
+ }
+ ArrayAsserts.assertArrayEquals(m1.getD(), m2.getD(), 0.00001d);
+ ArrayAsserts.assertArrayEquals(m1.getE(), m2.getE(), 0.00001d);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindMinMax()
+ {
+ /*
+ * empty matrix case
+ */
+ Matrix m = new Matrix(new double[][] { {} });
+ assertNull(m.findMinMax());
+
+ /*
+ * normal case
+ */
+ double[][] vals = new double[2][];
+ vals[0] = new double[] {7d, 1d, -2.3d};
+ vals[1] = new double[] {-12d, 94.3d, -102.34d};
+ m = new Matrix(vals);
+ double[] minMax = m.findMinMax();
+ assertEquals(minMax[0], -102.34d);
+ assertEquals(minMax[1], 94.3d);
+ }
+
+ @Test(groups = { "Functional", "Timing" })
+ public void testFindMinMax_timing()
+ {
+ Random r = new Random();
+ int size = 1000; // increase to stress test timing
+ double[][] vals = new double[size][size];
+ double max = -Double.MAX_VALUE;
+ double min = Double.MAX_VALUE;
+ for (int i = 0; i < size; i++)
+ {
+ vals[i] = new double[size];
+ for (int j = 0; j < size; j++)
+ {
+ // use nextLong rather than nextDouble to include negative values
+ double d = r.nextLong();
+ if (d > max)
+ {
+ max = d;
+ }
+ if (d < min)
+ {
+ min = d;
+ }
+ vals[i][j] = d;
+ }
+ }
+ Matrix m = new Matrix(vals);
+ long now = System.currentTimeMillis();
+ double[] minMax = m.findMinMax();
+ System.out.println(String.format("findMinMax for %d x %d took %dms",
+ size, size, (System.currentTimeMillis() - now)));
+ assertEquals(minMax[0], min);
+ assertEquals(minMax[1], max);
+ }
+
+ /**
+ * Test range reversal with maximum value becoming zero
+ */
+ @Test(groups = "Functional")
+ public void testReverseRange_maxToZero()
+ {
+ Matrix m1 = new Matrix(
+ new double[][] { { 2, 3.5, 4 }, { -3.4, 4, 15 } });
+
+ /*
+ * subtract all from max: range -3.4 to 15 becomes 18.4 to 0
+ */
+ m1.reverseRange(true);
+ assertEquals(m1.getValue(0, 0), 13d, DELTA);
+ assertEquals(m1.getValue(0, 1), 11.5d, DELTA);
+ assertEquals(m1.getValue(0, 2), 11d, DELTA);
+ assertEquals(m1.getValue(1, 0), 18.4d, DELTA);
+ assertEquals(m1.getValue(1, 1), 11d, DELTA);
+ assertEquals(m1.getValue(1, 2), 0d, DELTA);
+
+ /*
+ * repeat operation - range is now 0 to 18.4
+ */
+ m1.reverseRange(true);
+ assertEquals(m1.getValue(0, 0), 5.4d, DELTA);
+ assertEquals(m1.getValue(0, 1), 6.9d, DELTA);
+ assertEquals(m1.getValue(0, 2), 7.4d, DELTA);
+ assertEquals(m1.getValue(1, 0), 0d, DELTA);
+ assertEquals(m1.getValue(1, 1), 7.4d, DELTA);
+ assertEquals(m1.getValue(1, 2), 18.4d, DELTA);
+ }
+
+ /**
+ * Test range reversal with minimum and maximum values swapped
+ */
+ @Test(groups = "Functional")
+ public void testReverseRange_swapMinMax()
+ {
+ Matrix m1 = new Matrix(
+ new double[][] { { 2, 3.5, 4 }, { -3.4, 4, 15 } });
+
+ /*
+ * swap all values in min-max range
+ * = subtract from (min + max = 11.6)
+ * range -3.4 to 15 becomes 18.4 to -3.4
+ */
+ m1.reverseRange(false);
+ assertEquals(m1.getValue(0, 0), 9.6d, DELTA);
+ assertEquals(m1.getValue(0, 1), 8.1d, DELTA);
+ assertEquals(m1.getValue(0, 2), 7.6d, DELTA);
+ assertEquals(m1.getValue(1, 0), 15d, DELTA);
+ assertEquals(m1.getValue(1, 1), 7.6d, DELTA);
+ assertEquals(m1.getValue(1, 2), -3.4d, DELTA);
+
+ /*
+ * repeat operation - original values restored
+ */
+ m1.reverseRange(false);
+ assertEquals(m1.getValue(0, 0), 2d, DELTA);
+ assertEquals(m1.getValue(0, 1), 3.5d, DELTA);
+ assertEquals(m1.getValue(0, 2), 4d, DELTA);
+ assertEquals(m1.getValue(1, 0), -3.4d, DELTA);
+ assertEquals(m1.getValue(1, 1), 4d, DELTA);
+ assertEquals(m1.getValue(1, 2), 15d, DELTA);
+ }
+
+ @Test(groups = "Functional")
+ public void testMultiply()
+ {
+ Matrix m = new Matrix(new double[][] { { 2, 3.5, 4 }, { -3.4, 4, 15 } });
+ m.multiply(2d);
+ assertEquals(m.getValue(0, 0), 4d, DELTA);
+ assertEquals(m.getValue(0, 1), 7d, DELTA);
+ assertEquals(m.getValue(0, 2), 8d, DELTA);
+ assertEquals(m.getValue(1, 0), -6.8d, DELTA);
+ assertEquals(m.getValue(1, 1), 8d, DELTA);
+ assertEquals(m.getValue(1, 2), 30d, DELTA);
+ }
+
+ @Test(groups = "Functional")
+ public void testConstructor()
+ {
+ double[][] values = new double[][] { { 1, 2, 3 }, { 4, 5, 6 } };
+ Matrix m = new Matrix(values);
+ assertEquals(m.getValue(0, 0), 1d, DELTA);
+
+ /*
+ * verify the matrix has a copy of the original array
+ */
+ assertNotSame(values[0], m.getRow(0));
+ values[0][0] = -1d;
+ assertEquals(m.getValue(0, 0), 1d, DELTA); // unchanged
+ }
}
--- /dev/null
+package jalview.math;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.Random;
+
+import org.testng.annotations.Test;
+import org.testng.internal.junit.ArrayAsserts;
+
+public class SparseMatrixTest
+{
+ final static double DELTA = 0.0001d;
+
+ Random r = new Random(1729);
+
+ @Test(groups = "Functional")
+ public void testConstructor()
+ {
+ MatrixI m1 = new SparseMatrix(
+ new double[][] { { 2, 0, 4 }, { 0, 6, 0 } });
+ assertEquals(m1.getValue(0, 0), 2d);
+ assertEquals(m1.getValue(0, 1), 0d);
+ assertEquals(m1.getValue(0, 2), 4d);
+ assertEquals(m1.getValue(1, 0), 0d);
+ assertEquals(m1.getValue(1, 1), 6d);
+ assertEquals(m1.getValue(1, 2), 0d);
+ }
+
+ @Test(groups = "Functional")
+ public void testTranspose()
+ {
+ MatrixI m1 = new SparseMatrix(
+ new double[][] { { 2, 0, 4 }, { 5, 6, 0 } });
+ MatrixI m2 = m1.transpose();
+ assertTrue(m2 instanceof SparseMatrix);
+ assertEquals(m2.height(), 3);
+ assertEquals(m2.width(), 2);
+ assertEquals(m2.getValue(0, 0), 2d);
+ assertEquals(m2.getValue(0, 1), 5d);
+ assertEquals(m2.getValue(1, 0), 0d);
+ assertEquals(m2.getValue(1, 1), 6d);
+ assertEquals(m2.getValue(2, 0), 4d);
+ assertEquals(m2.getValue(2, 1), 0d);
+ }
+ @Test(groups = "Functional")
+ public void testPreMultiply()
+ {
+ MatrixI m1 = new SparseMatrix(new double[][] { { 2, 3, 4 } }); // 1x3
+ MatrixI m2 = new SparseMatrix(new double[][] { { 5 }, { 6 }, { 7 } }); // 3x1
+
+ /*
+ * 1x3 times 3x1 is 1x1
+ * 2x5 + 3x6 + 4*7 = 56
+ */
+ MatrixI m3 = m2.preMultiply(m1);
+ assertFalse(m3 instanceof SparseMatrix);
+ assertEquals(m3.height(), 1);
+ assertEquals(m3.width(), 1);
+ assertEquals(m3.getValue(0, 0), 56d);
+
+ /*
+ * 3x1 times 1x3 is 3x3
+ */
+ m3 = m1.preMultiply(m2);
+ assertEquals(m3.height(), 3);
+ assertEquals(m3.width(), 3);
+ assertEquals(m3.getValue(0, 0), 10d);
+ assertEquals(m3.getValue(0, 1), 15d);
+ assertEquals(m3.getValue(0, 2), 20d);
+ assertEquals(m3.getValue(1, 0), 12d);
+ assertEquals(m3.getValue(1, 1), 18d);
+ assertEquals(m3.getValue(1, 2), 24d);
+ assertEquals(m3.getValue(2, 0), 14d);
+ assertEquals(m3.getValue(2, 1), 21d);
+ assertEquals(m3.getValue(2, 2), 28d);
+ }
+
+ @Test(
+ groups = "Functional",
+ expectedExceptions = { IllegalArgumentException.class })
+ public void testPreMultiply_tooManyColumns()
+ {
+ Matrix m1 = new SparseMatrix(
+ new double[][] { { 2, 3, 4 }, { 3, 4, 5 } }); // 2x3
+
+ /*
+ * 2x3 times 2x3 invalid operation -
+ * multiplier has more columns than multiplicand has rows
+ */
+ m1.preMultiply(m1);
+ fail("Expected exception");
+ }
+
+ @Test(
+ groups = "Functional",
+ expectedExceptions = { IllegalArgumentException.class })
+ public void testPreMultiply_tooFewColumns()
+ {
+ Matrix m1 = new SparseMatrix(
+ new double[][] { { 2, 3, 4 }, { 3, 4, 5 } }); // 2x3
+
+ /*
+ * 3x2 times 3x2 invalid operation -
+ * multiplier has more columns than multiplicand has row
+ */
+ m1.preMultiply(m1);
+ fail("Expected exception");
+ }
+
+ @Test(groups = "Functional")
+ public void testPostMultiply()
+ {
+ /*
+ * Square matrices
+ * (2 3) . (10 100)
+ * (4 5) (1000 10000)
+ * =
+ * (3020 30200)
+ * (5040 50400)
+ */
+ MatrixI m1 = new SparseMatrix(new double[][] { { 2, 3 }, { 4, 5 } });
+ MatrixI m2 = new SparseMatrix(new double[][] { { 10, 100 },
+ { 1000, 10000 } });
+ MatrixI m3 = m1.postMultiply(m2);
+ assertEquals(m3.getValue(0, 0), 3020d);
+ assertEquals(m3.getValue(0, 1), 30200d);
+ assertEquals(m3.getValue(1, 0), 5040d);
+ assertEquals(m3.getValue(1, 1), 50400d);
+
+ /*
+ * also check m2.preMultiply(m1) - should be same as m1.postMultiply(m2)
+ */
+ MatrixI m4 = m2.preMultiply(m1);
+ assertMatricesMatch(m3, m4, 0.00001d);
+
+ /*
+ * m1 has more rows than columns
+ * (2).(10 100 1000) = (20 200 2000)
+ * (3) (30 300 3000)
+ */
+ m1 = new SparseMatrix(new double[][] { { 2 }, { 3 } });
+ m2 = new SparseMatrix(new double[][] { { 10, 100, 1000 } });
+ m3 = m1.postMultiply(m2);
+ assertEquals(m3.height(), 2);
+ assertEquals(m3.width(), 3);
+ assertEquals(m3.getValue(0, 0), 20d);
+ assertEquals(m3.getValue(0, 1), 200d);
+ assertEquals(m3.getValue(0, 2), 2000d);
+ assertEquals(m3.getValue(1, 0), 30d);
+ assertEquals(m3.getValue(1, 1), 300d);
+ assertEquals(m3.getValue(1, 2), 3000d);
+
+ m4 = m2.preMultiply(m1);
+ assertMatricesMatch(m3, m4, 0.00001d);
+
+ /*
+ * m1 has more columns than rows
+ * (2 3 4) . (5 4) = (56 25)
+ * (6 3)
+ * (7 2)
+ * [0, 0] = 2*5 + 3*6 + 4*7 = 56
+ * [0, 1] = 2*4 + 3*3 + 4*2 = 25
+ */
+ m1 = new SparseMatrix(new double[][] { { 2, 3, 4 } });
+ m2 = new SparseMatrix(new double[][] { { 5, 4 }, { 6, 3 }, { 7, 2 } });
+ m3 = m1.postMultiply(m2);
+ assertEquals(m3.height(), 1);
+ assertEquals(m3.width(), 2);
+ assertEquals(m3.getValue(0, 0), 56d);
+ assertEquals(m3.getValue(0, 1), 25d);
+
+ /*
+ * and check premultiply equivalent
+ */
+ m4 = m2.preMultiply(m1);
+ assertMatricesMatch(m3, m4, 0.00001d);
+ }
+
+ @Test(groups = "Timing")
+ public void testSign()
+ {
+ assertEquals(Matrix.sign(-1, -2), -1d);
+ assertEquals(Matrix.sign(-1, 2), 1d);
+ assertEquals(Matrix.sign(-1, 0), 1d);
+ assertEquals(Matrix.sign(1, -2), -1d);
+ assertEquals(Matrix.sign(1, 2), 1d);
+ assertEquals(Matrix.sign(1, 0), 1d);
+ }
+
+ /**
+ * Verify that the results of method tred() are the same for SparseMatrix as
+ * they are for Matrix (i.e. a regression test rather than an absolute test of
+ * correctness of results)
+ */
+ @Test(groups = "Functional")
+ public void testTred_matchesMatrix()
+ {
+ /*
+ * make a pseudo-random symmetric matrix as required for tred/tqli
+ */
+ int rows = 10;
+ int cols = rows;
+ double[][] d = getSparseValues(rows, cols, 3);
+
+ /*
+ * make a copy of the values so m1, m2 are not
+ * sharing arrays!
+ */
+ double[][] d1 = new double[rows][cols];
+ for (int row = 0; row < rows; row++)
+ {
+ for (int col = 0; col < cols; col++)
+ {
+ d1[row][col] = d[row][col];
+ }
+ }
+ Matrix m1 = new Matrix(d);
+ Matrix m2 = new SparseMatrix(d1);
+ assertMatricesMatch(m1, m2, 0.00001d); // sanity check
+ m1.tred();
+ m2.tred();
+ assertMatricesMatch(m1, m2, 0.00001d);
+ }
+
+ private void assertMatricesMatch(MatrixI m1, MatrixI m2, double delta)
+ {
+ if (m1.height() != m2.height())
+ {
+ fail("height mismatch");
+ }
+ if (m1.width() != m2.width())
+ {
+ fail("width mismatch");
+ }
+ for (int row = 0; row < m1.height(); row++)
+ {
+ for (int col = 0; col < m1.width(); col++)
+ {
+ double v2 = m2.getValue(row, col);
+ double v1 = m1.getValue(row, col);
+ if (Math.abs(v1 - v2) > DELTA)
+ {
+ fail(String.format("At [%d, %d] %f != %f", row, col, v1, v2));
+ }
+ }
+ }
+ ArrayAsserts.assertArrayEquals(m1.getD(), m2.getD(), delta);
+ ArrayAsserts.assertArrayEquals(m1.getE(), m2.getE(), 0.00001d);
+ }
+
+ @Test
+ public void testGetValue()
+ {
+ double[][] d = new double[][] { { 0, 0, 1, 0, 0 }, { 2, 3, 0, 0, 0 },
+ { 4, 0, 0, 0, 5 } };
+ MatrixI m = new SparseMatrix(d);
+ for (int row = 0; row < 3; row++)
+ {
+ for (int col = 0; col < 5; col++)
+ {
+ assertEquals(m.getValue(row, col), d[row][col],
+ String.format("At [%d, %d]", row, col));
+ }
+ }
+ }
+
+ /**
+ * Verify that the results of method tqli() are the same for SparseMatrix as
+ * they are for Matrix (i.e. a regression test rather than an absolute test of
+ * correctness of results)
+ *
+ * @throws Exception
+ */
+ @Test(groups = "Functional")
+ public void testTqli_matchesMatrix() throws Exception
+ {
+ /*
+ * make a pseudo-random symmetric matrix as required for tred
+ */
+ int rows = 6;
+ int cols = rows;
+ double[][] d = getSparseValues(rows, cols, 3);
+
+ /*
+ * make a copy of the values so m1, m2 are not
+ * sharing arrays!
+ */
+ double[][] d1 = new double[rows][cols];
+ for (int row = 0; row < rows; row++)
+ {
+ for (int col = 0; col < cols; col++)
+ {
+ d1[row][col] = d[row][col];
+ }
+ }
+ Matrix m1 = new Matrix(d);
+ Matrix m2 = new SparseMatrix(d1);
+
+ // have to do tred() before doing tqli()
+ m1.tred();
+ m2.tred();
+ assertMatricesMatch(m1, m2, 0.00001d);
+
+ m1.tqli();
+ m2.tqli();
+ assertMatricesMatch(m1, m2, 0.00001d);
+ }
+
+ /**
+ * Helper method to make values for a sparse, pseudo-random symmetric matrix
+ *
+ * @param rows
+ * @param cols
+ * @param occupancy
+ * one in 'occupancy' entries will be non-zero
+ * @return
+ */
+ public double[][] getSparseValues(int rows, int cols, int occupancy)
+ {
+ /*
+ * generate whole number values between -12 and +12
+ * (to mimic score matrices used in Jalview)
+ */
+ double[][] d = new double[rows][cols];
+ int m = 0;
+ for (int i = 0; i < rows; i++)
+ {
+ if (++m % occupancy == 0)
+ {
+ d[i][i] = r.nextInt() % 13; // diagonal
+ }
+ for (int j = 0; j < i; j++)
+ {
+ if (++m % occupancy == 0)
+ {
+ d[i][j] = r.nextInt() % 13;
+ d[j][i] = d[i][j];
+ }
+ }
+ }
+ return d;
+
+ }
+
+ /**
+ * Test that verifies that the result of preMultiply is a SparseMatrix if more
+ * than 80% zeroes, else a Matrix
+ */
+ @Test(groups = "Functional")
+ public void testPreMultiply_sparseProduct()
+ {
+ MatrixI m1 = new SparseMatrix(new double[][] { { 1 }, { 0 }, { 0 },
+ { 0 }, { 0 } }); // 5x1
+ MatrixI m2 = new SparseMatrix(new double[][] { { 1, 1, 1, 1 } }); // 1x4
+
+ /*
+ * m1.m2 makes a row of 4 1's, and 4 rows of zeros
+ * 20% non-zero so not 'sparse'
+ */
+ MatrixI m3 = m2.preMultiply(m1);
+ assertFalse(m3 instanceof SparseMatrix);
+
+ /*
+ * replace a 1 with a 0 in the product:
+ * it is now > 80% zero so 'sparse'
+ */
+ m2 = new SparseMatrix(new double[][] { { 1, 1, 1, 0 } });
+ m3 = m2.preMultiply(m1);
+ assertTrue(m3 instanceof SparseMatrix);
+ }
+
+ @Test(groups = "Functional")
+ public void testFillRatio()
+ {
+ SparseMatrix m1 = new SparseMatrix(new double[][] { { 2, 0, 4, 1, 0 },
+ { 0, 6, 0, 0, 0 } });
+ assertEquals(m1.getFillRatio(), 0.4f);
+ }
+
+ /**
+ * Verify that the results of method tred() are the same if the calculation is
+ * redone
+ */
+ @Test(groups = "Functional")
+ public void testTred_reproducible()
+ {
+ /*
+ * make a pseudo-random symmetric matrix as required for tred/tqli
+ */
+ int rows = 10;
+ int cols = rows;
+ double[][] d = getSparseValues(rows, cols, 3);
+
+ /*
+ * make a copy of the values so m1, m2 are not
+ * sharing arrays!
+ */
+ double[][] d1 = new double[rows][cols];
+ for (int row = 0; row < rows; row++)
+ {
+ for (int col = 0; col < cols; col++)
+ {
+ d1[row][col] = d[row][col];
+ }
+ }
+ Matrix m1 = new SparseMatrix(d);
+ Matrix m2 = new SparseMatrix(d1);
+ assertMatricesMatch(m1, m2, 1.0e16); // sanity check
+ m1.tred();
+ m2.tred();
+ assertMatricesMatch(m1, m2, 0.00001d);
+ }
+}
\ No newline at end of file
--- /dev/null
+package jalview.renderer.seqfeatures;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import jalview.api.FeatureColourI;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.AlignViewport;
+import jalview.gui.FeatureRenderer;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+import jalview.schemes.FeatureColour;
+
+import java.awt.Color;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for feature colour determination, including but not limited to
+ * <ul>
+ * <li>gap position</li>
+ * <li>no features present</li>
+ * <li>features present but show features turned off</li>
+ * <li>features displayed but selected feature turned off</li>
+ * <li>features displayed but feature group turned off</li>
+ * <li>feature displayed but none at the specified position</li>
+ * <li>multiple features at position, with no transparency</li>
+ * <li>multiple features at position, with transparency</li>
+ * <li>score graduated feature colour</li>
+ * <li>contact feature start at the selected position</li>
+ * <li>contact feature end at the selected position</li>
+ * <li>contact feature straddling the selected position (not shown)</li>
+ * </ul>
+ */
+public class FeatureColourFinderTest
+{
+ private AlignViewport av;
+
+ private SequenceI seq;
+
+ private FeatureColourFinder finder;
+
+ private AlignFrame af;
+
+ private FeatureRenderer fr;
+
+ @BeforeTest(alwaysRun = true)
+ public void setUp()
+ {
+ // aligned column 8 is sequence position 6
+ String s = ">s1\nABCDE---FGHIJKLMNOPQRSTUVWXYZ\n";
+ af = new FileLoader().LoadFileWaitTillLoaded(s,
+ DataSourceType.PASTE);
+ av = af.getViewport();
+ seq = av.getAlignment().getSequenceAt(0);
+ fr = af.getFeatureRenderer();
+ finder = new FeatureColourFinder(fr);
+ }
+
+ /**
+ * Clear down any sequence features before each test (not as easy as it
+ * sounds...)
+ */
+ @BeforeMethod(alwaysRun = true)
+ public void setUpBeforeTest()
+ {
+ SequenceFeature[] sfs = seq.getSequenceFeatures();
+ if (sfs != null)
+ {
+ for (SequenceFeature sf : sfs)
+ {
+ seq.deleteFeature(sf);
+ }
+ }
+ fr.findAllFeatures(true);
+
+ /*
+ * reset all feature groups to visible
+ */
+ for (String group : fr.getGroups(false))
+ {
+ fr.setGroupVisibility(group, true);
+ }
+
+ fr.clearRenderOrder();
+ av.setShowSequenceFeatures(true);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_noFeatures()
+ {
+ av.setShowSequenceFeatures(false);
+ Color c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.blue);
+
+ av.setShowSequenceFeatures(true);
+ c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.blue);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_noFeaturesShown()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(false);
+ Color c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.blue);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_singleFeatureAtPosition()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ fr.setColour("Metal", new FeatureColour(Color.red));
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+ Color c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.red);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_gapPosition()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12, 0f,
+ null));
+ fr.setColour("Metal", new FeatureColour(Color.red));
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+ Color c = finder.findFeatureColour(null, seq, 6);
+ assertEquals(c, Color.white);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_multipleFeaturesAtPositionNoTransparency()
+ {
+ /*
+ * featuresAdded -> FeatureRendererModel.updateRenderOrder which adds any
+ * new features 'on top' (but reverses the order of any added features)
+ */
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ FeatureColour red = new FeatureColour(Color.red);
+ fr.setColour("Metal", red);
+ fr.featuresAdded();
+ seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
+ Float.NaN, "DomainGroup"));
+ FeatureColour green = new FeatureColour(Color.green);
+ fr.setColour("Domain", green);
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+
+ /*
+ * expect Domain (green) to be rendered above Metal (red)
+ */
+ Color c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.green);
+
+ /*
+ * now promote Metal above Domain
+ * - currently no way other than mimicking reordering of
+ * table in Feature Settings
+ */
+ Object[][] data = new Object[2][];
+ data[0] = new Object[] { "Metal", red, true };
+ data[1] = new Object[] { "Domain", green, true };
+ fr.setFeaturePriority(data);
+ c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.red);
+
+ /*
+ * ..and turn off display of Metal
+ */
+ data[0][2] = false;
+ fr.setFeaturePriority(data);
+ c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.green);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_singleFeatureNotAtPosition()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 8, 12,
+ Float.NaN, "MetalGroup"));
+ fr.setColour("Metal", new FeatureColour(Color.red));
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+ // column 2 = sequence position 3
+ Color c = finder.findFeatureColour(Color.blue, seq, 2);
+ assertEquals(c, Color.blue);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_featureTypeNotDisplayed()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ FeatureColour red = new FeatureColour(Color.red);
+ fr.setColour("Metal", red);
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+ Color c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.red);
+
+ /*
+ * turn off display of Metal - is this the easiest way to do it??
+ */
+ Object[][] data = new Object[1][];
+ data[0] = new Object[] { "Metal", red, false };
+ fr.setFeaturePriority(data);
+ c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.blue);
+
+ /*
+ * turn display of Metal back on
+ */
+ data[0] = new Object[] { "Metal", red, true };
+ fr.setFeaturePriority(data);
+ c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.red);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_featureGroupNotDisplayed()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ FeatureColour red = new FeatureColour(Color.red);
+ fr.setColour("Metal", red);
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+ Color c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.red);
+
+ /*
+ * turn off display of MetalGroup
+ */
+ fr.setGroupVisibility("MetalGroup", false);
+ c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.blue);
+
+ /*
+ * turn display of MetalGroup back on
+ */
+ fr.setGroupVisibility("MetalGroup", true);
+ c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.red);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_contactFeature()
+ {
+ /*
+ * currently contact feature == type "Disulphide Bond" or "Disulfide Bond" !!
+ */
+ seq.addSequenceFeature(new SequenceFeature("Disulphide Bond",
+ "Contact", 2, 12, Float.NaN, "Disulphide"));
+ fr.setColour("Disulphide Bond", new FeatureColour(Color.red));
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+
+ /*
+ * Contact positions are residues 2 and 12
+ * which are columns 1 and 14
+ * positions in between don't count for a contact feature!
+ */
+ Color c = finder.findFeatureColour(Color.blue, seq, 10);
+ assertEquals(c, Color.blue);
+ c = finder.findFeatureColour(Color.blue, seq, 8);
+ assertEquals(c, Color.blue);
+ c = finder.findFeatureColour(Color.blue, seq, 1);
+ assertEquals(c, Color.red);
+ c = finder.findFeatureColour(Color.blue, seq, 14);
+ assertEquals(c, Color.red);
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_graduatedFeatureColour()
+ {
+ seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 2,
+ 2, 0f, "KdGroup"));
+ seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 4,
+ 4, 5f, "KdGroup"));
+ seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 7,
+ 7, 10f, "KdGroup"));
+
+ /*
+ * graduated colour from 0 to 10
+ */
+ Color min = new Color(100, 50, 150);
+ Color max = new Color(200, 0, 100);
+ FeatureColourI fc = new FeatureColour(min, max, 0, 10);
+ fr.setColour("kd", fc);
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+
+ /*
+ * position 2, column 1, score 0 - minimum colour in range
+ */
+ Color c = finder.findFeatureColour(Color.blue, seq, 1);
+ assertEquals(c, min);
+
+ /*
+ * position 7, column 9, score 10 - maximum colour in range
+ */
+ c = finder.findFeatureColour(Color.blue, seq, 9);
+ assertEquals(c, max);
+
+ /*
+ * position 4, column 3, score 5 - half way from min to max
+ */
+ c = finder.findFeatureColour(Color.blue, seq, 3);
+ assertEquals(c, new Color(150, 25, 125));
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_transparencySingleFeature()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ FeatureColour red = new FeatureColour(Color.red);
+ fr.setColour("Metal", red);
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+
+ /*
+ * the FeatureSettings transparency slider has range 0-70 which
+ * corresponds to a transparency value of 1 - 0.3
+ * A value of 0.4 gives a combination of
+ * 0.4 * red(255, 0, 0) + 0.6 * cyan(0, 255, 255) = (102, 153, 153)
+ */
+ fr.setTransparency(0.4f);
+ Color c = finder.findFeatureColour(Color.cyan, seq, 10);
+ assertEquals(c, new Color(102, 153, 153));
+ }
+
+ @Test(groups = "Functional")
+ public void testFindFeatureColour_transparencyTwoFeatures()
+ {
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ FeatureColour red = new FeatureColour(Color.red);
+ fr.setColour("Metal", red);
+ fr.featuresAdded();
+ seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
+ Float.NaN, "DomainGroup"));
+ FeatureColour green = new FeatureColour(Color.green);
+ fr.setColour("Domain", green);
+ fr.featuresAdded();
+ av.setShowSequenceFeatures(true);
+
+ /*
+ * Domain (green) rendered above Metal (red) above background (cyan)
+ * 1) 0.6 * red(255, 0, 0) + 0.4 * cyan(0, 255, 255) = (153, 102, 102)
+ * 2) 0.6* green(0, 255, 0) + 0.4 * (153, 102, 102) = (61, 194, 41) rounded
+ */
+ fr.setTransparency(0.6f);
+ Color c = finder.findFeatureColour(Color.cyan, seq, 10);
+ assertEquals(c, new Color(61, 194, 41));
+
+ /*
+ * now promote Metal above Domain
+ * - currently no way other than mimicking reordering of
+ * table in Feature Settings
+ * Metal (red) rendered above Domain (green) above background (cyan)
+ * 1) 0.6 * green(0, 255, 0) + 0.4 * cyan(0, 255, 255) = (0, 255, 102)
+ * 2) 0.6* red(255, 0, 0) + 0.4 * (0, 255, 102) = (153, 102, 41) rounded
+ */
+ Object[][] data = new Object[2][];
+ data[0] = new Object[] { "Metal", red, true };
+ data[1] = new Object[] { "Domain", green, true };
+ fr.setFeaturePriority(data);
+ c = finder.findFeatureColour(Color.cyan, seq, 10);
+ assertEquals(c, new Color(153, 102, 41));
+
+ /*
+ * ..and turn off display of Metal
+ * Domain (green) above background (pink)
+ * 0.6 * green(0, 255, 0) + 0.4 * pink(255, 175, 175) = (102, 223, 70)
+ */
+ data[0][2] = false;
+ fr.setFeaturePriority(data);
+ c = finder.findFeatureColour(Color.pink, seq, 10);
+ assertEquals(c, new Color(102, 223, 70));
+ }
+
+ @Test(groups = "Functional")
+ public void testNoFeaturesDisplayed()
+ {
+ /*
+ * no features on alignment to render
+ */
+ assertTrue(finder.noFeaturesDisplayed());
+
+ /*
+ * add a feature
+ * it will be automatically set visible but we leave
+ * the viewport configured not to show features
+ */
+ av.setShowSequenceFeatures(false);
+ seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
+ Float.NaN, "MetalGroup"));
+ FeatureColour red = new FeatureColour(Color.red);
+ fr.setColour("Metal", red);
+ fr.featuresAdded();
+ assertTrue(finder.noFeaturesDisplayed());
+
+ /*
+ * turn on feature display
+ */
+ av.setShowSequenceFeatures(true);
+ assertFalse(finder.noFeaturesDisplayed());
+
+ /*
+ * turn off display of Metal
+ */
+ Object[][] data = new Object[1][];
+ data[0] = new Object[] { "Metal", red, false };
+ fr.setFeaturePriority(data);
+ assertTrue(finder.noFeaturesDisplayed());
+
+ /*
+ * turn display of Metal back on
+ */
+ fr.setVisible("Metal");
+ assertFalse(finder.noFeaturesDisplayed());
+
+ /*
+ * turn off MetalGroup - has no effect here since the group of a
+ * sequence feature instance is independent of its type
+ */
+ fr.setGroupVisibility("MetalGroup", false);
+ assertFalse(finder.noFeaturesDisplayed());
+
+ /*
+ * a finder with no feature renderer
+ */
+ FeatureColourFinder finder2 = new FeatureColourFinder(null);
+ assertTrue(finder2.noFeaturesDisplayed());
+ }
+}
--- /dev/null
+package jalview.schemes;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.GraphLine;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+
+import java.awt.Color;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class AnnotationColourGradientTest
+{
+ final static int WIDTH = 11;
+
+ final static int THRESHOLD_FIVE = 5;
+
+ private AlignmentAnnotation ann;
+
+ private SequenceI seq;
+
+ private AlignmentI al;
+
+ Color minColour = new Color(50, 200, 150);
+
+ Color maxColour = new Color(150, 100, 250);
+
+ /**
+ * Setup creates an annotation over 11 columns with values 0-10 and threshold
+ * 5
+ */
+ @BeforeClass(alwaysRun = true)
+ public void setUp()
+ {
+ Annotation[] anns = new Annotation[WIDTH];
+ /*
+ * set annotations with values 0-10, graded colours
+ */
+ for (int col = 0; col < WIDTH; col++)
+ {
+ int hue = col * 20;
+ Color colour = new Color(hue, hue, hue);
+ anns[col] = new Annotation("a", "a", 'a', col, colour);
+ }
+
+ seq = new Sequence("", "");
+ al = new Alignment(new SequenceI[]{ seq});
+
+ /*
+ * AlignmentAnnotation constructor works out min-max range
+ */
+ ann = new AlignmentAnnotation("", "", anns);
+ ann.setThreshold(new GraphLine(THRESHOLD_FIVE, "", Color.RED));
+ seq.addAlignmentAnnotation(ann);
+ }
+
+ @Test(groups = "Functional")
+ public void testShadeCalculation_noThreshold()
+ {
+ AnnotationColourGradient testee = new AnnotationColourGradient(ann,
+ minColour, maxColour, AnnotationColourGradient.NO_THRESHOLD);
+ for (int col = 0; col < WIDTH; col++)
+ {
+ Color result = testee.shadeCalculation(ann, col);
+ /*
+ * column <n> is n/10 of the way from minCol to maxCol
+ */
+ Color expected = new Color(50 + 10 * col, 200 - 10 * col,
+ 150 + 10 * col);
+ assertEquals(result, expected, "for column " + col);
+ }
+ }
+
+ /**
+ * Test the 'colour above threshold' case
+ */
+ @Test(groups = "Functional")
+ public void testShadeCalculation_aboveThreshold()
+ {
+ AnnotationColourGradient testee = new AnnotationColourGradient(ann,
+ minColour, maxColour, AnnotationColourGradient.ABOVE_THRESHOLD);
+ for (int col = 0; col < WIDTH; col++)
+ {
+ Color result = testee.shadeCalculation(ann, col);
+ /*
+ * colour is derived regardless of the threshold value
+ * (the renderer will suppress colouring if above/below threshold)
+ */
+ Color expected = new Color(50 + 10 * col, 200 - 10 * col,
+ 150 + 10 * col);
+ assertEquals(result, expected, "for column " + col);
+ }
+
+ /*
+ * now make 6-10 the span of the colour range
+ * (annotation value == column number in this test)
+ */
+ testee.setThresholdIsMinMax(true);
+ for (int col = 0; col < THRESHOLD_FIVE; col++)
+ {
+ /*
+ * colours below the threshold are computed as before
+ */
+ Color expected = new Color(50 + 10 * col, 200 - 10 * col,
+ 150 + 10 * col);
+ Color result = testee.shadeCalculation(ann, col);
+ assertEquals(result, expected, "for column " + col);
+ }
+ for (int col = THRESHOLD_FIVE; col < WIDTH; col++)
+ {
+ /*
+ * colours for values >= threshold are graduated
+ * range is 6-10 so steps of 100/5 = 20
+ */
+ int factor = col - THRESHOLD_FIVE;
+ Color expected = new Color(50 + 20 * factor, 200 - 20 * factor,
+ 150 + 20 * factor);
+ Color result = testee.shadeCalculation(ann, col);
+ assertEquals(result, expected, "for column " + col);
+ }
+ }
+
+ /**
+ * Test the 'colour below threshold' case
+ */
+ @Test(groups = "Functional")
+ public void testShadeCalculation_belowThreshold()
+ {
+ AnnotationColourGradient testee = new AnnotationColourGradient(ann,
+ minColour, maxColour, AnnotationColourGradient.BELOW_THRESHOLD);
+
+ for (int col = 0; col < WIDTH; col++)
+ {
+ Color result = testee.shadeCalculation(ann, col);
+ /*
+ * colour is derived regardless of the threshold value
+ * (the renderer will suppress colouring if above/below threshold)
+ */
+ Color expected = new Color(50 + 10 * col, 200 - 10 * col,
+ 150 + 10 * col);
+ assertEquals(result, expected, "for column " + col);
+ }
+
+ /*
+ * now make 0-5 the span of the colour range
+ * (annotation value == column number in this test)
+ */
+ testee.setThresholdIsMinMax(true);
+ for (int col = THRESHOLD_FIVE + 1; col < WIDTH; col++)
+ {
+ /*
+ * colours above the threshold are computed as before
+ */
+ Color expected = new Color(50 + 10 * col, 200 - 10 * col,
+ 150 + 10 * col);
+ Color result = testee.shadeCalculation(ann, col);
+ assertEquals(result, expected, "for column " + col);
+ }
+
+ for (int col = 0; col <= THRESHOLD_FIVE; col++)
+ {
+ /*
+ * colours for values <= threshold are graduated
+ * range is 0-5 so steps of 100/5 = 20
+ */
+ Color expected = new Color(50 + 20 * col, 200 - 20 * col,
+ 150 + 20 * col);
+ Color result = testee.shadeCalculation(ann, col);
+ assertEquals(result, expected, "for column " + col);
+ }
+ }
+
+ /**
+ * Test the 'colour above threshold' case
+ */
+ @Test(groups = "Functional")
+ public void testFindColour_aboveThreshold()
+ {
+ AnnotationColourGradient testee = new AnnotationColourGradient(ann,
+ minColour, maxColour, AnnotationColourGradient.ABOVE_THRESHOLD);
+ testee = (AnnotationColourGradient) testee.getInstance(al, null);
+
+ for (int col = 0; col < WIDTH; col++)
+ {
+ Color result = testee.findColour('a', col, seq);
+ /*
+ * expect white below threshold of 5
+ */
+ Color expected = col < 5 ? Color.white : new Color(50 + 10 * col,
+ 200 - 10 * col,
+ 150 + 10 * col);
+ assertEquals(result, expected, "for column " + col);
+ }
+
+ /*
+ * now make 6-10 the span of the colour range
+ * (annotation value == column number in this test)
+ */
+ testee.setThresholdIsMinMax(true);
+ for (int col = 0; col < WIDTH; col++)
+ {
+ /*
+ * colours for values >= threshold are graduated
+ * range is 6-10 so steps of 100/5 = 20
+ */
+ int factor = col - THRESHOLD_FIVE;
+ Color expected = col < 5 ? Color.white : new Color(50 + 20 * factor,
+ 200 - 20 * factor,
+ 150 + 20 * factor);
+ Color result = testee.findColour('a', col, seq);
+ assertEquals(result, expected, "for column " + col);
+ }
+ }
+
+ /**
+ * Test the 'colour below threshold' case
+ */
+ @Test(groups = "Functional")
+ public void testFindColour_belowThreshold()
+ {
+ AnnotationColourGradient testee = new AnnotationColourGradient(ann,
+ minColour, maxColour, AnnotationColourGradient.BELOW_THRESHOLD);
+ testee = (AnnotationColourGradient) testee.getInstance(al, null);
+
+ for (int col = 0; col < WIDTH; col++)
+ {
+ Color result = testee.findColour('a', col, seq);
+ Color expected = col > 5 ? Color.white : new Color(50 + 10 * col,
+ 200 - 10 * col, 150 + 10 * col);
+ assertEquals(result, expected, "for column " + col);
+ }
+
+ /*
+ * now make 0-5 the span of the colour range
+ * (annotation value == column number in this test)
+ */
+ testee.setThresholdIsMinMax(true);
+ for (int col = 0; col < WIDTH; col++)
+ {
+ /*
+ * colours for values <= threshold are graduated
+ * range is 0-5 so steps of 100/5 = 20
+ */
+ Color expected = col > 5 ? Color.white : new Color(50 + 20 * col,
+ 200 - 20 * col, 150 + 20 * col);
+ Color result = testee.findColour('a', col, seq);
+ assertEquals(result, expected, "for column " + col);
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testFindColour_noThreshold()
+ {
+ AnnotationColourGradient testee = new AnnotationColourGradient(ann,
+ minColour, maxColour, AnnotationColourGradient.NO_THRESHOLD);
+ testee = (AnnotationColourGradient) testee.getInstance(al, null);
+
+ for (int col = 0; col < WIDTH; col++)
+ {
+ Color result = testee.findColour('a', col, seq);
+ /*
+ * column <n> is n/10 of the way from minCol to maxCol
+ */
+ Color expected = new Color(50 + 10 * col, 200 - 10 * col,
+ 150 + 10 * col);
+ assertEquals(result, expected, "for column " + col);
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testFindColour_originalColours()
+ {
+ AnnotationColourGradient testee = new AnnotationColourGradient(ann,
+ minColour, maxColour, AnnotationColourGradient.NO_THRESHOLD);
+ testee = (AnnotationColourGradient) testee.getInstance(al, null);
+
+ /*
+ * flag corresponding to 'use original colours' checkbox
+ * - just use the individual annotation colours
+ */
+ testee.setPredefinedColours(true);
+
+ /*
+ * the annotation colour is returned, except for column 0 where it is
+ * black - in this case the colour scheme colour overrides it
+ */
+ for (int col = 0; col < WIDTH; col++)
+ {
+ int hue = col * 20;
+ Color c = col == 0 ? minColour : new Color(hue, hue, hue);
+ assertEquals(testee.findColour('a', col, seq), c, "for column " + col);
+ }
+ }
+}
* set and check Taylor colours
*/
af.changeColour_actionPerformed(JalviewColourScheme.Taylor.toString());
- Color taylor1 = sr.getResidueBoxColour(seq, 88); // E 255,0,102
- Color taylor2 = sr.getResidueBoxColour(seq, 89); // A 204,255,0
- Color taylor3 = sr.getResidueBoxColour(seq, 90); // G 255,153,0
+ Color taylor1 = sr.getResidueColour(seq, 88, null); // E 255,0,102
+ Color taylor2 = sr.getResidueColour(seq, 89, null); // A 204,255,0
+ Color taylor3 = sr.getResidueColour(seq, 90, null); // G 255,153,0
assertEquals(taylor1, new Color(255, 0, 102));
assertEquals(taylor2, new Color(204, 255, 0));
assertEquals(taylor3, new Color(255, 153, 0));
* set and check Zappo colours
*/
af.changeColour_actionPerformed(JalviewColourScheme.Zappo.toString());
- Color zappo1 = sr.getResidueBoxColour(seq, 88); // E red
- Color zappo2 = sr.getResidueBoxColour(seq, 89); // A pink
- Color zappo3 = sr.getResidueBoxColour(seq, 90); // G magenta
+ Color zappo1 = sr.getResidueColour(seq, 88, null); // E red
+ Color zappo2 = sr.getResidueColour(seq, 89, null); // A pink
+ Color zappo3 = sr.getResidueColour(seq, 90, null); // G magenta
assertEquals(zappo1, Color.red);
assertEquals(zappo2, Color.pink);
assertEquals(zappo3, Color.magenta);
* set 'stripy' colours - odd columns are Taylor and even are Zappo
*/
af.changeColour_actionPerformed("stripy");
- Color stripy1 = sr.getResidueBoxColour(seq, 88);
- Color stripy2 = sr.getResidueBoxColour(seq, 89);
- Color stripy3 = sr.getResidueBoxColour(seq, 90);
+ Color stripy1 = sr.getResidueColour(seq, 88, null);
+ Color stripy2 = sr.getResidueColour(seq, 89, null);
+ Color stripy3 = sr.getResidueColour(seq, 90, null);
assertEquals(stripy1, zappo1);
assertEquals(stripy2, taylor2);
assertEquals(stripy3, zappo3);
* set and check Clustal colours
*/
af.changeColour_actionPerformed(JalviewColourScheme.Clustal.toString());
- Color clustal1 = sr.getResidueBoxColour(seq, 88);
- Color clustal2 = sr.getResidueBoxColour(seq, 89);
- Color clustal3 = sr.getResidueBoxColour(seq, 90);
+ Color clustal1 = sr.getResidueColour(seq, 88, null);
+ Color clustal2 = sr.getResidueColour(seq, 89, null);
+ Color clustal3 = sr.getResidueColour(seq, 90, null);
assertEquals(clustal1, ClustalColour.MAGENTA.colour);
assertEquals(clustal2, ClustalColour.BLUE.colour);
assertEquals(clustal3, ClustalColour.ORANGE.colour);
* set 'MyClustal' colours - uses AWT colour equivalents
*/
af.changeColour_actionPerformed("MyClustal");
- Color myclustal1 = sr.getResidueBoxColour(seq, 88);
- Color myclustal2 = sr.getResidueBoxColour(seq, 89);
- Color myclustal3 = sr.getResidueBoxColour(seq, 90);
+ Color myclustal1 = sr.getResidueColour(seq, 88, null);
+ Color myclustal2 = sr.getResidueColour(seq, 89, null);
+ Color myclustal3 = sr.getResidueColour(seq, 90, null);
assertEquals(myclustal1, Color.MAGENTA);
assertEquals(myclustal2, Color.BLUE);
assertEquals(myclustal3, Color.ORANGE);
+++ /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.
- */
-package jalview.schemes;
-
-import jalview.api.analysis.ScoreModelI;
-import jalview.gui.JvOptionPane;
-
-import java.util.Map;
-
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-public class ScoreMatrixPrinter
-{
-
- @BeforeClass(alwaysRun = true)
- public void setUpJvOptionPane()
- {
- JvOptionPane.setInteractiveMode(false);
- JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
- }
-
- @Test(groups = { "Functional" })
- public void printAllMatrices()
- {
- for (Map.Entry<String, ScoreModelI> sm : ResidueProperties.scoreMatrices
- .entrySet())
- {
- System.out.println("Matrix " + sm.getKey());
- System.out.println(sm.getValue().toString());
- }
- }
-
- @Test(groups = { "Functional" })
- public void printHTMLMatrices()
- {
- for (Map.Entry<String, ScoreModelI> _sm : ResidueProperties.scoreMatrices
- .entrySet())
- {
- if (_sm.getValue() instanceof ScoreMatrix)
- {
- ScoreMatrix sm = (ScoreMatrix) _sm.getValue();
- System.out.println("Matrix " + _sm.getKey());
- System.out.println(sm.outputMatrix(true));
- }
- }
- }
-
-}
--- /dev/null
+package jalview.structure;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.fail;
+
+import org.testng.annotations.Test;
+
+public class AtomSpecTest
+{
+ @Test
+ public void testFromChimeraAtomSpec()
+ {
+ AtomSpec as = AtomSpec.fromChimeraAtomspec("#1:12.B");
+ assertEquals(as.getModelNumber(), 1);
+ assertEquals(as.getPdbResNum(), 12);
+ assertEquals(as.getChain(), "B");
+ assertNull(as.getPdbFile());
+
+ // no model - default to zero
+ as = AtomSpec.fromChimeraAtomspec(":13.C");
+ assertEquals(as.getModelNumber(), 0);
+ assertEquals(as.getPdbResNum(), 13);
+ assertEquals(as.getChain(), "C");
+ assertNull(as.getPdbFile());
+
+ // model.submodel
+ as = AtomSpec.fromChimeraAtomspec("#3.2:15");
+ assertEquals(as.getModelNumber(), 3);
+ assertEquals(as.getPdbResNum(), 15);
+ assertEquals(as.getChain(), "");
+ assertNull(as.getPdbFile());
+
+ String spec = "3:12.B";
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec);
+ fail("Expected exception for " + spec);
+ } catch (IllegalArgumentException e)
+ {
+ // ok
+ }
+
+ spec = "#3:12-14.B";
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec);
+ fail("Expected exception for " + spec);
+ } catch (IllegalArgumentException e)
+ {
+ // ok
+ }
+
+ spec = "";
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec);
+ fail("Expected exception for " + spec);
+ } catch (IllegalArgumentException e)
+ {
+ // ok
+ }
+
+ spec = null;
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec);
+ fail("Expected exception for " + spec);
+ } catch (NullPointerException e)
+ {
+ // ok
+ }
+ }
+}
--- /dev/null
+package jalview.structure;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+public class StructureMappingTest
+{
+ @Test(groups = "Functional")
+ public void testgetPDBResNumRanges()
+ {
+ HashMap<Integer, int[]> map = new HashMap<Integer, int[]>();
+
+ StructureMapping mapping = new StructureMapping(null, null, null, null,
+ map, null);
+
+ List<int[]> ranges = mapping.getPDBResNumRanges(1, 2);
+ assertTrue(ranges.isEmpty());
+
+ map.put(1, new int[] { 12, 20 }); // 1 maps to 12
+ ranges = mapping.getPDBResNumRanges(2, 3);
+ assertTrue(ranges.isEmpty());
+ ranges = mapping.getPDBResNumRanges(1, 2);
+ assertEquals(ranges.size(), 1);
+ assertEquals(ranges.get(0)[0], 12);
+ assertEquals(ranges.get(0)[1], 12);
+
+ map.put(2, new int[] { 13, 20 }); // 2 maps to 13
+ ranges = mapping.getPDBResNumRanges(1, 2);
+ assertEquals(ranges.size(), 1);
+ assertEquals(ranges.get(0)[0], 12);
+ assertEquals(ranges.get(0)[1], 13);
+
+ map.put(3, new int[] { 15, 20 }); // 3 maps to 15 - break
+ ranges = mapping.getPDBResNumRanges(1, 5);
+ assertEquals(ranges.size(), 2);
+ assertEquals(ranges.get(0)[0], 12);
+ assertEquals(ranges.get(0)[1], 13);
+ assertEquals(ranges.get(1)[0], 15);
+ assertEquals(ranges.get(1)[1], 15);
+ }
+}
import jalview.api.SequenceRenderer;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.PDBEntry.Type;
import jalview.datamodel.Sequence;
import java.awt.Color;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.List;
import org.testng.annotations.BeforeClass;
testee = new AAStructureBindingModel(ssm, pdbFiles, seqs, null)
{
@Override
- public String[] getPdbFile()
+ public String[] getStructureFiles()
{
return new String[] { "INLINE1YCS", "INLINE3A6S", "INLINE1OOT" };
}
}
@Override
- public void superposeStructures(AlignmentI[] als, int[] alm,
- ColumnSelection[] alc)
+ public String superposeStructures(AlignmentI[] als, int[] alm,
+ HiddenColumns[] alc)
{
+ return null;
}
@Override
@Override
protected StructureMappingcommandSet[] getColourBySequenceCommands(
- String[] files, SequenceRenderer sr, FeatureRenderer fr,
- AlignmentI alignment)
- {
- return null;
- }
-
- @Override
- public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
+ String[] files, SequenceRenderer sr, AlignmentViewPanel avp)
{
return null;
}
public void colourByCharge()
{
}
+
+ @Override
+ public FeatureRenderer getFeatureRenderer(
+ AlignmentViewPanel alignment)
+ {
+ return null;
+ }
};
}
/*
* create a data bean to hold data per structure file
*/
- SuperposeData[] structs = new SuperposeData[testee.getPdbFile().length];
+ SuperposeData[] structs = new SuperposeData[testee.getStructureFiles().length];
for (int i = 0; i < structs.length; i++)
{
structs[i] = testee.new SuperposeData(al.getWidth());
}
/*
- * initialise array of 'superposable columns' to true (would be false for
+ * initialise BitSet of 'superposable columns' to true (would be false for
* hidden columns)
*/
- boolean[] matched = new boolean[al.getWidth()];
- Arrays.fill(matched, true);
+ BitSet matched = new BitSet();
+ for (int i = 0; i < al.getWidth(); i++)
+ {
+ matched.set(i);
+ }
int refStructure = testee
.findSuperposableResidues(al, matched, structs);
/*
* only ungapped, structure-mapped columns are superposable
*/
- assertFalse(matched[0]); // gap in first sequence
- assertTrue(matched[1]);
- assertFalse(matched[2]); // gap in third sequence
- assertFalse(matched[3]); // gap in fourth sequence
- assertTrue(matched[4]);
- assertTrue(matched[5]); // gap in second sequence
+ assertFalse(matched.get(0)); // gap in first sequence
+ assertTrue(matched.get(1));
+ assertFalse(matched.get(2)); // gap in third sequence
+ assertFalse(matched.get(3)); // gap in fourth sequence
+ assertTrue(matched.get(4));
+ assertTrue(matched.get(5)); // gap in second sequence
assertEquals("1YCS", structs[0].pdbId);
assertEquals("3A6S", structs[1].pdbId);
structs[i] = testee.new SuperposeData(al.getWidth());
}
/*
- * initialise array of 'superposable columns' to true (would be false for
+ * initialise BitSet of 'superposable columns' to true (would be false for
* hidden columns)
*/
- boolean[] matched = new boolean[al.getWidth()];
- Arrays.fill(matched, true);
+ BitSet matched = new BitSet();
+ for (int i = 0; i < al.getWidth(); i++)
+ {
+ matched.set(i);
+ }
+
// treat column 5 of the alignment as hidden
- matched[4] = false;
+ matched.clear(4);
int refStructure = testee
.findSuperposableResidues(al, matched, structs);
assertEquals(0, refStructure);
// only ungapped, structure-mapped columns are not superposable
- assertFalse(matched[0]);
- assertTrue(matched[1]);
- assertFalse(matched[2]);
- assertFalse(matched[3]);
- assertFalse(matched[4]); // superposable, but hidden, column
- assertTrue(matched[5]);
- }
-
- public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
- {
- return null;
- }
-
- public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment)
- {
- return null;
+ assertFalse(matched.get(0));
+ assertTrue(matched.get(1));
+ assertFalse(matched.get(2));
+ assertFalse(matched.get(3));
+ assertFalse(matched.get(4)); // superposable, but hidden, column
+ assertTrue(matched.get(5));
}
}
u.setValue(UrlLinkDisplay.NAME, "New Desc");
Assert.assertEquals(u.getValue(UrlLinkDisplay.NAME), "New Desc");
+ Assert.assertEquals(u.getValue(UrlLinkDisplay.DATABASE), "New Desc");
u.setValue(UrlLinkDisplay.DATABASE, "NewName");
Assert.assertEquals(u.getValue(UrlLinkDisplay.DATABASE), "NewName");
@Test(groups = { "Functional" })
public void testPID_includingGaps()
{
- String seq1 = "ABCDEF";
+ String seq1 = "ABCDEFG"; // extra length here is ignored
String seq2 = "abcdef";
assertEquals("identical", 100f, Comparison.PID(seq1, seq2), 0.001f);
int length = seq1.length();
// match gap-residue, match gap-gap: 9/10 identical
+ // TODO should gap-gap be included in a PID score? JAL-791
assertEquals(90f, Comparison.PID(seq1, seq2, 0, length, true, false),
0.001f);
// overloaded version of the method signature above:
assertEquals(90f, Comparison.PID(seq1, seq2), 0.001f);
// don't match gap-residue, match gap-gap: 7/10 identical
+ // TODO should gap-gap be included in a PID score?
assertEquals(70f, Comparison.PID(seq1, seq2, 0, length, false, false),
0.001f);
}
public void testPID_ungappedOnly()
{
// 5 identical, 2 gap-gap, 2 gap-residue, 1 mismatch
- String seq1 = "a--b-cdefh";
+ // the extra length of seq1 is ignored
+ String seq1 = "a--b-cdefhr";
String seq2 = "a---bcdefg";
int length = seq1.length();
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SearchResultMatchI;
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.Sequence;
setupMappedAlignments();
ColumnSelection colsel = new ColumnSelection();
+ HiddenColumns hidden = new HiddenColumns();
/*
* Column 0 in protein picks up Seq2/L, Seq3/G which map to cols 0-4 and 0-3
* in dna respectively, overall 0-4
*/
colsel.addElement(0);
- ColumnSelection cs = MappingUtils.mapColumnSelection(colsel,
- proteinView, dnaView);
+ ColumnSelection cs = new ColumnSelection();
+ HiddenColumns hs = new HiddenColumns();
+ MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
+ cs, hs);
assertEquals("[0, 1, 2, 3, 4]", cs.getSelected().toString());
/*
* Column 1 in protein picks up Seq1/K which maps to cols 0-3 in dna
*/
+ cs.clear();
colsel.clear();
colsel.addElement(1);
- cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
+ MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
+ cs, hs);
assertEquals("[0, 1, 2, 3]", cs.getSelected().toString());
/*
* Column 2 in protein picks up gaps only - no mapping
*/
+ cs.clear();
colsel.clear();
colsel.addElement(2);
- cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
+ MappingUtils.mapColumnSelection(colsel, hidden, proteinView,
+ dnaView, cs, hs);
assertEquals("[]", cs.getSelected().toString());
/*
* Column 3 in protein picks up Seq1/P, Seq2/Q, Seq3/S which map to columns
* 6-9, 6-10, 5-8 respectively, overall to 5-10
*/
+ cs.clear();
colsel.clear();
colsel.addElement(3);
- cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
+ MappingUtils.mapColumnSelection(colsel, hidden, proteinView,
+ dnaView, cs, hs);
assertEquals("[5, 6, 7, 8, 9, 10]", cs.getSelected().toString());
/*
* Combine selection of columns 1 and 3 to get a discontiguous mapped
* selection
*/
+ cs.clear();
colsel.clear();
colsel.addElement(1);
colsel.addElement(3);
- cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
+ MappingUtils.mapColumnSelection(colsel, hidden, proteinView,
+ dnaView, cs, hs);
assertEquals("[0, 1, 2, 3, 5, 6, 7, 8, 9, 10]", cs.getSelected()
.toString());
}
setupMappedAlignments();
ColumnSelection colsel = new ColumnSelection();
+ HiddenColumns hidden = new HiddenColumns();
/*
* Column 0 in dna picks up first bases which map to residue 1, columns 0-1
* in protein.
*/
+ ColumnSelection cs = new ColumnSelection();
+ HiddenColumns hs = new HiddenColumns();
colsel.addElement(0);
- ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, dnaView,
- proteinView);
+ MappingUtils.mapColumnSelection(colsel, hidden, dnaView, proteinView,
+ cs, hs);
assertEquals("[0, 1]", cs.getSelected().toString());
/*
colsel.addElement(3);
colsel.addElement(4);
colsel.addElement(5);
- cs = MappingUtils.mapColumnSelection(colsel, dnaView, proteinView);
+ cs.clear();
+ MappingUtils.mapColumnSelection(colsel, hidden, dnaView, proteinView,
+ cs, hs);
assertEquals("[0, 1, 3]", cs.getSelected().toString());
}
public void testMapColumnSelection_null() throws IOException
{
setupMappedAlignments();
- ColumnSelection cs = MappingUtils.mapColumnSelection(null, dnaView,
- proteinView);
+ ColumnSelection cs = new ColumnSelection();
+ HiddenColumns hs = new HiddenColumns();
+ MappingUtils.mapColumnSelection(null, null, dnaView, proteinView, cs,
+ hs);
assertTrue("mapped selection not empty", cs.getSelected().isEmpty());
}
setupMappedAlignments();
ColumnSelection proteinSelection = new ColumnSelection();
+ HiddenColumns hiddenCols = new HiddenColumns();
/*
* Column 0 in protein picks up Seq2/L, Seq3/G which map to cols 0-4 and 0-3
* in dna respectively, overall 0-4
*/
- proteinSelection.hideColumns(0);
- ColumnSelection dnaSelection = MappingUtils.mapColumnSelection(
- proteinSelection, proteinView, dnaView);
+ proteinSelection.hideSelectedColumns(0, hiddenCols);
+ ColumnSelection dnaSelection = new ColumnSelection();
+ HiddenColumns dnaHidden = new HiddenColumns();
+ MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
+ proteinView, dnaView, dnaSelection, dnaHidden);
assertEquals("[]", dnaSelection.getSelected().toString());
- List<int[]> hidden = dnaSelection.getHiddenColumns();
+ List<int[]> hidden = dnaHidden.getHiddenRegions();
assertEquals(1, hidden.size());
assertEquals("[0, 4]", Arrays.toString(hidden.get(0)));
/*
* Column 1 in protein picks up Seq1/K which maps to cols 0-3 in dna
*/
- proteinSelection.revealAllHiddenColumns();
+ dnaSelection = new ColumnSelection();
+ dnaHidden = new HiddenColumns();
+ hiddenCols.revealAllHiddenColumns(proteinSelection);
// the unhidden columns are now marked selected!
assertEquals("[0]", proteinSelection.getSelected().toString());
// deselect these or hideColumns will be expanded to include 0
proteinSelection.clear();
- proteinSelection.hideColumns(1);
- dnaSelection = MappingUtils.mapColumnSelection(proteinSelection,
- proteinView, dnaView);
- hidden = dnaSelection.getHiddenColumns();
+ proteinSelection.hideSelectedColumns(1, hiddenCols);
+ MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
+ proteinView, dnaView, dnaSelection, dnaHidden);
+ hidden = dnaHidden.getHiddenRegions();
assertEquals(1, hidden.size());
assertEquals("[0, 3]", Arrays.toString(hidden.get(0)));
/*
* Column 2 in protein picks up gaps only - no mapping
*/
- proteinSelection.revealAllHiddenColumns();
+ dnaSelection = new ColumnSelection();
+ dnaHidden = new HiddenColumns();
+ hiddenCols.revealAllHiddenColumns(proteinSelection);
proteinSelection.clear();
- proteinSelection.hideColumns(2);
- dnaSelection = MappingUtils.mapColumnSelection(proteinSelection,
- proteinView, dnaView);
- assertTrue(dnaSelection.getHiddenColumns().isEmpty());
+ proteinSelection.hideSelectedColumns(2, hiddenCols);
+ MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
+ proteinView, dnaView, dnaSelection, dnaHidden);
+ assertTrue(dnaHidden.getHiddenRegions().isEmpty());
/*
* Column 3 in protein picks up Seq1/P, Seq2/Q, Seq3/S which map to columns
* 6-9, 6-10, 5-8 respectively, overall to 5-10
*/
- proteinSelection.revealAllHiddenColumns();
+ dnaSelection = new ColumnSelection();
+ dnaHidden = new HiddenColumns();
+ hiddenCols.revealAllHiddenColumns(proteinSelection);
proteinSelection.clear();
- proteinSelection.hideColumns(3); // 5-10 hidden in dna
+ proteinSelection.hideSelectedColumns(3, hiddenCols); // 5-10 hidden in dna
proteinSelection.addElement(1); // 0-3 selected in dna
- dnaSelection = MappingUtils.mapColumnSelection(proteinSelection,
- proteinView, dnaView);
+ MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
+ proteinView, dnaView, dnaSelection, dnaHidden);
assertEquals("[0, 1, 2, 3]", dnaSelection.getSelected().toString());
- hidden = dnaSelection.getHiddenColumns();
+ hidden = dnaHidden.getHiddenRegions();
assertEquals(1, hidden.size());
assertEquals("[5, 10]", Arrays.toString(hidden.get(0)));
/*
* Combine hiding columns 1 and 3 to get discontiguous hidden columns
*/
- proteinSelection.revealAllHiddenColumns();
+ dnaSelection = new ColumnSelection();
+ dnaHidden = new HiddenColumns();
+ hiddenCols.revealAllHiddenColumns(proteinSelection);
proteinSelection.clear();
- proteinSelection.hideColumns(1);
- proteinSelection.hideColumns(3);
- dnaSelection = MappingUtils.mapColumnSelection(proteinSelection,
- proteinView, dnaView);
- hidden = dnaSelection.getHiddenColumns();
+ proteinSelection.hideSelectedColumns(1, hiddenCols);
+ proteinSelection.hideSelectedColumns(3, hiddenCols);
+ MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
+ proteinView, dnaView, dnaSelection, dnaHidden);
+ hidden = dnaHidden.getHiddenRegions();
assertEquals(2, hidden.size());
assertEquals("[0, 3]", Arrays.toString(hidden.get(0)));
assertEquals("[5, 10]", Arrays.toString(hidden.get(1)));
--- /dev/null
+package jalview.util;
+
+import static org.testng.Assert.assertEquals;
+
+import java.awt.Color;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.testng.annotations.Test;
+
+public class SetUtilsTest
+{
+ @Test(groups = "Functional")
+ public void testCountDisjunction()
+ {
+ Set<Color> s1 = new HashSet<Color>();
+ assertEquals(SetUtils.countDisjunction(null, null), 0);
+ assertEquals(SetUtils.countDisjunction(s1, null), 0);
+ assertEquals(SetUtils.countDisjunction(null, s1), 0);
+ s1.add(Color.white);
+ assertEquals(SetUtils.countDisjunction(s1, null), 1);
+ assertEquals(SetUtils.countDisjunction(null, s1), 1);
+ assertEquals(SetUtils.countDisjunction(s1, null), 1);
+ assertEquals(SetUtils.countDisjunction(s1, s1), 0);
+
+ Set<Object> s2 = new HashSet<Object>();
+ assertEquals(SetUtils.countDisjunction(s2, s2), 0);
+ assertEquals(SetUtils.countDisjunction(s1, s2), 1);
+ assertEquals(SetUtils.countDisjunction(s2, s1), 1);
+
+ s1.add(Color.yellow);
+ s1.add(Color.blue);
+ s2.add(new Color(Color.yellow.getRGB()));
+
+ /*
+ * now s1 is {white, yellow, blue}
+ * s2 is {yellow'}
+ */
+ assertEquals(SetUtils.countDisjunction(s1, s2), 2);
+ s2.add(Color.blue);
+ assertEquals(SetUtils.countDisjunction(s1, s2), 1);
+ s2.add(Color.pink);
+ assertEquals(SetUtils.countDisjunction(s1, s2), 2);
+
+ }
+}
--- /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.
+ */
+package jalview.viewmodel;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.analysis.AlignmentGenerator;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceCollectionI;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+
+import java.util.Hashtable;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+@Test(singleThreaded = true)
+public class OverviewDimensionsHideHiddenTest
+{
+ AlignmentI al;
+
+ OverviewDimensionsHideHidden od;
+
+ // cached widths and heights
+ int boxWidth;
+ int boxHeight;
+ int viewHeight;
+ int viewWidth;
+ int alheight;
+ int alwidth;
+
+ ViewportRanges vpranges;
+
+ Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences = new Hashtable<SequenceI, SequenceCollectionI>();
+
+ HiddenColumns hiddenCols = new HiddenColumns();
+
+ @BeforeClass(alwaysRun = true)
+ public void setUpAlignment()
+ {
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ al = gen.generate(157, 525, 123, 5, 5);
+ }
+
+ @BeforeMethod(alwaysRun = true)
+ public void setUp()
+ {
+ if (!hiddenRepSequences.isEmpty())
+ {
+ al.getHiddenSequences().showAll(hiddenRepSequences);
+ }
+ ColumnSelection colsel = new ColumnSelection();
+ hiddenCols.revealAllHiddenColumns(colsel);
+
+ vpranges = new ViewportRanges(al);
+ vpranges.setViewportStartAndHeight(0, 18);
+ vpranges.setViewportStartAndWidth(0, 63);
+
+ viewHeight = vpranges.getEndSeq() - vpranges.getStartSeq() + 1;
+ viewWidth = vpranges.getEndRes() - vpranges.getStartRes() + 1;
+
+ HiddenColumns hiddenCols = new HiddenColumns();
+
+ od = new OverviewDimensionsHideHidden(vpranges, true);
+ // Initial box sizing - default path through code
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+
+ mouseClick(od, 0, 0);
+ moveViewport(0, 0);
+
+ // calculate with visible values
+ alheight = vpranges.getVisibleAlignmentHeight();
+ alwidth = vpranges.getVisibleAlignmentWidth();
+
+ boxWidth = Math.round((float) (vpranges.getEndRes()
+ - vpranges.getStartRes() + 1)
+ * od.getWidth() / alwidth);
+ boxHeight = Math.round((float) (vpranges.getEndSeq()
+ - vpranges.getStartSeq() + 1)
+ * od.getSequencesHeight() / alheight);
+ }
+
+ @AfterClass(alwaysRun = true)
+ public void cleanUp()
+ {
+ al = null;
+ }
+
+ /**
+ * Test that the OverviewDimensions constructor sets width and height
+ * correctly
+ */
+ @Test(groups = { "Functional" })
+ public void testConstructor()
+ {
+ SequenceI seqa = new Sequence("Seq1", "ABC");
+ SequenceI seqb = new Sequence("Seq2", "ABC");
+ SequenceI seqc = new Sequence("Seq3", "ABC");
+ SequenceI seqd = new Sequence("Seq4", "ABC");
+ SequenceI seqe = new Sequence("Seq5",
+ "ABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ int defaultGraphHeight = 20;
+ int maxWidth = 400;
+ int minWidth = 120;
+ int maxSeqHeight = 300;
+ int minSeqHeight = 40;
+
+ // test for alignment with width > height
+ SequenceI[] seqs1 = new SequenceI[] { seqa, seqb };
+ Alignment al1 = new Alignment(seqs1);
+ ViewportRanges props = new ViewportRanges(al1);
+
+ OverviewDimensions od = new OverviewDimensionsHideHidden(props, true);
+ int scaledHeight = 267;
+ assertEquals(od.getGraphHeight(), defaultGraphHeight);
+ assertEquals(od.getSequencesHeight(), scaledHeight);
+ assertEquals(od.getWidth(), maxWidth);
+ assertEquals(od.getHeight(), scaledHeight + defaultGraphHeight);
+
+ // test for alignment with width < height
+ SequenceI[] seqs2 = new SequenceI[] { seqa, seqb, seqc, seqd };
+ Alignment al2 = new Alignment(seqs2);
+ props = new ViewportRanges(al2);
+
+ od = new OverviewDimensionsHideHidden(props, true);
+ int scaledWidth = 300;
+ assertEquals(od.getGraphHeight(), defaultGraphHeight);
+ assertEquals(od.getSequencesHeight(), maxSeqHeight);
+ assertEquals(od.getWidth(), scaledWidth);
+ assertEquals(od.getHeight(), scaledWidth + defaultGraphHeight);
+
+ // test for alignment with width > height and sequence height scaled below
+ // min value
+ SequenceI[] seqs3 = new SequenceI[] { seqe };
+ Alignment al3 = new Alignment(seqs3);
+ props = new ViewportRanges(al3);
+
+ od = new OverviewDimensionsHideHidden(props, true);
+ assertEquals(od.getGraphHeight(), defaultGraphHeight);
+ assertEquals(od.getSequencesHeight(), minSeqHeight);
+ assertEquals(od.getWidth(), maxWidth);
+ assertEquals(od.getHeight(), minSeqHeight + defaultGraphHeight);
+
+ // test for alignment with width < height and width scaled below min value
+ SequenceI[] seqs4 = new SequenceI[] { seqa, seqb, seqc, seqd, seqa,
+ seqb, seqc, seqd, seqa, seqb, seqc, seqd, seqa, seqb, seqc, seqd };
+ Alignment al4 = new Alignment(seqs4);
+ props = new ViewportRanges(al4);
+
+ od = new OverviewDimensionsHideHidden(props, true);
+ assertEquals(od.getGraphHeight(), defaultGraphHeight);
+ assertEquals(od.getSequencesHeight(), maxSeqHeight);
+ assertEquals(od.getWidth(), minWidth);
+ assertEquals(od.getHeight(), maxSeqHeight + defaultGraphHeight);
+
+ Alignment al5 = new Alignment(seqs4);
+ props = new ViewportRanges(al5);
+
+ od = new OverviewDimensionsHideHidden(props, false);
+ assertEquals(od.getGraphHeight(), 0);
+ assertEquals(od.getSequencesHeight(), maxSeqHeight);
+ assertEquals(od.getWidth(), minWidth);
+ assertEquals(od.getHeight(), maxSeqHeight);
+ }
+
+ /**
+ * Test that validation after mouse adjustments to boxX and boxY sets box
+ * dimensions and scroll values correctly, when there are no hidden rows or
+ * columns.
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromMouseClick()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // negative boxX value reset to 0
+ mouseClick(od, -5, 10);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartSeq(),
+ Math.round((float) 10 * alheight / od.getSequencesHeight()));
+ assertEquals(vpranges.getStartRes(), 0);
+
+ // negative boxY value reset to 0
+ mouseClick(od, 6, -2);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) 6 * alwidth / od.getWidth()));
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // overly large boxX value reset to width-boxWidth
+ mouseClick(od, 100, 6);
+ assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+ assertEquals(od.getBoxY(), 6);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(
+ vpranges.getStartSeq(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()));
+
+ // overly large boxY value reset to sequenceHeight - boxHeight
+ mouseClick(od, 10, 520);
+ assertEquals(od.getBoxX(), 10);
+ assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight());
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+
+ // here (float) od.getBoxY() * alheight / od.getSequencesHeight() = 507.5
+ // and round rounds to 508; however we get 507 working with row values
+ // hence the subtraction of 1
+ assertEquals(
+ vpranges.getStartSeq(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()) - 1);
+
+ // click past end of alignment, as above
+ mouseClick(od, 3000, 5);
+ assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(
+ vpranges.getStartSeq(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()));
+
+ // move viewport so startRes non-zero and then mouseclick
+ moveViewportH(50);
+
+ // click at viewport position
+ int oldboxx = od.getBoxX();
+ int oldboxy = od.getBoxY();
+ mouseClick(od, od.getBoxX() + 5, od.getBoxY() + 2);
+ assertEquals(od.getBoxX(), oldboxx + 5);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(od.getBoxY(), oldboxy + 2);
+ assertEquals(
+ vpranges.getStartSeq(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()));
+
+ // click at top corner
+ mouseClick(od, 0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden cols at the start
+ * of the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenColsAtStart()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // hide cols at start and check updated box position is correct
+ int lastHiddenCol = 30;
+ hiddenCols.hideColumns(0, lastHiddenCol);
+
+ testBoxIsAtClickPoint(0, 0);
+
+ // click to right of hidden columns, box moves to click point
+ testBoxIsAtClickPoint(40, 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) 40 * alwidth / od.getWidth()));
+
+ // click to right of hidden columns such that box runs over right hand side
+ // of alignment
+ // box position is adjusted away from the edge
+ // overly large boxX value reset to width-boxWidth
+ int xpos = 100;
+ mouseClick(od, xpos, 0);
+ assertEquals(od.getBoxX(), Math.round(od.getWidth()) - boxWidth);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(vpranges.getStartSeq(), 0);
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden cols in the middle
+ * of the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenColsInMiddle()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+ testBoxIsAtClickPoint(0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // hide columns 63-73, no change to box position or dimensions
+ int firstHidden = 63;
+ int lastHidden = 73;
+ hiddenCols.hideColumns(firstHidden, lastHidden);
+
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ testBoxIsAtClickPoint(0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // move box so that it overlaps with hidden cols on one side
+ // box width, boxX and scrollCol as for unhidden case
+ int xpos = 55 - boxWidth; // 55 is position in overview approx halfway
+ // between cols 60 and 70
+ mouseClick(od, xpos, 0);
+ testBoxIsAtClickPoint(xpos, 0);
+ assertEquals(vpranges.getStartRes(),
+ Math.round(xpos * alwidth / od.getWidth()));
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // move box so that it completely covers hidden cols
+ // box width, boxX and scrollCol as for unhidden case
+ xpos = 33;
+ mouseClick(od, xpos, 0);
+ testBoxIsAtClickPoint(xpos, 0);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) xpos * alwidth / od.getWidth()));
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // move box so boxX is in hidden cols, box overhangs at right
+ // boxX and scrollCol at left of hidden area, box width unchanged
+ xpos = 50;
+ mouseClick(od, xpos, 0);
+ testBoxIsAtClickPoint(xpos, 0);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) xpos * alwidth / od.getWidth()));
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // move box so boxX is to right of hidden cols, but does not go beyond full
+ // width of alignment
+ // box width, boxX and scrollCol all as for non-hidden case
+ xpos = 75;
+ testBoxIsAtClickPoint(xpos, 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+ assertEquals(vpranges.getStartRes(),
+ Math.round(xpos * alwidth / od.getWidth()));
+
+ // move box so it goes beyond full width of alignment
+ // boxX, scrollCol adjusted back, box width normal
+ xpos = 3000;
+ mouseClick(od, xpos, 0);
+ assertEquals(od.getBoxX(), Math.round(od.getWidth()) - boxWidth);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden cols at the end of
+ * the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenColsAtEnd()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // hide columns 140-164, no change to box position or dimensions
+ int firstHidden = 140;
+ int lastHidden = 164;
+ hiddenCols.hideColumns(firstHidden, lastHidden);
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // click to left of hidden cols, without overlapping
+ // boxX, scrollCol and width as normal
+ int xpos = 5;
+ testBoxIsAtClickPoint(xpos, 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) xpos * alwidth / od.getWidth()));
+
+ // click to left of hidden cols, with overlap
+ // boxX and scrollCol adjusted for hidden cols, width normal
+ xpos = Math.round((float) 145 * od.getWidth() / alwidth) - boxWidth;
+ mouseClick(od, xpos, 0);
+ testBoxIsAtClickPoint(xpos, 0);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) xpos * alwidth / od.getWidth()));
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // click off end of alignment
+ // boxX and scrollCol adjusted backwards, width normal
+ xpos = 3000;
+ mouseClick(od, xpos, 0);
+ assertEquals(od.getBoxX(), Math.round(od.getWidth()) - boxWidth);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(vpranges.getStartSeq(), 0);
+ }
+
+ /**
+ * Test that the box position is set correctly when set from the viewport,
+ * with no hidden rows or columns
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewport()
+ {
+ // move viewport to start of alignment
+ moveViewport(0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to right
+ moveViewportH(70);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 70 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport down
+ moveViewportV(100);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 70 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(),
+ Math.round(100 * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to bottom right
+ moveViewport(98, 508);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 98 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(),
+ Math.round((float) 508 * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden columns
+ * at the start
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenColsAtStart()
+ {
+ int firstHidden = 0;
+ int lastHidden = 20;
+ hiddenCols.hideColumns(firstHidden, lastHidden);
+
+ // move viewport to start of alignment
+ moveViewport(0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to end of alignment - need to make startRes by removing
+ // hidden cols because of how viewport/overview are implemented
+ moveViewport(98 - lastHidden - 1, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) (98 - lastHidden - 1) * od.getWidth()
+ / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden columns
+ * in the middle
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenColsInMiddle()
+ {
+ int firstHidden = 68;
+ int lastHidden = 78;
+ hiddenCols.hideColumns(firstHidden, lastHidden);
+
+ // move viewport before hidden columns
+ moveViewport(3, 0);
+
+ assertEquals(od.getBoxX(),
+ Math.round((float) 3 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to left of hidden columns with overlap
+ moveViewport(10, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 10 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to straddle hidden columns
+ moveViewport(63, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 63 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to right of hidden columns, no overlap
+ moveViewport(80 - (lastHidden - firstHidden + 1), 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) (80 - (lastHidden - firstHidden + 1))
+ * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden columns
+ * at the end
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenColsAtEnd()
+ {
+ int firstHidden = 152;
+ int lastHidden = 164;
+ hiddenCols.hideColumns(firstHidden, lastHidden);
+
+ // move viewport before hidden columns
+ moveViewport(3, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 3 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to hidden columns
+ // viewport can't actually extend into hidden cols,
+ // so move to the far right edge of the viewport
+ moveViewport(firstHidden - viewWidth, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) (firstHidden - viewWidth)
+ * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden rows at
+ * the start
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenRowsAtStart()
+ {
+ int firstHidden = 0;
+ int lastHidden = 20;
+ hideSequences(firstHidden, lastHidden);
+
+ // calculate with visible values
+ alheight = vpranges.getVisibleAlignmentHeight();
+ alwidth = vpranges.getVisibleAlignmentWidth();
+
+ boxWidth = Math.round((float) (vpranges.getEndRes()
+ - vpranges.getStartRes() + 1)
+ * od.getWidth() / alwidth);
+ boxHeight = Math.round((float) (vpranges.getEndSeq()
+ - vpranges.getStartSeq() + 1)
+ * od.getSequencesHeight() / alheight);
+
+ // move viewport to start of alignment:
+ // box moves to below hidden rows, height remains same
+ moveViewport(0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to end of alignment
+ moveViewport(0, 525 - viewHeight - lastHidden - 1);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(
+ od.getBoxY(),
+ Math.round((float) (525 - viewHeight - lastHidden - 1)
+ * od.getSequencesHeight()
+ / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden rows in
+ * the middle
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenRowsInMiddle()
+ {
+ int firstHidden = 200;
+ int lastHidden = 210;
+ hideSequences(firstHidden, lastHidden);
+
+ // calculate with visible values
+ alheight = vpranges.getVisibleAlignmentHeight();
+ alwidth = vpranges.getVisibleAlignmentWidth();
+
+ boxWidth = Math.round((float) (vpranges.getEndRes()
+ - vpranges.getStartRes() + 1)
+ * od.getWidth() / alwidth);
+ boxHeight = Math.round((float) (vpranges.getEndSeq()
+ - vpranges.getStartSeq() + 1)
+ * od.getSequencesHeight() / alheight);
+
+ // move viewport to start of alignment:
+ // box, height etc as in non-hidden case
+ moveViewport(0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to straddle hidden rows
+ moveViewport(0, 198);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), Math.round ((float)198 * od.getSequencesHeight()
+ / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden rows at
+ * the bottom
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenRowsAtEnd()
+ {
+ int firstHidden = 500;
+ int lastHidden = 524;
+ hideSequences(firstHidden, lastHidden);
+
+ // calculate with visible values
+ alheight = vpranges.getVisibleAlignmentHeight();
+ alwidth = vpranges.getVisibleAlignmentWidth();
+
+ boxWidth = Math.round((float) (vpranges.getEndRes()
+ - vpranges.getStartRes() + 1)
+ * od.getWidth() / alwidth);
+ boxHeight = Math.round((float) (vpranges.getEndSeq()
+ - vpranges.getStartSeq() + 1)
+ * od.getSequencesHeight() / alheight);
+
+ // move viewport to start of alignment:
+ // box, height etc as in non-hidden case
+ moveViewport(0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to end of alignment
+ // viewport sits above hidden rows and does not include them
+ moveViewport(0, firstHidden - viewHeight - 1);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(
+ od.getBoxY(),
+ Math.round((float) (firstHidden - viewHeight - 1)
+ * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden rows at the start
+ * of the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenRowsAtStart()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // hide rows at start and check updated box position is correct
+ int lastHiddenRow = 30;
+ hideSequences(0, lastHiddenRow);
+
+ // calculate with visible values
+ alheight = vpranges.getVisibleAlignmentHeight();
+ alwidth = vpranges.getVisibleAlignmentWidth();
+
+ boxWidth = Math.round((float) (vpranges.getEndRes()
+ - vpranges.getStartRes() + 1)
+ * od.getWidth() / alwidth);
+ boxHeight = Math.round((float) (vpranges.getEndSeq()
+ - vpranges.getStartSeq() + 1)
+ * od.getSequencesHeight() / alheight);
+
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click below hidden rows
+ mouseClick(od, 0, 150);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 150);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden rows at the middle
+ * of the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenRowsInMiddle()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // hide rows in middle and check updated box position is correct
+ // no changes
+ int firstHiddenRow = 50;
+ int lastHiddenRow = 54;
+ hideSequences(firstHiddenRow, lastHiddenRow);
+
+ // calculate with visible values
+ alheight = vpranges.getVisibleAlignmentHeight();
+ alwidth = vpranges.getVisibleAlignmentWidth();
+
+ boxWidth = Math.round((float) (vpranges.getEndRes()
+ - vpranges.getStartRes() + 1)
+ * od.getWidth() / alwidth);
+ boxHeight = Math.round((float) (vpranges.getEndSeq()
+ - vpranges.getStartSeq() + 1)
+ * od.getSequencesHeight() / alheight);
+
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click above hidden rows, so that box overlaps
+ int ypos = 35; // column value in residues
+ mouseClick(od, 0,
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(),
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click so that box straddles hidden rows
+ ypos = 44; // column value in residues
+ mouseClick(od, 0,
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(),
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden rows at the end of
+ * the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenRowsAtEnd()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // hide rows at end and check updated box position is correct
+ // no changes
+ int firstHidden = 500;
+ int lastHidden = 524;
+ hideSequences(firstHidden, lastHidden);
+
+ // calculate with visible values
+ alheight = vpranges.getVisibleAlignmentHeight();
+ alwidth = vpranges.getVisibleAlignmentWidth();
+
+ boxWidth = Math.round((float) (vpranges.getEndRes()
+ - vpranges.getStartRes() + 1)
+ * od.getWidth() / alwidth);
+ boxHeight = Math.round((float) (vpranges.getEndSeq()
+ - vpranges.getStartSeq() + 1)
+ * od.getSequencesHeight() / alheight);
+
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click above hidden rows
+ int ypos = 40; // row 40
+ mouseClick(od, 0,
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(),
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click above hidden rows so box overlaps
+ // boxY, boxHeight remains same
+ ypos = 497; // row 497
+ mouseClick(od, 0,
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(
+ od.getBoxY(),
+ Math.round((float) firstHidden * od.getSequencesHeight()
+ / alheight)
+ - boxHeight);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /*
+ * Move viewport horizontally: startRes + previous width gives new horizontal extent. Vertical extent stays the same.
+ */
+ private void moveViewportH(int startRes)
+ {
+ vpranges.setViewportStartAndWidth(startRes, viewWidth);
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ }
+
+ /*
+ * Move viewport vertically: startSeq and endSeq give new vertical extent. Horizontal extent stays the same.
+ */
+ private void moveViewportV(int startSeq)
+ {
+ vpranges.setViewportStartAndHeight(startSeq, viewHeight);
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ }
+
+ /*
+ * Move viewport horizontally and vertically.
+ */
+ private void moveViewport(int startRes, int startSeq)
+ {
+ vpranges.setViewportStartAndWidth(startRes, viewWidth);
+ vpranges.setViewportStartAndHeight(startSeq, viewHeight);
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ }
+
+ /*
+ * Mouse click as position x,y in overview window
+ */
+ private void mouseClick(OverviewDimensions od, int x, int y)
+ {
+ od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols);
+
+ // updates require an OverviewPanel to exist which it doesn't here
+ // so call setBoxPosition() as it would be called by the AlignmentPanel
+ // normally
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ }
+
+ /*
+ * Test that the box is positioned with the top left corner at xpos, ypos
+ * and with the original width and height
+ */
+ private void testBoxIsAtClickPoint(int xpos, int ypos)
+ {
+ mouseClick(od, xpos, ypos);
+ assertEquals(od.getBoxX(), xpos);
+ assertEquals(od.getBoxY(), ypos);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ }
+
+ /*
+ * Hide sequences between start and end
+ */
+ private void hideSequences(int start, int end)
+ {
+ SequenceI[] allseqs = al.getSequencesArray();
+ SequenceGroup theseSeqs = new SequenceGroup();
+
+ for (int i = start; i <= end; i++)
+ {
+ theseSeqs.addSequence(allseqs[i], false);
+ al.getHiddenSequences().hideSequence(allseqs[i]);
+ }
+
+ hiddenRepSequences.put(allseqs[start], theseSeqs);
+ }
+}
--- /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.
+ */
+package jalview.viewmodel;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.analysis.AlignmentGenerator;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceCollectionI;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+
+import java.util.Hashtable;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+@Test(singleThreaded = true)
+public class OverviewDimensionsShowHiddenTest
+{
+ AlignmentI al;
+ OverviewDimensionsShowHidden od;
+
+ // cached widths and heights
+ int boxWidth;
+ int boxHeight;
+ int viewHeight;
+ int viewWidth;
+ int alheight;
+ int alwidth;
+
+ ViewportRanges vpranges;
+
+ Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences = new Hashtable<SequenceI, SequenceCollectionI>();
+
+ HiddenColumns hiddenCols = new HiddenColumns();
+
+ @BeforeClass(alwaysRun = true)
+ public void setUpAlignment()
+ {
+ // create random alignment
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+ al = gen.generate(157, 525, 123, 5, 5);
+ }
+
+ @BeforeMethod(alwaysRun = true)
+ public void setUp()
+ {
+ if (!hiddenRepSequences.isEmpty())
+ {
+ al.getHiddenSequences().showAll(hiddenRepSequences);
+ }
+ ColumnSelection colsel = new ColumnSelection();
+ hiddenCols.revealAllHiddenColumns(colsel);
+
+ vpranges = new ViewportRanges(al);
+ vpranges.setViewportStartAndHeight(0, 18);
+ vpranges.setViewportStartAndWidth(0, 63);
+
+ viewHeight = vpranges.getEndSeq() - vpranges.getStartSeq() + 1;
+ viewWidth = vpranges.getEndRes() - vpranges.getStartRes() + 1;
+
+ HiddenColumns hiddenCols = new HiddenColumns();
+
+ od = new OverviewDimensionsShowHidden(vpranges, true);
+ // Initial box sizing - default path through code
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+
+ mouseClick(od, 0, 0);
+ moveViewport(0, 0);
+
+ // calculate before hidden columns so we get absolute values
+ alheight = vpranges.getAbsoluteAlignmentHeight();
+ alwidth = vpranges.getAbsoluteAlignmentWidth();
+
+ boxWidth = Math.round((float) (vpranges.getEndRes()
+ - vpranges.getStartRes() + 1)
+ * od.getWidth() / alwidth);
+ boxHeight = Math.round((float) (vpranges.getEndSeq()
+ - vpranges.getStartSeq() + 1)
+ * od.getSequencesHeight() / alheight);
+ }
+
+ @AfterClass(alwaysRun = true)
+ public void cleanUp()
+ {
+ al = null;
+ }
+
+ /**
+ * Test that the OverviewDimensions constructor sets width and height
+ * correctly
+ */
+ @Test(groups = { "Functional" })
+ public void testConstructor()
+ {
+ SequenceI seqa = new Sequence("Seq1", "ABC");
+ SequenceI seqb = new Sequence("Seq2", "ABC");
+ SequenceI seqc = new Sequence("Seq3", "ABC");
+ SequenceI seqd = new Sequence("Seq4", "ABC");
+ SequenceI seqe = new Sequence("Seq5",
+ "ABCABCABCABCABCABCABCABCBACBACBACBAC");
+
+ int defaultGraphHeight = 20;
+ int maxWidth = 400;
+ int minWidth = 120;
+ int maxSeqHeight = 300;
+ int minSeqHeight = 40;
+
+ // test for alignment with width > height
+ SequenceI[] seqs1 = new SequenceI[] { seqa, seqb };
+ Alignment al1 = new Alignment(seqs1);
+ ViewportRanges props = new ViewportRanges(al1);
+
+ OverviewDimensions od = new OverviewDimensionsShowHidden(props, true);
+ int scaledHeight = 267;
+ assertEquals(od.getGraphHeight(), defaultGraphHeight);
+ assertEquals(od.getSequencesHeight(), scaledHeight);
+ assertEquals(od.getWidth(), maxWidth);
+ assertEquals(od.getHeight(), scaledHeight + defaultGraphHeight);
+
+ // test for alignment with width < height
+ SequenceI[] seqs2 = new SequenceI[] { seqa, seqb, seqc, seqd };
+ Alignment al2 = new Alignment(seqs2);
+ props = new ViewportRanges(al2);
+
+ od = new OverviewDimensionsShowHidden(props, true);
+ int scaledWidth = 300;
+ assertEquals(od.getGraphHeight(), defaultGraphHeight);
+ assertEquals(od.getSequencesHeight(), maxSeqHeight);
+ assertEquals(od.getWidth(), scaledWidth);
+ assertEquals(od.getHeight(), scaledWidth + defaultGraphHeight);
+
+ // test for alignment with width > height and sequence height scaled below
+ // min value
+ SequenceI[] seqs3 = new SequenceI[] { seqe };
+ Alignment al3 = new Alignment(seqs3);
+ props = new ViewportRanges(al3);
+
+ od = new OverviewDimensionsShowHidden(props, true);
+ assertEquals(od.getGraphHeight(), defaultGraphHeight);
+ assertEquals(od.getSequencesHeight(), minSeqHeight);
+ assertEquals(od.getWidth(), maxWidth);
+ assertEquals(od.getHeight(), minSeqHeight + defaultGraphHeight);
+
+ // test for alignment with width < height and width scaled below min value
+ SequenceI[] seqs4 = new SequenceI[] { seqa, seqb, seqc, seqd, seqa,
+ seqb, seqc, seqd, seqa, seqb, seqc, seqd, seqa, seqb, seqc, seqd };
+ Alignment al4 = new Alignment(seqs4);
+ props = new ViewportRanges(al4);
+
+ od = new OverviewDimensionsShowHidden(props, true);
+ assertEquals(od.getGraphHeight(), defaultGraphHeight);
+ assertEquals(od.getSequencesHeight(), maxSeqHeight);
+ assertEquals(od.getWidth(), minWidth);
+ assertEquals(od.getHeight(), maxSeqHeight + defaultGraphHeight);
+
+ Alignment al5 = new Alignment(seqs4);
+ props = new ViewportRanges(al5);
+
+ od = new OverviewDimensionsShowHidden(props, false);
+ assertEquals(od.getGraphHeight(), 0);
+ assertEquals(od.getSequencesHeight(), maxSeqHeight);
+ assertEquals(od.getWidth(), minWidth);
+ assertEquals(od.getHeight(), maxSeqHeight);
+ }
+
+ /**
+ * Test that validation after mouse adjustments to boxX and boxY sets box
+ * dimensions and scroll values correctly, when there are no hidden rows or
+ * columns.
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromMouseClick()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // negative boxX value reset to 0
+ mouseClick(od, -5, 10);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartSeq(),
+ Math.round((float) 10 * alheight / od.getSequencesHeight()));
+ assertEquals(vpranges.getStartRes(), 0);
+
+ // negative boxY value reset to 0
+ mouseClick(od, 6, -2);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) 6 * alwidth / od.getWidth()));
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // overly large boxX value reset to width-boxWidth
+ mouseClick(od, 100, 6);
+ assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+ assertEquals(od.getBoxY(), 6);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(
+ vpranges.getStartSeq(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()));
+
+ // overly large boxY value reset to sequenceHeight - boxHeight
+ mouseClick(od, 10, 520);
+ assertEquals(od.getBoxX(), 10);
+ assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight());
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+
+ // here (float) od.getBoxY() * alheight / od.getSequencesHeight() = 507.5
+ // and round rounds to 508; however we get 507 working with row values
+ // hence the subtraction of 1
+ assertEquals(
+ vpranges.getStartSeq(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()) - 1);
+
+ // click past end of alignment, as above
+ mouseClick(od, 3000, 5);
+ assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(
+ vpranges.getStartSeq(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()));
+
+ // move viewport so startRes non-zero and then mouseclick
+ moveViewportH(50);
+
+ // click at viewport position
+ int oldboxx = od.getBoxX();
+ int oldboxy = od.getBoxY();
+ mouseClick(od, od.getBoxX() + 5, od.getBoxY() + 2);
+ assertEquals(od.getBoxX(), oldboxx + 5);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(od.getBoxY(), oldboxy + 2);
+ assertEquals(
+ vpranges.getStartSeq(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()));
+
+ // click at top corner
+ mouseClick(od, 0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden cols at the start
+ * of the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenColsAtStart()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // hide cols at start and check updated box position is correct
+ // changes boxX but not boxwidth
+ int lastHiddenCol = 30;
+ hiddenCols.hideColumns(0, lastHiddenCol);
+
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(),
+ Math.round((float) (lastHiddenCol + 1) * od.getWidth()
+ / alwidth));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // try to click in hidden cols, check box does not move
+ int xpos = 10;
+ mouseClick(od, xpos, 0);
+ assertEquals(
+ od.getBoxX(),
+ Math.round((float) (lastHiddenCol + 1) * od.getWidth()
+ / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartSeq(), 0);
+ assertEquals(vpranges.getStartRes(), 0);
+
+ // click to right of hidden columns, box moves to click point
+ testBoxIsAtClickPoint(40, 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) 40 * alwidth / od.getWidth())
+ - (lastHiddenCol + 1));
+
+ // click to right of hidden columns such that box runs over right hand side
+ // of alignment
+ // box position is adjusted away from the edge
+ // overly large boxX value reset to width-boxWidth
+ xpos = 100;
+ mouseClick(od, xpos, 5);
+ assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+ assertEquals(od.getBoxY(), 5);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth())
+ - (lastHiddenCol + 1));
+ assertEquals(
+ vpranges.getStartSeq(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()));
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden cols in the middle
+ * of the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenColsInMiddle()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // hide columns 63-73, no change to box position or dimensions
+ int firstHidden = 63;
+ int lastHidden = 73;
+ hiddenCols.hideColumns(firstHidden, lastHidden);
+
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // move box so that it overlaps with hidden cols on one side
+ // box width changes, boxX and scrollCol as for unhidden case
+ int xpos = 55 - boxWidth; // 55 is position in overview approx halfway
+ // between cols 60 and 70
+ mouseClick(od, xpos, 0);
+ assertEquals(od.getBoxX(), xpos);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(
+ od.getBoxWidth(),
+ Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
+ * od.getWidth() / alwidth));
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round(xpos * alwidth / od.getWidth()));
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // move box so that it completely covers hidden cols
+ // box width changes, boxX and scrollCol as for hidden case
+ xpos = 33;
+ mouseClick(od, xpos, 0);
+ assertEquals(od.getBoxX(), xpos);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(
+ od.getBoxWidth(),
+ Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
+ * od.getWidth() / alwidth));
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) xpos * alwidth / od.getWidth()));
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // move box so boxX is in hidden cols, box overhangs at right
+ // boxX and scrollCol at left of hidden area, box width extends across
+ // hidden region
+ xpos = 50;
+ mouseClick(od, xpos, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(
+ od.getBoxWidth(),
+ boxWidth
+ + Math.round((float) (lastHidden - firstHidden + 1)
+ * od.getWidth() / alwidth));
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(), firstHidden - 1);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // move box so boxX is to right of hidden cols, but does not go beyond full
+ // width of alignment
+ // box width, boxX and scrollCol all as for non-hidden case
+ xpos = 75;
+ testBoxIsAtClickPoint(xpos, 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+ assertEquals(vpranges.getStartRes(),
+ Math.round(xpos * alwidth / od.getWidth())
+ - (lastHidden - firstHidden + 1));
+
+ // move box so it goes beyond full width of alignment
+ // boxX, scrollCol adjusted back, box width normal
+ xpos = 3000;
+ mouseClick(od, xpos, 5);
+ assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
+ assertEquals(od.getBoxY(), 5);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(
+ vpranges.getStartRes(),
+ Math.round(((float) od.getBoxX() * alwidth / od.getWidth())
+ - (lastHidden - firstHidden + 1)));
+ assertEquals(
+ vpranges.getStartSeq(),
+ Math.round((float) od.getBoxY() * alheight
+ / od.getSequencesHeight()));
+
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden cols at the end of
+ * the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenColsAtEnd()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // hide columns 140-164, no change to box position or dimensions
+ int firstHidden = 140;
+ int lastHidden = 164;
+ hiddenCols.hideColumns(firstHidden, lastHidden);
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // click to left of hidden cols, without overlapping
+ // boxX, scrollCol and width as normal
+ int xpos = 5;
+ testBoxIsAtClickPoint(xpos, 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) xpos * alwidth / od.getWidth()));
+
+ // click to left of hidden cols, with overlap
+ // boxX and scrollCol adjusted for hidden cols, width normal
+ xpos = Math.round((float) 145 * od.getWidth() / alwidth) - boxWidth;
+ mouseClick(od, xpos, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)
+ - boxWidth + 1);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // click in hidden cols
+ // boxX and scrollCol adjusted for hidden cols, width normal
+ xpos = 115;
+ assertEquals(od.getBoxX(),
+ Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)
+ - boxWidth + 1);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // click off end of alignment
+ // boxX and scrollCol adjusted for hidden cols, width normal
+ xpos = 3000;
+ assertEquals(od.getBoxX(),
+ Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)
+ - boxWidth + 1);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(),
+ Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
+ assertEquals(vpranges.getStartSeq(), 0);
+ }
+
+ /**
+ * Test that the box position is set correctly when set from the viewport,
+ * with no hidden rows or columns
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewport()
+ {
+ // move viewport to start of alignment
+ moveViewport(0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to right
+ moveViewportH(70);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 70 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport down
+ moveViewportV(100);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 70 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(),
+ Math.round(100 * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to bottom right
+ moveViewport(98, 508);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 98 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(),
+ Math.round((float) 508 * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden columns
+ * at the start
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenColsAtStart()
+ {
+ int firstHidden = 0;
+ int lastHidden = 20;
+ hiddenCols.hideColumns(firstHidden, lastHidden);
+
+ // move viewport to start of alignment
+ moveViewport(0, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) (lastHidden + 1) * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to end of alignment - need to make startRes by removing
+ // hidden cols because of how viewport/overview are implemented
+ moveViewport(98 - lastHidden - 1, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 98 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden columns
+ * in the middle
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenColsInMiddle()
+ {
+ int firstHidden = 68;
+ int lastHidden = 78;
+ hiddenCols.hideColumns(firstHidden, lastHidden);
+
+ // move viewport before hidden columns
+ moveViewport(3, 0);
+
+ assertEquals(od.getBoxX(),
+ Math.round((float) 3 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to left of hidden columns with overlap
+ moveViewport(10, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 10 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(
+ od.getBoxWidth(),
+ boxWidth
+ + Math.round((float) (lastHidden - firstHidden + 1)
+ * od.getWidth() / alwidth));
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to straddle hidden columns
+ moveViewport(63, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 63 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(
+ od.getBoxWidth(),
+ boxWidth
+ + Math.round((lastHidden - firstHidden + 1)
+ * od.getWidth() / alwidth));
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to right of hidden columns, no overlap
+ moveViewport(80 - (lastHidden - firstHidden + 1), 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 80 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden columns
+ * at the end
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenColsAtEnd()
+ {
+ int firstHidden = 152;
+ int lastHidden = 164;
+ hiddenCols.hideColumns(firstHidden, lastHidden);
+
+ // move viewport before hidden columns
+ moveViewport(3, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) 3 * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to hidden columns
+ // viewport can't actually extend into hidden cols,
+ // so move to the far right edge of the viewport
+ moveViewport(firstHidden - viewWidth, 0);
+ assertEquals(od.getBoxX(),
+ Math.round((float) (firstHidden - viewWidth)
+ * od.getWidth() / alwidth));
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden rows at
+ * the start
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenRowsAtStart()
+ {
+ int firstHidden = 0;
+ int lastHidden = 20;
+ hideSequences(firstHidden, lastHidden);
+
+ // move viewport to start of alignment:
+ // box moves to below hidden rows, height remains same
+ moveViewport(0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(),
+ Math.round((float) (lastHidden + 1) * od.getSequencesHeight()
+ / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to end of alignment
+ moveViewport(0, 525 - viewHeight - lastHidden - 1);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(
+ od.getBoxY(),
+ Math.round((float) (525 - viewHeight) * od.getSequencesHeight()
+ / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden rows in
+ * the middle
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenRowsInMiddle()
+ {
+ int firstHidden = 200;
+ int lastHidden = 210;
+ hideSequences(firstHidden, lastHidden);
+
+ // move viewport to start of alignment:
+ // box, height etc as in non-hidden case
+ moveViewport(0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to straddle hidden rows
+ moveViewport(0, 198);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), Math.round ((float)198 * od.getSequencesHeight()
+ / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(
+ od.getBoxHeight(),
+ Math.round((float) (viewHeight + lastHidden - firstHidden + 1)
+ * od.getSequencesHeight() / alheight));
+ }
+
+ /**
+ * Test that the box position is set correctly when there are hidden rows at
+ * the bottom
+ */
+ @Test(groups = { "Functional" })
+ public void testSetBoxFromViewportHiddenRowsAtEnd()
+ {
+ int firstHidden = 500;
+ int lastHidden = 524;
+ hideSequences(firstHidden, lastHidden);
+
+ // move viewport to start of alignment:
+ // box, height etc as in non-hidden case
+ moveViewport(0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // move viewport to end of alignment
+ // viewport sits above hidden rows and does not include them
+ moveViewport(0, firstHidden - viewHeight - 1);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(
+ od.getBoxY(),
+ Math.round((float) (firstHidden - viewHeight - 1)
+ * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden rows at the start
+ * of the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenRowsAtStart()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // hide rows at start and check updated box position is correct
+ // changes boxY but not boxheight
+ int lastHiddenRow = 30;
+ hideSequences(0, lastHiddenRow);
+
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(),
+ Math.round((float) (lastHiddenRow + 1)
+ * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click in hidden rows - same result
+ mouseClick(od, 0, 0);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(
+ od.getBoxY(),
+ Math.round((float) (lastHiddenRow + 1)
+ * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click below hidden rows
+ mouseClick(od, 0, 150);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 150);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden rows at the middle
+ * of the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenRowsInMiddle()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // hide rows in middle and check updated box position is correct
+ // no changes
+ int firstHiddenRow = 50;
+ int lastHiddenRow = 54;
+ hideSequences(firstHiddenRow, lastHiddenRow);
+
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click above hidden rows, so that box overlaps
+ int ypos = 35; // column value in residues
+ mouseClick(od, 0,
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(),
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(
+ od.getBoxHeight(),
+ boxHeight
+ + Math.round((float) (lastHiddenRow - firstHiddenRow + 1)
+ * od.getSequencesHeight() / alheight));
+
+ // click so that box straddles hidden rows
+ ypos = 44; // column value in residues
+ mouseClick(od, 0,
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(),
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(
+ od.getBoxHeight(),
+ boxHeight
+ + Math.round((float) (lastHiddenRow - firstHiddenRow + 1)
+ * od.getSequencesHeight() / alheight));
+ }
+
+ /**
+ * Test setting of the box position, when there are hidden rows at the end of
+ * the alignment
+ */
+ @Test(groups = { "Functional" })
+ public void testFromMouseWithHiddenRowsAtEnd()
+ {
+ od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ assertEquals(vpranges.getStartRes(), 0);
+ assertEquals(vpranges.getStartSeq(), 0);
+
+ // hide rows at end and check updated box position is correct
+ // no changes
+ int firstHidden = 500;
+ int lastHidden = 524;
+ hideSequences(firstHidden, lastHidden);
+
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(), 0);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click above hidden rows
+ int ypos = 40; // row 40
+ mouseClick(od, 0,
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(od.getBoxY(),
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click above hidden rows so box overlaps
+ // boxY moved upwards, boxHeight remains same
+ ypos = 497; // row 497
+ mouseClick(od, 0,
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(
+ od.getBoxY(),
+ Math.round((float) (firstHidden - viewHeight)
+ * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ // click within hidden rows
+ ypos = 505;
+ mouseClick(od, 0,
+ Math.round((float) ypos * od.getSequencesHeight() / alheight));
+ assertEquals(od.getBoxX(), 0);
+ assertEquals(
+ od.getBoxY(),
+ Math.round((firstHidden - viewHeight) * od.getSequencesHeight()
+ / alheight));
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+ }
+
+ /*
+ * Move viewport horizontally: startRes + previous width gives new horizontal extent. Vertical extent stays the same.
+ */
+ private void moveViewportH(int startRes)
+ {
+ vpranges.setViewportStartAndWidth(startRes, viewWidth);
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ }
+
+ /*
+ * Move viewport vertically: startSeq and endSeq give new vertical extent. Horizontal extent stays the same.
+ */
+ private void moveViewportV(int startSeq)
+ {
+ vpranges.setViewportStartAndHeight(startSeq, viewHeight);
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ }
+
+ /*
+ * Move viewport horizontally and vertically.
+ */
+ private void moveViewport(int startRes, int startSeq)
+ {
+ vpranges.setViewportStartAndWidth(startRes, viewWidth);
+ vpranges.setViewportStartAndHeight(startSeq, viewHeight);
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ }
+
+ /*
+ * Mouse click as position x,y in overview window
+ */
+ private void mouseClick(OverviewDimensions od, int x, int y)
+ {
+ od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols);
+
+ // updates require an OverviewPanel to exist which it doesn't here
+ // so call setBoxPosition() as it would be called by the AlignmentPanel
+ // normally
+ od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
+ }
+
+ /*
+ * Test that the box is positioned with the top left corner at xpos, ypos
+ * and with the original width and height
+ */
+ private void testBoxIsAtClickPoint(int xpos, int ypos)
+ {
+ mouseClick(od, xpos, ypos);
+ assertEquals(od.getBoxX(), xpos);
+ assertEquals(od.getBoxY(), ypos);
+ assertEquals(od.getBoxWidth(), boxWidth);
+ assertEquals(od.getBoxHeight(), boxHeight);
+
+ }
+
+ /*
+ * Hide sequences between start and end
+ */
+ private void hideSequences(int start, int end)
+ {
+ SequenceI[] allseqs = al.getSequencesArray();
+ SequenceGroup theseSeqs = new SequenceGroup();
+
+ for (int i = start; i <= end; i++)
+ {
+ theseSeqs.addSequence(allseqs[i], false);
+ al.getHiddenSequences().hideSequence(allseqs[i]);
+ }
+
+ hiddenRepSequences.put(allseqs[start], theseSeqs);
+ }
+}
--- /dev/null
+package jalview.viewmodel;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import jalview.analysis.AlignmentGenerator;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.HiddenSequences;
+
+import java.beans.PropertyChangeEvent;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class ViewportRangesTest {
+
+ AlignmentGenerator gen = new AlignmentGenerator(false);
+
+ AlignmentI al = gen.generate(20, 30, 1, 5, 5);
+
+ AlignmentI smallAl = gen.generate(7, 2, 2, 5, 5);
+
+ @BeforeMethod(alwaysRun = true)
+ public void cleanUp()
+ {
+ ColumnSelection sel = new ColumnSelection();
+ al.getHiddenColumns().revealAllHiddenColumns(sel);
+ al.getHiddenSequences().showAll(null);
+ smallAl.getHiddenColumns().revealAllHiddenColumns(sel);
+ smallAl.getHiddenSequences().showAll(null);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testViewportRanges()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+
+ assertEquals(vr.getStartRes(),0);
+ assertEquals(vr.getEndRes(), al.getWidth()-1);
+ assertEquals(vr.getStartSeq(), 0);
+ assertEquals(vr.getEndSeq(), al.getHeight() - 1);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testGetAbsoluteAlignmentHeight()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+
+ assertEquals(vr.getAbsoluteAlignmentHeight(), al.getHeight());
+
+ al.getHiddenSequences().hideSequence(al.getSequenceAt(3));
+ assertEquals(vr.getAbsoluteAlignmentHeight(), al.getHeight() + 1);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testGetAbsoluteAlignmentWidth()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ assertEquals(vr.getAbsoluteAlignmentWidth(), al.getWidth());
+ }
+
+ @Test(groups = { "Functional" })
+ public void testSetEndRes()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setEndRes(-1);
+ assertEquals(vr.getEndRes(), 0);
+
+ vr.setEndRes(al.getWidth() - 1);
+ assertEquals(vr.getEndRes(), al.getWidth() - 1);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testSetEndSeq()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setEndSeq(-1);
+ assertEquals(vr.getEndSeq(), 0);
+
+ vr.setEndSeq(al.getHeight());
+ assertEquals(vr.getEndSeq(), al.getHeight() - 1);
+
+ vr.setEndRes(al.getHeight() - 1);
+ assertEquals(vr.getEndSeq(), al.getHeight() - 1);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testSetStartRes()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setStartRes(-1);
+ assertEquals(vr.getStartRes(), 0);
+
+ vr.setStartRes(al.getWidth());
+ assertEquals(vr.getStartRes(), al.getWidth() - 1);
+
+ vr.setStartRes(al.getWidth() - 1);
+ assertEquals(vr.getStartRes(), al.getWidth() - 1);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testSetStartSeq()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setStartSeq(-1);
+ assertEquals(vr.getStartSeq(), 0);
+
+ vr.setStartSeq(al.getHeight() - vr.getViewportHeight() + 1);
+ assertEquals(vr.getStartSeq(), al.getHeight() - vr.getViewportHeight());
+
+ vr.setStartSeq(al.getHeight() - vr.getViewportHeight());
+ assertEquals(vr.getStartSeq(), al.getHeight() - vr.getViewportHeight());
+ }
+
+ @Test(groups = { "Functional" })
+ public void testSetStartEndRes()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setStartEndRes(-1, -1);
+ assertEquals(vr.getStartRes(), 0);
+ assertEquals(vr.getEndRes(), 0);
+
+ vr.setStartEndRes(5, 19);
+ assertEquals(vr.getStartRes(), 5);
+ assertEquals(vr.getEndRes(), 19);
+
+ vr.setStartEndRes(al.getWidth(), al.getWidth());
+ assertEquals(vr.getEndRes(), al.getWidth() - 1);
+
+ ViewportRanges vrsmall = new ViewportRanges(smallAl);
+ vrsmall.setStartEndRes(al.getWidth(), al.getWidth());
+ assertEquals(vrsmall.getEndRes(), 6);
+
+ // make visible alignment width = 0
+ smallAl.getHiddenColumns().hideColumns(0, 6);
+ vrsmall.setStartEndRes(0, 4);
+ assertEquals(vrsmall.getStartRes(), 0);
+ assertEquals(vrsmall.getEndRes(), 0);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testSetStartEndSeq()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setStartEndSeq(-1, -1);
+ assertEquals(vr.getStartSeq(), 0);
+ assertEquals(vr.getEndSeq(), 0);
+
+ vr.setStartEndSeq(5, 19);
+ assertEquals(vr.getStartSeq(), 5);
+ assertEquals(vr.getEndSeq(), 19);
+
+ vr.setStartEndSeq(al.getHeight(), al.getHeight());
+ assertEquals(vr.getEndSeq(), al.getHeight() - 1);
+
+ // make visible alignment height = 0
+ smallAl.getHiddenSequences().hideSequence(smallAl.getSequenceAt(0));
+ smallAl.getHiddenSequences().hideSequence(smallAl.getSequenceAt(0));
+ ViewportRanges vrsmall = new ViewportRanges(smallAl);
+ vrsmall.setStartEndSeq(0, 3);
+ assertEquals(vrsmall.getStartSeq(), 0);
+ assertEquals(vrsmall.getEndSeq(), 0);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testSetViewportHeight()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setViewportHeight(13);
+ assertEquals(vr.getViewportHeight(), 13);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testSetViewportWidth()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setViewportWidth(13);
+ assertEquals(vr.getViewportWidth(), 13);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testSetViewportStartAndHeight()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setViewportStartAndHeight(2, 6);
+ assertEquals(vr.getViewportHeight(), 6);
+ assertEquals(vr.getStartSeq(), 2);
+
+ // reset -ve values of start to 0
+ vr.setViewportStartAndHeight(-1, 7);
+ assertEquals(vr.getViewportHeight(), 7);
+ assertEquals(vr.getStartSeq(), 0);
+
+ // reset out of bounds start values to within bounds
+ vr.setViewportStartAndHeight(35, 5);
+ assertEquals(vr.getViewportHeight(), 5);
+ assertEquals(vr.getStartSeq(), 24);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testSetViewportStartAndWidth()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setViewportStartAndWidth(2, 6);
+ assertEquals(vr.getViewportWidth(), 6);
+ assertEquals(vr.getStartRes(), 2);
+
+ // reset -ve values of start to 0
+ vr.setViewportStartAndWidth(-1, 7);
+ assertEquals(vr.getViewportWidth(), 7);
+ assertEquals(vr.getStartRes(), 0);
+
+ // reset out of bounds start values to within bounds
+ vr.setViewportStartAndWidth(35, 5);
+ assertEquals(vr.getViewportWidth(), 5);
+ assertEquals(vr.getStartRes(), 16);
+
+ // small alignment doesn't get bounds reset
+ ViewportRanges vrsmall = new ViewportRanges(smallAl);
+ vrsmall.setViewportStartAndWidth(0, 63);
+ assertEquals(vrsmall.getViewportWidth(), 7);
+ assertEquals(vrsmall.getStartRes(), 0);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testPageUpDown()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setViewportStartAndHeight(8, 6);
+ vr.pageDown();
+ assertEquals(vr.getStartSeq(), 13);
+
+ vr.pageUp();
+ assertEquals(vr.getStartSeq(), 8);
+
+ vr.pageUp();
+ assertEquals(vr.getStartSeq(), 3);
+
+ vr.pageUp();
+ // pageup does not go beyond 0, viewport height stays the same
+ assertEquals(vr.getStartSeq(), 0);
+ assertEquals(vr.getViewportHeight(), 6);
+
+ vr.pageDown();
+ vr.pageDown();
+ vr.pageDown();
+ vr.pageDown();
+ vr.pageDown();
+
+ // pagedown to bottom does not go beyond end, and height stays same
+ assertEquals(vr.getStartSeq(), 24);
+ assertEquals(vr.getViewportHeight(), 6);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testScrollUp()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setViewportStartAndHeight(1, 5);
+ vr.scrollUp(true);
+ assertEquals(vr.getStartSeq(), 0);
+ // can't scroll above top
+ vr.scrollUp(true);
+ assertEquals(vr.getStartSeq(), 0);
+
+ vr.setViewportStartAndHeight(24, 5);
+ vr.scrollUp(false);
+ assertEquals(vr.getStartSeq(), 25);
+ // can't scroll beyond bottom
+ vr.scrollUp(false);
+ assertEquals(vr.getStartSeq(), 25);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testScrollUpWithHidden()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+
+ // hide last sequence
+ HiddenSequences hidden = new HiddenSequences(al);
+ hidden.hideSequence(al.getSequenceAt(29));
+
+ vr.setViewportStartAndHeight(1, 5);
+ vr.scrollUp(true);
+ assertEquals(vr.getStartSeq(), 0);
+ // can't scroll above top
+ vr.scrollUp(true);
+ assertEquals(vr.getStartSeq(), 0);
+
+ vr.setViewportStartAndHeight(23, 5);
+ vr.scrollUp(false);
+ assertEquals(vr.getStartSeq(), 24);
+ // can't scroll beyond bottom
+ vr.scrollUp(false);
+ assertEquals(vr.getStartSeq(), 24);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testScrollRight()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setViewportStartAndWidth(1, 5);
+ vr.scrollRight(false);
+ assertEquals(vr.getStartRes(), 0);
+ // can't scroll left past start
+ vr.scrollRight(false);
+ assertEquals(vr.getStartRes(), 0);
+
+ vr.setViewportStartAndWidth(15, 5);
+ vr.scrollRight(true);
+ assertEquals(vr.getStartRes(), 16);
+ // can't scroll right past end
+ vr.scrollRight(true);
+ assertEquals(vr.getStartRes(), 16);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testScrollRightWithHidden()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+
+ // hide last 2 columns
+ HiddenColumns cols = new HiddenColumns();
+ cols.hideColumns(19, 20);
+ al.setHiddenColumns(cols);
+
+ vr.setViewportStartAndWidth(1, 5);
+ vr.scrollRight(false);
+ assertEquals(vr.getStartRes(), 0);
+ // can't scroll left past start
+ vr.scrollRight(false);
+ assertEquals(vr.getStartRes(), 0);
+
+ vr.setViewportStartAndWidth(13, 5);
+ vr.scrollRight(true);
+ assertEquals(vr.getStartRes(), 14);
+ // can't scroll right past last visible col
+ vr.scrollRight(true);
+ assertEquals(vr.getStartRes(), 14);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testScrollToWrappedVisible()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setViewportStartAndWidth(5, 10);
+
+ vr.scrollToWrappedVisible(0);
+ assertEquals(vr.getStartRes(), 0);
+
+ vr.scrollToWrappedVisible(10);
+ assertEquals(vr.getStartRes(), 10);
+
+ vr.scrollToWrappedVisible(15);
+ assertEquals(vr.getStartRes(), 10);
+ }
+
+ // leave until JAL-2388 is merged and we can do without viewport
+ /*@Test(groups = { "Functional" })
+ public void testScrollToVisible()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ vr.setViewportStartAndWidth(12,5);
+ vr.setViewportStartAndHeight(10,6);
+ vr.scrollToVisible(13,14)
+
+ // no change
+ assertEquals(vr.getStartRes(), 12);
+ assertEquals(vr.getStartSeq(), 10);
+
+ vr.scrollToVisible(5,6);
+ assertEquals(vr.getStartRes(), 5);
+ assertEquals(vr.getStartSeq(), 6);
+
+ // test for hidden columns too
+ }*/
+
+ @Test(groups = { "Functional" })
+ public void testEventFiring()
+ {
+ ViewportRanges vr = new ViewportRanges(al);
+ MockPropChangeListener l = new MockPropChangeListener(vr);
+ List<String> emptylist = new ArrayList<>();
+
+ vr.setViewportWidth(5);
+ vr.setViewportHeight(5);
+ l.reset();
+
+ // one event fired when startRes is called with new value
+ vr.setStartRes(4);
+ assertTrue(l.verify(1, Arrays.asList("startres")));
+ l.reset();
+
+ // no event fired for same value
+ vr.setStartRes(4);
+ assertTrue(l.verify(0, emptylist));
+ l.reset();
+
+ vr.setEndRes(10);
+ assertTrue(l.verify(1, Arrays.asList("startres")));
+ l.reset();
+
+ // no event fired for same value
+ vr.setEndRes(10);
+ assertTrue(l.verify(0, emptylist));
+ l.reset();
+
+ vr.setStartSeq(4);
+ assertTrue(l.verify(1, Arrays.asList("startseq")));
+ l.reset();
+
+ vr.setStartSeq(4);
+ assertTrue(l.verify(0, emptylist));
+ l.reset();
+
+ vr.setEndSeq(10);
+ assertTrue(l.verify(1, Arrays.asList("startseq")));
+ l.reset();
+
+ vr.setEndSeq(10);
+ assertTrue(l.verify(0, emptylist));
+ l.reset();
+
+ vr.setStartEndRes(2, 15);
+ assertTrue(l.verify(1, Arrays.asList("startres")));
+ l.reset();
+
+ vr.setStartEndRes(2, 15);
+ assertTrue(l.verify(0, emptylist));
+ l.reset();
+
+ // check new value fired by event is corrected startres
+ vr.setStartEndRes(-1, 5);
+ assertTrue(l.verify(1, Arrays.asList("startres"), Arrays.asList(0)));
+ l.reset();
+
+ // check new value fired by event is corrected endres
+ vr.setStartEndRes(0, -1);
+ assertTrue(l.verify(1, Arrays.asList("endres"), Arrays.asList(0)));
+ l.reset();
+
+ vr.setStartEndSeq(2, 15);
+ assertTrue(l.verify(1, Arrays.asList("startseq")));
+ l.reset();
+
+ vr.setStartEndSeq(2, 15);
+ assertTrue(l.verify(0, emptylist));
+ l.reset();
+
+ vr.setStartEndRes(2, 2); // so seq and res values should be different, in
+ // case of transposing in code
+ l.reset();
+
+ // check new value fired by event is corrected startseq
+ vr.setStartEndSeq(-1, 5);
+ assertTrue(l.verify(1, Arrays.asList("startseq"), Arrays.asList(0)));
+ l.reset();
+
+ // check new value fired by event is corrected endseq
+ vr.setStartEndSeq(0, -1);
+ assertTrue(l.verify(1, Arrays.asList("endseq"), Arrays.asList(0)));
+ l.reset();
+
+ // reset for later tests
+ vr.setStartEndSeq(2, 15);
+ l.reset();
+
+ // test viewport height and width setting triggers event
+ vr.setViewportHeight(10);
+ assertTrue(l.verify(1, Arrays.asList("endseq")));
+ l.reset();
+
+ vr.setViewportWidth(18);
+ assertTrue(l.verify(1, Arrays.asList("endres")));
+ l.reset();
+
+ // already has seq start set to 2, so triggers endseq
+ vr.setViewportStartAndHeight(2, 16);
+ assertTrue(l.verify(1, Arrays.asList("endseq")));
+ l.reset();
+
+ vr.setViewportStartAndWidth(1, 14);
+ assertTrue(l.verify(1, Arrays.asList("startres")));
+ l.reset();
+
+ // test page up/down triggers event
+ vr.pageUp();
+ assertTrue(l.verify(1, Arrays.asList("startseq")));
+ l.reset();
+
+ vr.pageDown();
+ assertTrue(l.verify(1, Arrays.asList("startseq")));
+ l.reset();
+
+ // test scrolling triggers event
+ vr.scrollUp(true);
+ assertTrue(l.verify(1, Arrays.asList("startseq")));
+ l.reset();
+
+ vr.scrollUp(false);
+ assertTrue(l.verify(1, Arrays.asList("startseq")));
+ l.reset();
+
+ vr.scrollRight(true);
+ assertTrue(l.verify(1, Arrays.asList("startres")));
+ l.reset();
+
+ vr.scrollRight(false);
+ assertTrue(l.verify(1, Arrays.asList("startres")));
+ l.reset();
+
+ vr.scrollToVisible(10, 10);
+ assertTrue(l.verify(4,
+ Arrays.asList("startseq", "startseq", "startseq", "startseq")));
+ l.reset();
+
+ vr.scrollToWrappedVisible(5);
+ assertTrue(l.verify(1, Arrays.asList("startres")));
+ l.reset();
+ }
+}
+
+// mock listener for property change events
+class MockPropChangeListener implements ViewportListenerI
+{
+ private int firecount = 0;
+
+ private List<String> events = new ArrayList<>();
+
+ private List<Integer> newvalues = new ArrayList<>();
+
+ public MockPropChangeListener(ViewportRanges vr)
+ {
+ vr.addPropertyChangeListener(this);
+ }
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ firecount++;
+ events.add(evt.getPropertyName());
+ newvalues.add((Integer) evt.getNewValue());
+ }
+
+ public boolean verify(int count, List<String> eventslist,
+ List<Integer> valueslist)
+ {
+ return (count == firecount) && events.equals(eventslist)
+ && newvalues.equals(valueslist);
+ }
+
+ public boolean verify(int count, List<String> eventslist)
+ {
+ return (count == firecount) && events.equals(eventslist);
+ }
+
+ public void reset()
+ {
+ firecount = 0;
+ events.clear();
+ newvalues.clear();
+ }
+}
--- /dev/null
+package jalview.ws.dbsources;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import jalview.analysis.AlignSeq;
+import jalview.bin.Cache;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.SequenceI;
+import jalview.ext.ensembl.EnsemblGenomes;
+import jalview.fts.api.FTSData;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.fts.service.uniprot.UniProtFTSRestClient;
+import jalview.ws.SequenceFetcher;
+import jalview.ws.seqfetcher.DbSourceProxy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * A class to verify that remotely fetched data has an expected format and can
+ * be successfully processed by Jalview. This is intended as a first line of
+ * defence and early warning of service affecting changes to data fetched
+ * externally.
+ * <p>
+ * This is class is not intended to cover remote services e.g. alignment. Nor
+ * should it duplicate tests already provided by other classes (such as
+ * PDBFTSRestClientTest). Or maybe we will relocate those tests here...
+ */
+public class RemoteFormatTest
+{
+ SequenceFetcher sf;
+
+ @BeforeTest(alwaysRun = true)
+ public void setUp() throws Exception
+ {
+ Cache.loadProperties("test/jalview/io/testProps.jvprops");
+ // ensure 'add annotation from structure' is selected
+ Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
+ Boolean.TRUE.toString());
+ Cache.applicationProperties.setProperty("ADD_SS_ANN",
+ Boolean.TRUE.toString());
+
+ sf = new SequenceFetcher(false);
+ }
+
+ @DataProvider(name = "AccessionData")
+ protected Object[][] getAccessions()
+ {
+ return new Object[][] { { DBRefSource.UNIPROT, "P30419" },
+ { DBRefSource.PDB, "1QIP" }, { DBRefSource.EMBL, "X53828" },
+ { DBRefSource.EMBLCDS, "CAA37824" },
+ { DBRefSource.ENSEMBL, "ENSG00000157764" },
+ { new EnsemblGenomes().getDbSource(), "DDB_G0283883" },
+ { new PfamFull().getDbSource(), "PF03760" },
+ { new PfamSeed().getDbSource(), "PF03760" },
+ { new RfamSeed().getDbSource(), "RF00014" } };
+ }
+
+ @Test(groups = "Network", dataProvider = "AccessionData")
+ public void testFetchAccession(String dbSource, String accessionId)
+ throws Exception
+ {
+ System.out.println("Fetching " + accessionId + " from " + dbSource);
+ List<DbSourceProxy> sps = sf.getSourceProxy(dbSource);
+ assertFalse(sps.isEmpty());
+ AlignmentI al = sps.get(0).getSequenceRecords(accessionId);
+ assertNotNull(al);
+ assertTrue(al.getHeight() > 0);
+ SequenceI sq = al.getSequenceAt(0);
+ // suppress this check as only Uniprot and PDB acquire PDB refs
+ // assertTrue(sq.getAllPDBEntries().size() > 0, "No PDBEntry on sequence.");
+ assertTrue(sq.getDBRefs().length > 0, "No DBRef on sequence.");
+ // suppress this test as only certain databases provide 'primary' dbrefs
+ // assertFalse(sq.getPrimaryDBRefs().isEmpty());
+ int length = AlignSeq.extractGaps("-. ", sq.getSequenceAsString())
+ .length();
+ assertEquals(sq.getEnd() - sq.getStart() + 1, length,
+ "Sequence start/end doesn't match number of residues in sequence");
+ }
+
+ @Test(groups = { "Network" })
+ public void testUniprotFreeTextSearch() throws Exception
+ {
+ List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+ FTSRestClientI client = UniProtFTSRestClient.getInstance();
+ wantedFields.add(client.getDataColumnByNameOrCode("id"));
+ wantedFields.add(client.getDataColumnByNameOrCode("entry name"));
+ wantedFields.add(client.getDataColumnByNameOrCode("organism"));
+ wantedFields.add(client.getDataColumnByNameOrCode("reviewed")); // Status
+ wantedFields.add(client.getDataColumnByNameOrCode("length"));
+
+ FTSRestRequest request = new FTSRestRequest();
+ request.setAllowEmptySeq(false);
+ request.setResponseSize(100);
+ request.setFieldToSearchBy("Search All");
+ request.setSearchTerm("metanephrops"); // lobster!
+ request.setWantedFields(wantedFields);
+
+ FTSRestResponse response;
+ response = client.executeRequest(request);
+ assertTrue(response.getNumberOfItemsFound() > 20);
+ assertTrue(response.getSearchSummary() != null);
+ assertTrue(response.getSearchSummary().size() > 20);
+ // verify we successfully filtered out the header row (JAL-2485)
+ FTSData header = response.getSearchSummary().iterator().next();
+ assertFalse(
+ header.getSummaryData()[0].toString().equalsIgnoreCase("Entry"),
+ "Failed to filter out summary header row");
+ }
+}
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
-@Test(groups = { "External" })
+/*
+ * All methods in this class are set to the Network group because setUpBeforeClass will fail
+ * if there is no network.
+ */
+@Test(singleThreaded = true)
public class DisorderAnnotExportImport
{
public static jalview.gui.AlignFrame af = null;
- @BeforeClass(inheritGroups = true)
+ @BeforeClass(alwaysRun = true)
public static void setUpBeforeClass() throws Exception
{
Cache.loadProperties("test/jalview/io/testProps.jvprops");
Cache.initLogger();
disc = JalviewJabawsTestUtils.getJabawsDiscoverer();
+
+ while (disc.isRunning())
+ {
+ // don't get services until discoverer has finished
+ Thread.sleep(100);
+ }
+
iupreds = new ArrayList<Jws2Instance>();
for (Jws2Instance svc : disc.getServices())
{
/**
* test for patches to JAL-1294
*/
- @Test
+ @Test(groups = { "External", "Network" })
public void testDisorderAnnotExport()
{
disorderClient = new AADisorderClient(iupreds.get(0), af, null, null);
DataSourceType.PASTE));
// test for consistency in io
- StockholmFileTest.testAlignmentEquivalence(al, al_new, true);
+ StockholmFileTest.testAlignmentEquivalence(al, al_new, true, false,
+ false);
return;
} catch (Exception e)
{
+++ /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.
- */
-package jalview.ws.jabaws;
-
-import static org.testng.AssertJUnit.assertNotNull;
-import static org.testng.AssertJUnit.assertTrue;
-
-import jalview.bin.Cache;
-import jalview.datamodel.AlignmentI;
-import jalview.gui.Jalview2XML;
-import jalview.gui.JvOptionPane;
-import jalview.io.AnnotationFile;
-import jalview.io.DataSourceType;
-import jalview.io.FileFormat;
-import jalview.io.FormatAdapter;
-import jalview.io.StockholmFileTest;
-import jalview.ws.jws2.JPred301Client;
-import jalview.ws.jws2.JabaParamStore;
-import jalview.ws.jws2.Jws2Discoverer;
-import jalview.ws.jws2.SequenceAnnotationWSClient;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
-import jalview.ws.params.AutoCalcSetting;
-
-import java.awt.Component;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-
-import org.testng.Assert;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import compbio.metadata.Argument;
-import compbio.metadata.WrongParameterException;
-
-public class JpredJabaStructExportImport
-{
-
- @BeforeClass(alwaysRun = true)
- public void setUpJvOptionPane()
- {
- JvOptionPane.setInteractiveMode(false);
- JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
- }
-
- public static String testseqs = "examples/uniref50.fa";
-
- public static Jws2Discoverer disc;
-
- public static Jws2Instance jpredws;
-
- jalview.ws.jws2.JPred301Client jpredClient;
-
- public static jalview.gui.AlignFrame af = null;
-
- @BeforeClass(alwaysRun = true)
- public static void setUpBeforeClass() throws Exception
- {
- Cache.loadProperties("test/jalview/io/testProps.jvprops");
- Cache.initLogger();
- disc = JalviewJabawsTestUtils.getJabawsDiscoverer(false);
-
- for (Jws2Instance svc : disc.getServices())
- {
- if (svc.getServiceTypeURI().toLowerCase().contains("jpred"))
- {
- jpredws = svc;
- }
- }
-
- System.out.println("State of jpredws: " + jpredws);
- Assert.assertNotNull(jpredws, "jpredws is null!");
- jalview.io.FileLoader fl = new jalview.io.FileLoader(false);
- af = fl.LoadFileWaitTillLoaded(testseqs, jalview.io.DataSourceType.FILE);
- assertNotNull("Couldn't load test data ('" + testseqs + "')", af);
- }
-
- @AfterClass(alwaysRun = true)
- public static void tearDownAfterClass() throws Exception
- {
- if (af != null)
- {
- af.setVisible(false);
- af.dispose();
- }
- }
-
- @Test(groups = { "Functional" })
- public void testJPredStructOneSeqOnly()
- {
- af.selectAllSequenceMenuItem_actionPerformed(null);
- af.getViewport()
- .getSelectionGroup()
- .addOrRemove(
- af.getViewport().getSelectionGroup().getSequenceAt(0),
- false);
- af.hideSelSequences_actionPerformed(null);
- jpredClient = new JPred301Client(jpredws, af, null, null);
-
- assertTrue(
- "Didn't find any default args to check for. Buggy implementation of hardwired arguments in client.",
- jpredClient.selectDefaultArgs().size() > 0);
-
- boolean success = false;
- af.getViewport().getCalcManager().startWorker(jpredClient);
- do
- {
- try
- {
- Thread.sleep(500);
- List<Argument> args = JabaParamStore.getJabafromJwsArgs(af
- .getViewport()
- .getCalcIdSettingsFor(jpredClient.getCalcId())
- .getArgumentSet()), defargs = jpredClient
- .selectDefaultArgs();
- for (Argument rg : args)
- {
- for (Argument defg : defargs)
- {
- if (defg.equals(rg))
- {
- success = true;
- }
- }
- }
- if (!success)
- {
- jpredClient.cancelCurrentJob();
- Assert.fail("Jpred Client didn't run with hardwired default parameters.");
- }
-
- } catch (InterruptedException x)
- {
- }
- ;
- } while (af.getViewport().getCalcManager().isWorking());
-
- }
-
- @Test(groups = { "Functional" })
- public void testJPredStructExport()
- {
-
- jpredClient = new JPred301Client(jpredws, af, null, null);
-
- af.getViewport().getCalcManager().startWorker(jpredClient);
-
- do
- {
- try
- {
- Thread.sleep(50);
- } catch (InterruptedException x)
- {
- }
- ;
- } while (af.getViewport().getCalcManager().isWorking());
-
- AlignmentI orig_alig = af.getViewport().getAlignment();
-
- testAnnotationFileIO("Testing JPredWS Annotation IO", orig_alig);
-
- }
-
- public static void testAnnotationFileIO(String testname, AlignmentI al)
- {
- try
- {
- // what format would be appropriate for RNAalifold annotations?
- String aligfileout = FileFormat.Pfam.getWriter(null).print(
- al.getSequencesArray(), true);
-
- String anfileout = new AnnotationFile()
- .printAnnotationsForAlignment(al);
- assertTrue(
- "Test "
- + testname
- + "\nAlignment annotation file was not regenerated. Null string",
- anfileout != null);
- assertTrue(
- "Test "
- + testname
- + "\nAlignment annotation file was not regenerated. Empty string",
- anfileout.length() > "JALVIEW_ANNOTATION".length());
-
- System.out.println("Output annotation file:\n" + anfileout
- + "\n<<EOF\n");
-
- // again what format would be appropriate?
- AlignmentI al_new = new FormatAdapter().readFile(aligfileout,
- DataSourceType.PASTE, FileFormat.Fasta);
- assertTrue(
- "Test "
- + testname
- + "\nregenerated annotation file did not annotate alignment.",
- new AnnotationFile().readAnnotationFile(al_new, anfileout,
- DataSourceType.PASTE));
-
- // test for consistency in io
- StockholmFileTest.testAlignmentEquivalence(al, al_new, false);
- return;
- } catch (Exception e)
- {
- e.printStackTrace();
- }
- Assert.fail("Test "
- + testname
- + "\nCouldn't complete Annotation file roundtrip input/output/input test.");
- }
-
- @Test(groups = { "Functional" })
- public void testJpredwsSettingsRecovery()
- {
- Assert.fail("not implemnented");
- List<compbio.metadata.Argument> opts = new ArrayList<compbio.metadata.Argument>();
- for (compbio.metadata.Argument rg : (List<compbio.metadata.Argument>) jpredws
- .getRunnerConfig().getArguments())
- {
- if (rg.getDescription().contains("emperature"))
- {
- try
- {
- rg.setValue("292");
- } catch (WrongParameterException q)
- {
- Assert.fail("Couldn't set the temperature parameter "
- + q.getStackTrace());
- }
- opts.add(rg);
- }
- if (rg.getDescription().contains("max"))
- {
- opts.add(rg);
- }
- }
- jpredClient = new JPred301Client(jpredws, af, null, opts);
-
- af.getViewport().getCalcManager().startWorker(jpredClient);
-
- do
- {
- try
- {
- Thread.sleep(50);
- } catch (InterruptedException x)
- {
- }
- ;
- } while (af.getViewport().getCalcManager().isWorking());
- AutoCalcSetting oldacs = af.getViewport().getCalcIdSettingsFor(
- jpredClient.getCalcId());
- String oldsettings = oldacs.getWsParamFile();
- // write out parameters
- jalview.gui.AlignFrame nalf = null;
- assertTrue("Couldn't write out the Jar file",
- new Jalview2XML(false).saveAlignment(af,
- "testJPredWS_param.jar", "trial parameter writeout"));
- assertTrue("Couldn't read back the Jar file", (nalf = new Jalview2XML(
- false).loadJalviewAlign("testJpredWS_param.jar")) != null);
- if (nalf != null)
- {
- AutoCalcSetting acs = af.getViewport().getCalcIdSettingsFor(
- jpredClient.getCalcId());
- assertTrue("Calc ID settings not recovered from viewport stash",
- acs.equals(oldacs));
- assertTrue(
- "Serialised Calc ID settings not identical to those recovered from viewport stash",
- acs.getWsParamFile().equals(oldsettings));
- JMenu nmenu = new JMenu();
- new SequenceAnnotationWSClient()
- .attachWSMenuEntry(nmenu, jpredws, af);
- assertTrue("Couldn't get menu entry for service",
- nmenu.getItemCount() > 0);
- for (Component itm : nmenu.getMenuComponents())
- {
- if (itm instanceof JMenuItem)
- {
- JMenuItem i = (JMenuItem) itm;
- if (i.getText().equals(
- jpredws.getAlignAnalysisUI().getAAconToggle()))
- {
- i.doClick();
- break;
- }
- }
- }
- while (af.getViewport().isCalcInProgress())
- {
- try
- {
- Thread.sleep(200);
- } catch (Exception x)
- {
- }
- ;
- }
- AutoCalcSetting acs2 = af.getViewport().getCalcIdSettingsFor(
- jpredClient.getCalcId());
- assertTrue(
- "Calc ID settings after recalculation has not been recovered.",
- acs2.getWsParamFile().equals(oldsettings));
- }
- }
-}
MsaWS msaservice = null;
for (Services service : registry.getSupportedServices())
{
+ if (service == null)
+ {
+ // the 'unsupported service'
+ continue;
+ }
if (service.equals(Services.ClustalOWS))
{
msaservice = (MsaWS) Jws2Client.connect(url, service);
import compbio.metadata.Argument;
import compbio.metadata.WrongParameterException;
+/*
+ * All methods in this class are set to the Network group because setUpBeforeClass will fail
+ * if there is no network.
+ */
+@Test(singleThreaded = true)
public class RNAStructExportImport
{
Cache.initLogger();
disc = JalviewJabawsTestUtils.getJabawsDiscoverer(false);
+ while (disc.isRunning())
+ {
+ // don't get services until discoverer has finished
+ Thread.sleep(100);
+ }
+
for (Jws2Instance svc : disc.getServices())
{
}
}
- @Test(groups = { "Functional" })
+ @Test(groups = { "Network" })
public void testRNAAliFoldValidStructure()
{
}
}
- @Test(groups = { "Functional" })
+ @Test(groups = { "Network" })
public void testRNAStructExport()
{
} while (af.getViewport().getCalcManager().isWorking());
AlignmentI orig_alig = af.getViewport().getAlignment();
-
- testAnnotationFileIO("Testing RNAalifold Annotation IO", orig_alig);
+ // JBPNote: this assert fails (2.10.2) because the 'Reference Positions'
+ // annotation is mistakenly recognised as an RNA annotation row when read in
+ // as an annotation file.
+ verifyAnnotationFileIO("Testing RNAalifold Annotation IO", orig_alig);
}
- public static void testAnnotationFileIO(String testname, AlignmentI al)
+ static void verifyAnnotationFileIO(String testname, AlignmentI al)
{
try
{
DataSourceType.PASTE));
// test for consistency in io
- StockholmFileTest.testAlignmentEquivalence(al, al_new, false);
+ StockholmFileTest.testAlignmentEquivalence(al, al_new, false, false,
+ false);
return;
} catch (Exception e)
{
+ "\nCouldn't complete Annotation file roundtrip input/output/input test.");
}
- @Test(groups = { "Functional" })
+ @Test(groups = { "Network" })
public void testRnaalifoldSettingsRecovery()
{
List<Argument> opts = new ArrayList<Argument>();
import compbio.metadata.PresetManager;
import compbio.metadata.WrongParameterException;
+/*
+ * All methods in this class are set to the Network group because setUpBeforeClass will fail
+ * if there is no network.
+ */
+@Test(singleThreaded = true)
public class ParameterUtilsTest
{
disc = JalviewJabawsTestUtils.getJabawsDiscoverer();
}
- @Test(groups = { "Functional" })
+ @Test(groups = { "Network" })
public void testWriteParameterSet() throws WrongParameterException
{
for (Jws2Instance service : disc.getServices())
|| serviceTests.contains(service.serviceType.toLowerCase());
}
- @Test(groups = { "Functional" })
+ @Test(groups = { "Network" })
public void testCopyOption()
{
for (Jws2Instance service : disc.getServices())
/**
*/
- @Test(groups = { "Functional" })
+ @Test(groups = { "Network" })
public void testCopyParameter()
{
for (Jws2Instance service : disc.getServices())
*/
package jalview.ws.seqfetcher;
+import static org.testng.Assert.assertTrue;
+
+import jalview.bin.Cache;
import jalview.gui.JvOptionPane;
-import org.testng.AssertJUnit;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
}
- @Test(groups = { "Functional" })
+ @Test(groups = { "Network" })
public void testDasRegistryContact()
{
- jalview.bin.Cache.getDasSourceRegistry().refreshSources();
- AssertJUnit
- .assertTrue(
- "Expected to find at least one DAS source at the registry. Check config.",
- jalview.bin.Cache.getDasSourceRegistry().getSources()
- .size() > 0);
+ Cache.getDasSourceRegistry().refreshSources();
+ assertTrue(Cache.getDasSourceRegistry().getSources().isEmpty(),
+ "Expected to find no DAS sources at the registry. Check config.");
}
}
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
import org.testng.Assert;
import org.testng.FileAssert;
"A", testSeq, null);
Assert.assertEquals(testSeq.getStart(), 1);
Assert.assertEquals(testSeq.getEnd(), 147);
- Assert.assertEquals(actualMapping, expectedMapping);
+ // Can't do Assert.assertEquals(actualMapping, expectedMapping);
+ // because this fails in our version of TestNG
+ Assert.assertEquals(actualMapping.size(), expectedMapping.size());
+ Iterator<Map.Entry<Integer, int[]>> it = expectedMapping.entrySet()
+ .iterator();
+ while (it.hasNext())
+ {
+ Map.Entry<Integer, int[]> pair = it.next();
+ Assert.assertTrue(actualMapping.containsKey(pair.getKey()));
+ Assert.assertEquals(actualMapping.get(pair.getKey()),
+ pair.getValue());
+ }
+
} catch (Exception e)
{
e.printStackTrace();
Assert.assertEquals(strucMapping.getMappingDetailsOutput(),
expectedMappingOutput);
- Assert.assertEquals(strucMapping.getMapping(), expectedMapping);
+
+ // Can't do Assert.assertEquals(strucMapping.getMapping(), expectedMapping);
+ // because this fails in our version of TestNG
+ Assert.assertEquals(strucMapping.getMapping().size(),
+ expectedMapping.size());
+ Iterator<Map.Entry<Integer, int[]>> it = expectedMapping.entrySet()
+ .iterator();
+ while (it.hasNext())
+ {
+ Map.Entry<Integer, int[]> pair = it.next();
+ Assert.assertTrue(strucMapping.getMapping()
+ .containsKey(pair.getKey()));
+ Assert.assertEquals(strucMapping.getMapping().get(pair.getKey()),
+ pair.getValue());
+ }
}
@Test(groups = { "Network" })
Assert.assertNull(entityP);
}
+
+ @Test(groups = { "Network" })
+ public void getLeadingIntegerFromString()
+ {
+ Assert.assertEquals(
+ SiftsClient.getLeadingIntegerValue("1234abcd", -1), 1234);
+ Assert.assertEquals(
+ SiftsClient.getLeadingIntegerValue("1234", -1),
+ 1234);
+ Assert.assertEquals(
+ SiftsClient.getLeadingIntegerValue("abcd", -1), -1);
+ Assert.assertEquals(
+ SiftsClient.getLeadingIntegerValue("abcd1234", -1), -1);
+ Assert.assertEquals(
+ SiftsClient.getLeadingIntegerValue("None", -1), -1);
+ Assert.assertEquals(
+ SiftsClient.getLeadingIntegerValue("Null", -1), -1);
+ }
}
--- /dev/null
+/*
+ * Copyright 2004-2012 Sebastian Dietrich (Sebastian.Dietrich@e-movimento.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package junit.extensions;
+
+import java.util.Collection;
+
+/**
+ * This class is used to access a method or field of an object no matter what the access modifier of the method or field. The syntax
+ * for accessing fields and methods is out of the ordinary because this class uses reflection to peel away protection.
+ * <p>
+ * a.k.a. The "ObjectMolester"
+ * <p>
+ * Here is an example of using this to access a private member: <br>
+ * Given the following class <code>MyClass</code>: <br>
+ *
+ * <pre>
+ * public class MyClass {
+ * private String name; // private attribute
+ *
+ * // private constructor
+ * private MyClass() {
+ * super();
+ * }
+ *
+ * // private method
+ * private void setName(String newName) {
+ * this.name = newName;
+ * }
+ * }
+ * </pre>
+ *
+ * We now want to access the class: <br>
+ *
+ * <pre>
+ * MyClass myObj = PA.instantiate(MyClass.class);
+ * PA.invokeMethod(myObj, "setName(java.lang.String)", "myNewName");
+ * String name = PA.getValue(myObj, "name");
+ * </pre>
+ *
+ * This class extends {@link PrivilegedAccessor} by re-throwing checked {@link Exception}s as {@link RuntimeException}s.
+ *
+ *
+ * @see PrivilegedAccessor
+ *
+ * @author Sebastian Dietrich (sebastian.dietrich@e-movimento.com)
+ * @author Lubos Bistak (lubos@bistak.sk)
+ */
+public class PA {
+ private final Object instanceOrClass;
+
+ /**
+ * Private constructor to make it impossible to instantiate this class from outside of PA.
+ *
+ * @param instanceOrClass
+ */
+ private PA(Object instanceOrClass) {
+ this.instanceOrClass = instanceOrClass;
+ }
+
+ /**
+ * Returns a string representation of the given object. The string has the following format: "<classname> {<attributes and values>}"
+ * whereas <attributes and values> is a comma separated list with <attributeName>=<attributeValue> <atributes and values> includes
+ * all attributes of the objects class followed by the attributes of its superclass (if any) and so on.
+ *
+ * @param instanceOrClass the object or class to get a string representation of
+ * @return a string representation of the given object
+ *
+ * @see PrivilegedAccessor#toString(Object)
+ */
+ public static String toString(final Object instanceOrClass) {
+ return PrivilegedAccessor.toString(instanceOrClass);
+ }
+
+ /**
+ * Gets the name of all fields (public, private, protected, default) of the given instance or class. This includes as well all
+ * fields (public, private, protected, default) of all its super classes.
+ *
+ * @param instanceOrClass the instance or class to get the fields of
+ * @return the collection of field names of the given instance or class
+ *
+ * @see PrivilegedAccessor#getFieldNames(Object)
+ */
+ public static Collection<String> getFieldNames(final Object instanceOrClass) {
+ return PrivilegedAccessor.getFieldNames(instanceOrClass);
+ }
+
+ /**
+ * Gets the signatures of all methods (public, private, protected, default) of the given instance or class. This includes as well
+ * all methods (public, private, protected, default) of all its super classes. This does not include constructors.
+ *
+ * @param instanceOrClass the instance or class to get the method signatures of
+ * @return the collection of method signatures of the given instance or class
+ *
+ * @see PrivilegedAccessor#getMethodSignatures(Object)
+ */
+ public static Collection<String> getMethodSignatures(final Object instanceOrClass) {
+ return PrivilegedAccessor.getMethodSignatures(instanceOrClass);
+ }
+
+ /**
+ * Gets the value of the named field and returns it as an object. If instanceOrClass is a class then a static field is returned.
+ *
+ * @param instanceOrClass the instance or class to get the field from
+ * @param fieldName the name of the field
+ * @return an object representing the value of the field
+ * @throws IllegalArgumentException if the field does not exist
+ *
+ * @see PrivilegedAccessor#getValue(Object,String)
+ */
+ public static Object getValue(final Object instanceOrClass, final String fieldName) {
+ try {
+ return PrivilegedAccessor.getValue(instanceOrClass, fieldName);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Can't get value of " + fieldName + " from " + instanceOrClass, e);
+ }
+ }
+
+ /**
+ * Gets the value of the named field and returns it as an object.
+ *
+ * @param fieldName the name of the field
+ * @return an object representing the value of the field
+ * @throws IllegalArgumentException if the field does not exist
+ *
+ * @see PA#getValue(Object,String)
+ */
+ public Object getValue(final String fieldName) {
+ return PA.getValue(instanceOrClass, fieldName);
+ }
+
+ /**
+ * Instantiates an object of the given class with the given arguments and the given argument types. If you want to instantiate a
+ * member class, you must provide the object it is a member of as first argument.
+ *
+ * @param fromClass the class to instantiate an object from
+ * @param arguments the arguments to pass to the constructor
+ * @param argumentTypes the fully qualified types of the arguments of the constructor
+ * @return an object of the given type
+ * @throws IllegalArgumentException if the class can't be instantiated. This could be the case if the number of actual and formal
+ * parameters differ; if an unwrapping conversion for primitive arguments fails; if, after possible unwrapping, a
+ * parameter value cannot be converted to the corresponding formal parameter type by a method invocation conversion; if
+ * this Constructor object enforces Java language access control and the underlying constructor is inaccessible; if the
+ * underlying constructor throws an exception; if the constructor could not be found; or if the class that declares the
+ * underlying constructor represents an abstract class.
+ *
+ * @see PrivilegedAccessor#instantiate(Class,Class[],Object[])
+ */
+ public static <T> T instantiate(final Class<? extends T> fromClass, final Class<?>[] argumentTypes, final Object... arguments) {
+ try {
+ return PrivilegedAccessor.instantiate(fromClass, argumentTypes, correctVarargs(arguments));
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Can't instantiate class " + fromClass + " with arguments " + arguments, e);
+ }
+ }
+
+ /**
+ * Instantiates an object of the given class with the given arguments. If you want to instantiate a member class, you must provide
+ * the object it is a member of as first argument.
+ *
+ * @param fromClass the class to instantiate an object from
+ * @param arguments the arguments to pass to the constructor
+ * @return an object of the given type
+ * @throws IllegalArgumentException if the class can't be instantiated. This could be the case if the number of actual and formal
+ * parameters differ; if an unwrapping conversion for primitive arguments fails; or if, after possible unwrapping, a
+ * parameter value cannot be converted to the corresponding formal parameter type by a method invocation conversion; if
+ * this Constructor object enforces Java language access control and the underlying constructor is inaccessible; if the
+ * underlying constructor throws an exception; if the constructor could not be found; or if the class that declares the
+ * underlying constructor represents an abstract class.
+ *
+ * @see PrivilegedAccessor#instantiate(Class,Object[])
+ */
+ public static <T> T instantiate(final Class<? extends T> fromClass, final Object... arguments) {
+ try {
+ return PrivilegedAccessor.instantiate(fromClass, correctVarargs(arguments));
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Can't instantiate class " + fromClass + " with arguments " + arguments, e);
+ }
+ }
+
+ /**
+ * Calls a method on the given object instance with the given arguments. Arguments can be object types or representations for
+ * primitives.
+ *
+ * @param instanceOrClass the instance or class to invoke the method on
+ * @param methodSignature the name of the method and the parameters <br>
+ * (e.g. "myMethod(java.lang.String, com.company.project.MyObject)")
+ * @param arguments an array of objects to pass as arguments
+ * @return the return value of this method or null if void
+ * @throws IllegalArgumentException if the method could not be invoked. This could be the case if the method is inaccessible; if the
+ * underlying method throws an exception; if no method with the given <code>methodSignature</code> could be found; or if
+ * an argument couldn't be converted to match the expected type
+ *
+ * @see PrivilegedAccessor#invokeMethod(Object,String,Object[])
+ */
+ public static Object invokeMethod(final Object instanceOrClass, final String methodSignature, final Object... arguments) {
+ try {
+ return PrivilegedAccessor.invokeMethod(instanceOrClass, methodSignature, correctVarargs(arguments));
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Can't invoke method " + methodSignature + " on " + instanceOrClass + " with arguments "
+ + arguments, e);
+ }
+ }
+
+ /**
+ * Calls a method with the given arguments. Arguments can be object types or representations for primitives.
+ *
+ * @param methodSignature the name of the method and the parameters <br>
+ * (e.g. "myMethod(java.lang.String, com.company.project.MyObject)")
+ * @param arguments an array of objects to pass as arguments
+ * @return the return value of this method or null if void
+ * @throws IllegalArgumentException if the method could not be invoked. This could be the case if the method is inaccessible; if the
+ * underlying method throws an exception; if no method with the given <code>methodSignature</code> could be found; or if
+ * an argument couldn't be converted to match the expected type
+ * @see PA#invokeMethod(Object, String, Object...)
+ */
+ public Object invokeMethod(final String methodSignature, final Object... arguments) {
+ return PA.invokeMethod(instanceOrClass, methodSignature, arguments);
+ }
+
+ /**
+ * Corrects varargs to their initial form. If you call a method with an object-array as last argument the Java varargs mechanism
+ * converts this array in single arguments. This method returns an object array if the arguments are all of the same type.
+ *
+ * @param arguments the possibly converted arguments of a vararg method
+ * @return arguments possibly converted
+ */
+ private static Object[] correctVarargs(final Object... arguments) {
+ if ((arguments == null) || changedByVararg(arguments)) return new Object[] {arguments};
+ return arguments;
+ }
+
+ /**
+ * Tests if the arguments were changed by vararg. Arguments are changed by vararg if they are of a non primitive array type. E.g.
+ * arguments[] = Object[String[]] is converted to String[] while e.g. arguments[] = Object[int[]] is not converted and stays
+ * Object[int[]]
+ *
+ * Unfortunately we can't detect the difference for arg = Object[primitive] since arguments[] = Object[Object[primitive]] which is
+ * converted to Object[primitive] and arguments[] = Object[primitive] which stays Object[primitive]
+ *
+ * and we can't detect the difference for arg = Object[non primitive] since arguments[] = Object[Object[non primitive]] is converted
+ * to Object[non primitive] and arguments[] = Object[non primitive] stays Object[non primitive]
+ *
+ * @param parameters the parameters
+ * @return true if parameters were changes by varargs, false otherwise
+ */
+ private static boolean changedByVararg(final Object[] parameters) {
+ if ((parameters.length == 0) || (parameters[0] == null)) return false;
+
+ if (parameters.getClass() == Object[].class) return false;
+
+ return true;
+ }
+
+ /**
+ * Sets the value of the named field. If fieldName denotes a static field, provide a class, otherwise provide an instance. If the
+ * fieldName denotes a final field, this method could fail with an IllegalAccessException, since setting the value of final fields
+ * at other times than instantiation can have unpredictable effects.<br/>
+ * <br/>
+ * Example:<br/>
+ * <br/>
+ * <code>
+ * String myString = "Test"; <br/>
+ * <br/>
+ * //setting the private field value<br/>
+ * PrivilegedAccessor.setValue(myString, "value", new char[] {'T', 'e', 's', 't'});<br/>
+ * <br/>
+ * //setting the static final field serialVersionUID - MIGHT FAIL<br/>
+ * PrivilegedAccessor.setValue(myString.getClass(), "serialVersionUID", 1);<br/>
+ * <br/>
+ * </code>
+ *
+ * @param instanceOrClass the instance or class to set the field
+ * @param fieldName the name of the field
+ * @param value the new value of the field
+ * @throws IllegalArgumentException if the value could not be set. This could be the case if no field with the given
+ * <code>fieldName</code> can be found; or if the field was final
+ *
+ * @see PrivilegedAccessor.setValue(Object,String,Object)
+ */
+ public static PA setValue(final Object instanceOrClass, final String fieldName, final Object value) {
+ try {
+ PrivilegedAccessor.setValue(instanceOrClass, fieldName, value);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Can't set value " + value + " at " + fieldName + " in " + instanceOrClass, e);
+ }
+ return new PA(instanceOrClass);
+ }
+
+ /**
+ * Sets the value of the named field. If fieldName denotes a static field, provide a class, otherwise provide an instance. If the
+ * fieldName denotes a final field, this method could fail with an IllegalAccessException, since setting the value of final fields
+ * at other times than instantiation can have unpredictable effects.<br/>
+ * <br/>
+ * Example:<br/>
+ * <br/>
+ * <code>
+ * String myString = "Test"; <br/>
+ * <br/>
+ * //setting the private field value<br/>
+ * PrivilegedAccessor.setValue(myString, "value", new char[] {'T', 'e', 's', 't'});<br/>
+ * <br/>
+ * //setting the static final field serialVersionUID - MIGHT FAIL<br/>
+ * PrivilegedAccessor.setValue(myString.getClass(), "serialVersionUID", 1);<br/>
+ * <br/>
+ * </code>
+ *
+ * @param fieldName the name of the field
+ * @param value the new value of the field
+ * @throws IllegalArgumentException if the value could not be set. This could be the case if no field with the given
+ * <code>fieldName</code> can be found; or if the field was final
+ *
+ * @see PA.setValue(Object,String,Object)
+ */
+ public PA setValue(final String fieldName, final Object value) {
+ PA.setValue(instanceOrClass, fieldName, value);
+ return this;
+ }
+}
--- /dev/null
+/*
+ * Copyright 2004-2012 Sebastian Dietrich (Sebastian.Dietrich@e-movimento.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package junit.extensions;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.security.InvalidParameterException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/**
+ * This class is used to access a method or field of an object no matter what the access modifier of the method or field. The syntax
+ * for accessing fields and methods is out of the ordinary because this class uses reflection to peel away protection.
+ * <p>
+ * a.k.a. The "ObjectMolester"
+ * <p>
+ * Here is an example of using this to access a private member: <br>
+ * <code>myObject</code> is an object of type <code>MyClass</code>. <code>setName(String)</code> is a private method of
+ * <code>MyClass</code>.
+ *
+ * <pre>
+ * PrivilegedAccessor.invokeMethod(myObject, "setName(java.lang.String)", "newName");
+ * </pre>
+ *
+ * @author Charlie Hubbard (chubbard@iss.net)
+ * @author Prashant Dhokte (pdhokte@iss.net)
+ * @author Sebastian Dietrich (sebastian.dietrich@e-movimento.com)
+ *
+ * @deprecated use PA instead. PA improves the functionality of PrivilegedAccessor by introducing support for varargs and removal of
+ * the necessity to catch exceptions.
+ */
+@Deprecated
+final class PrivilegedAccessor
+{
+ /**
+ * Private constructor to make it impossible to instantiate this class.
+ */
+ private PrivilegedAccessor() {
+ assert false : "You mustn't instantiate PrivilegedAccessor, use its methods statically";
+ }
+
+ /**
+ * Returns a string representation of the given object. The string has the following format: "<classname> {<attributes and values>}"
+ * whereas <attributes and values> is a comma separated list with <attributeName>=<attributeValue> <atributes and values> includes
+ * all attributes of the objects class followed by the attributes of its superclass (if any) and so on.
+ *
+ * @param instanceOrClass the object or class to get a string representation of
+ * @return a string representation of the given object
+ */
+ public static String toString(final Object instanceOrClass) {
+ Collection<String> fields = getFieldNames(instanceOrClass);
+
+ if (fields.isEmpty())
+ {
+ return getClass(instanceOrClass).getName();
+ }
+
+ StringBuffer stringBuffer = new StringBuffer();
+
+ stringBuffer.append(getClass(instanceOrClass).getName() + " {");
+
+ for (String fieldName : fields) {
+ try {
+ stringBuffer.append(fieldName + "=" + getValue(instanceOrClass, fieldName) + ", ");
+ } catch (NoSuchFieldException e) {
+ assert false : "It should always be possible to get a field that was just here";
+ }
+ }
+
+ stringBuffer.replace(stringBuffer.lastIndexOf(", "), stringBuffer.length(), "}");
+ return stringBuffer.toString();
+ }
+
+ /**
+ * Gets the name of all fields (public, private, protected, default) of the given instance or class. This includes as well all
+ * fields (public, private, protected, default) of all its super classes.
+ *
+ * @param instanceOrClass the instance or class to get the fields of
+ * @return the collection of field names of the given instance or class
+ */
+ public static Collection<String> getFieldNames(final Object instanceOrClass) {
+ if (instanceOrClass == null)
+ {
+ return Collections.EMPTY_LIST;
+ }
+
+ Class<?> clazz = getClass(instanceOrClass);
+ Field[] fields = clazz.getDeclaredFields();
+ Collection<String> fieldNames = new ArrayList<String>(fields.length);
+
+ for (Field field : fields) {
+ fieldNames.add(field.getName());
+ }
+ fieldNames.addAll(getFieldNames(clazz.getSuperclass()));
+
+ return fieldNames;
+ }
+
+ /**
+ * Gets the signatures of all methods (public, private, protected, default) of the given instance or class. This includes as well
+ * all methods (public, private, protected, default) of all its super classes. This does not include constructors.
+ *
+ * @param instanceOrClass the instance or class to get the method signatures of
+ * @return the collection of method signatures of the given instance or class
+ */
+ public static Collection<String> getMethodSignatures(final Object instanceOrClass) {
+ if (instanceOrClass == null)
+ {
+ return Collections.EMPTY_LIST;
+ }
+
+ Class<?> clazz = getClass(instanceOrClass);
+ Method[] methods = clazz.getDeclaredMethods();
+ Collection<String> methodSignatures = new ArrayList<String>(methods.length + Object.class.getDeclaredMethods().length);
+
+ for (Method method : methods) {
+ methodSignatures.add(method.getName() + "(" + getParameterTypesAsString(method.getParameterTypes()) + ")");
+ }
+ methodSignatures.addAll(getMethodSignatures(clazz.getSuperclass()));
+
+ return methodSignatures;
+ }
+
+ /**
+ * Gets the value of the named field and returns it as an object. If instanceOrClass is a class then a static field is returned.
+ *
+ * @param instanceOrClass the instance or class to get the field from
+ * @param fieldName the name of the field
+ * @return an object representing the value of the field
+ * @throws NoSuchFieldException if the field does not exist
+ */
+ public static Object getValue(final Object instanceOrClass, final String fieldName) throws NoSuchFieldException {
+ Field field = getField(instanceOrClass, fieldName);
+ try {
+ return field.get(instanceOrClass);
+ } catch (IllegalAccessException e) {
+ assert false : "getField() should have setAccessible(true), so an IllegalAccessException should not occur in this place";
+ return null;
+ }
+ }
+
+ /**
+ * Instantiates an object of the given class with the given arguments. If you want to instantiate a member class, you must provide
+ * the object it is a member of as first argument.
+ *
+ * @param fromClass the class to instantiate an object from
+ * @param args the arguments to pass to the constructor
+ * @return an object of the given type
+ * @throws IllegalArgumentException if the number of actual and formal parameters differ; if an unwrapping conversion for primitive
+ * arguments fails; or if, after possible unwrapping, a parameter value cannot be converted to the corresponding formal
+ * parameter type by a method invocation conversion.
+ * @throws IllegalAccessException if this Constructor object enforces Java language access control and the underlying constructor is
+ * inaccessible.
+ * @throws InvocationTargetException if the underlying constructor throws an exception.
+ * @throws NoSuchMethodException if the constructor could not be found
+ * @throws InstantiationException if the class that declares the underlying constructor represents an abstract class.
+ *
+ * @see PrivilegedAccessor#instantiate(Class,Class[],Object[])
+ */
+ public static <T> T instantiate(final Class<? extends T> fromClass, final Object[] args) throws IllegalArgumentException,
+ InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+ return instantiate(fromClass, getParameterTypes(args), args);
+ }
+
+ /**
+ * Instantiates an object of the given class with the given arguments and the given argument types. If you want to instantiate a
+ * member class, you must provide the object it is a member of as first argument.
+ *
+ *
+ * @param fromClass the class to instantiate an object from
+ * @param args the arguments to pass to the constructor
+ * @param argumentTypes the fully qualified types of the arguments of the constructor
+ * @return an object of the given type
+ * @throws IllegalArgumentException if the number of actual and formal parameters differ; if an unwrapping conversion for primitive
+ * arguments fails; or if, after possible unwrapping, a parameter value cannot be converted to the corresponding formal
+ * parameter type by a method invocation conversion.
+ * @throws IllegalAccessException if this Constructor object enforces Java language access control and the underlying constructor is
+ * inaccessible.
+ * @throws InvocationTargetException if the underlying constructor throws an exception.
+ * @throws NoSuchMethodException if the constructor could not be found
+ * @throws InstantiationException if the class that declares the underlying constructor represents an abstract class.
+ *
+ * @see PrivilegedAccessor#instantiate(Class,Object[])
+ */
+ public static <T> T instantiate(final Class<? extends T> fromClass, final Class<?>[] argumentTypes, final Object[] args)
+ throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException,
+ NoSuchMethodException {
+ return getConstructor(fromClass, argumentTypes).newInstance(args);
+ }
+
+ /**
+ * Calls a method on the given object instance with the given arguments. Arguments can be object types or representations for
+ * primitives.
+ *
+ * @param instanceOrClass the instance or class to invoke the method on
+ * @param methodSignature the name of the method and the parameters <br>
+ * (e.g. "myMethod(java.lang.String, com.company.project.MyObject)")
+ * @param arguments an array of objects to pass as arguments
+ * @return the return value of this method or null if void
+ * @throws IllegalAccessException if the method is inaccessible
+ * @throws InvocationTargetException if the underlying method throws an exception.
+ * @throws NoSuchMethodException if no method with the given <code>methodSignature</code> could be found
+ * @throws IllegalArgumentException if an argument couldn't be converted to match the expected type
+ */
+ public static Object invokeMethod(final Object instanceOrClass, final String methodSignature, final Object[] arguments)
+ throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+ if ((methodSignature.indexOf('(') == -1) || (methodSignature.indexOf('(') >= methodSignature.indexOf(')')))
+ {
+ throw new NoSuchMethodException(methodSignature);
+ }
+ Class<?>[] parameterTypes = getParameterTypes(methodSignature);
+ return getMethod(instanceOrClass, getMethodName(methodSignature), parameterTypes).invoke(instanceOrClass,
+ getCorrectedArguments(parameterTypes, arguments));
+ }
+
+ /**
+ * Gets the given arguments corrected to match the given methodSignature. Correction is necessary for array arguments not to be
+ * mistaken by varargs.
+ *
+ * @param parameterTypes the method signatue the given arguments should match
+ * @param arguments the arguments that should be corrected
+ * @return the corrected arguments
+ */
+ private static Object[] getCorrectedArguments(Class<?>[] parameterTypes, Object[] arguments) {
+ if (arguments == null)
+ {
+ return arguments;
+ }
+ if (parameterTypes.length > arguments.length)
+ {
+ return arguments;
+ }
+ if (parameterTypes.length < arguments.length)
+ {
+ return getCorrectedArguments(parameterTypes, new Object[] {arguments});
+ }
+
+ Object[] correctedArguments = new Object[arguments.length];
+ int currentArgument = 0;
+ for (Class<?> parameterType : parameterTypes) {
+ correctedArguments[currentArgument] = getCorrectedArgument(parameterType, arguments[currentArgument]);
+ currentArgument++;
+ }
+ return correctedArguments;
+ }
+
+ /**
+ * Gets the given argument corrected to match the given parameterType. Correction is necessary for array arguments not to be
+ * mistaken by varargs.
+ *
+ * @param parameterType the type to match the given argument upon
+ * @param argument the argument to match the given parameterType
+ * @return the corrected argument
+ */
+ private static Object getCorrectedArgument(Class<?> parameterType, Object argument) {
+ if (!parameterType.isArray() || (argument == null)) {
+ return argument; // normal argument for normal parameterType
+ }
+
+ if (!argument.getClass().isArray()) {
+ return new Object[] {argument};
+ }
+
+ if (parameterType.equals(argument.getClass()))
+ {
+ return argument; // no need to cast
+ }
+
+ // (typed) array argument for (object) array parameterType, elements need to be casted
+ Object correctedArrayArgument = Array.newInstance(parameterType.getComponentType(), Array.getLength(argument));
+ for (int index = 0; index < Array.getLength(argument); index++) {
+ if (parameterType.getComponentType().isPrimitive()) { // rely on autoboxing
+ Array.set(correctedArrayArgument, index, Array.get(argument, index));
+ } else { // cast to expected type
+ try {
+ Array.set(correctedArrayArgument, index, parameterType.getComponentType().cast(Array.get(argument, index)));
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException("Argument " + argument + " of type " + argument.getClass()
+ + " does not match expected argument type " + parameterType + ".");
+ }
+ }
+ }
+ return correctedArrayArgument;
+ }
+
+ /**
+ * Sets the value of the named field. If fieldName denotes a static field, provide a class, otherwise provide an instance. If the
+ * fieldName denotes a final field, this method could fail with an IllegalAccessException, since setting the value of final fields
+ * at other times than instantiation can have unpredictable effects.<br/>
+ * <br/>
+ * Example:<br/>
+ * <br/>
+ * <code>
+ * String myString = "Test"; <br/>
+ * <br/>
+ * //setting the private field value<br/>
+ * PrivilegedAccessor.setValue(myString, "value", new char[] {'T', 'e', 's', 't'});<br/>
+ * <br/>
+ * //setting the static final field serialVersionUID - MIGHT FAIL<br/>
+ * PrivilegedAccessor.setValue(myString.getClass(), "serialVersionUID", 1);<br/>
+ * <br/>
+ * </code>
+ *
+ * @param instanceOrClass the instance or class to set the field
+ * @param fieldName the name of the field
+ * @param value the new value of the field
+ * @throws NoSuchFieldException if no field with the given <code>fieldName</code> can be found
+ * @throws IllegalAccessException possibly if the field was final
+ */
+ public static void setValue(final Object instanceOrClass, final String fieldName, final Object value) throws NoSuchFieldException,
+ IllegalAccessException {
+ Field field = getField(instanceOrClass, fieldName);
+ if (Modifier.isFinal(field.getModifiers())) {
+ PrivilegedAccessor.setValue(field, "modifiers", field.getModifiers() ^ Modifier.FINAL);
+ }
+ field.set(instanceOrClass, value);
+ }
+
+ /**
+ * Gets the class with the given className.
+ *
+ * @param className the name of the class to get
+ * @return the class for the given className
+ * @throws ClassNotFoundException if the class could not be found
+ */
+ private static Class<?> getClassForName(final String className) throws ClassNotFoundException {
+ if (className.indexOf('[') > -1) {
+ Class<?> clazz = getClassForName(className.substring(0, className.indexOf('[')));
+ return Array.newInstance(clazz, 0).getClass();
+ }
+
+ if (className.indexOf("...") > -1) {
+ Class<?> clazz = getClassForName(className.substring(0, className.indexOf("...")));
+ return Array.newInstance(clazz, 0).getClass();
+ }
+
+ try {
+ return Class.forName(className, false, Thread.currentThread().getContextClassLoader());
+ } catch (ClassNotFoundException e) {
+ return getSpecialClassForName(className);
+ }
+ }
+
+ /**
+ * Maps string representation of primitives to their corresponding classes.
+ */
+ private static final Map<String, Class<?>> PRIMITIVE_MAPPER = new HashMap<String, Class<?>>(8);
+
+ /**
+ * Fills the map with all java primitives and their corresponding classes.
+ */
+ static {
+ PRIMITIVE_MAPPER.put("int", Integer.TYPE);
+ PRIMITIVE_MAPPER.put("float", Float.TYPE);
+ PRIMITIVE_MAPPER.put("double", Double.TYPE);
+ PRIMITIVE_MAPPER.put("short", Short.TYPE);
+ PRIMITIVE_MAPPER.put("long", Long.TYPE);
+ PRIMITIVE_MAPPER.put("byte", Byte.TYPE);
+ PRIMITIVE_MAPPER.put("char", Character.TYPE);
+ PRIMITIVE_MAPPER.put("boolean", Boolean.TYPE);
+ }
+
+ /**
+ * Gets special classes for the given className. Special classes are primitives and "standard" Java types (like String)
+ *
+ * @param className the name of the class to get
+ * @return the class for the given className
+ * @throws ClassNotFoundException if the class could not be found
+ */
+ private static Class<?> getSpecialClassForName(final String className) throws ClassNotFoundException {
+ if (PRIMITIVE_MAPPER.containsKey(className))
+ {
+ return PRIMITIVE_MAPPER.get(className);
+ }
+
+ if (missesPackageName(className))
+ {
+ return getStandardClassForName(className);
+ }
+
+ throw new ClassNotFoundException(className);
+ }
+
+ /**
+ * Gets a 'standard' java class for the given className.
+ *
+ * @param className the className
+ * @return the class for the given className (if any)
+ * @throws ClassNotFoundException of no 'standard' java class was found for the given className
+ */
+ private static Class<?> getStandardClassForName(String className) throws ClassNotFoundException {
+ try {
+ return Class.forName("java.lang." + className, false, Thread.currentThread().getContextClassLoader());
+ } catch (ClassNotFoundException e) {
+ try {
+ return Class.forName("java.util." + className, false, Thread.currentThread().getContextClassLoader());
+ } catch (ClassNotFoundException e1) {
+ throw new ClassNotFoundException(className);
+ }
+ }
+ }
+
+ /**
+ * Tests if the given className possibly misses its package name.
+ *
+ * @param className the className
+ * @return true if the className might miss its package name, otherwise false
+ */
+ private static boolean missesPackageName(String className) {
+ if (className.contains("."))
+ {
+ return false;
+ }
+ if (className.startsWith(className.substring(0, 1).toUpperCase()))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Gets the constructor for a given class with the given parameters.
+ *
+ * @param type the class to instantiate
+ * @param parameterTypes the types of the parameters
+ * @return the constructor
+ * @throws NoSuchMethodException if the method could not be found
+ */
+ private static <T> Constructor<T> getConstructor(final Class<T> type, final Class<?>[] parameterTypes) throws NoSuchMethodException {
+ Constructor<T> constructor = type.getDeclaredConstructor(parameterTypes);
+ constructor.setAccessible(true);
+ return constructor;
+ }
+
+ /**
+ * Return the named field from the given instance or class. Returns a static field if instanceOrClass is a class.
+ *
+ * @param instanceOrClass the instance or class to get the field from
+ * @param fieldName the name of the field to get
+ * @return the field
+ * @throws NoSuchFieldException if no such field can be found
+ * @throws InvalidParameterException if instanceOrClass was null
+ */
+ private static Field getField(final Object instanceOrClass, final String fieldName) throws NoSuchFieldException,
+ InvalidParameterException {
+ if (instanceOrClass == null)
+ {
+ throw new InvalidParameterException("Can't get field on null object/class");
+ }
+
+ Class<?> type = getClass(instanceOrClass);
+
+ try {
+ Field field = type.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ return field;
+ } catch (NoSuchFieldException e) {
+ if (type.getSuperclass() == null)
+ {
+ throw e;
+ }
+ return getField(type.getSuperclass(), fieldName);
+ }
+ }
+
+ /**
+ * Gets the class of the given parameter. If the parameter is a class, it is returned, if it is an object, its class is returned
+ *
+ * @param instanceOrClass the instance or class to get the class of
+ * @return the class of the given parameter
+ */
+ private static Class<?> getClass(final Object instanceOrClass) {
+ if (instanceOrClass instanceof Class)
+ {
+ return (Class<?>) instanceOrClass;
+ }
+
+ return instanceOrClass.getClass();
+ }
+
+ /**
+ * Return the named method with a method signature matching classTypes from the given class.
+ *
+ * @param type the class to get the method from
+ * @param methodName the name of the method to get
+ * @param parameterTypes the parameter-types of the method to get
+ * @return the method
+ * @throws NoSuchMethodException if the method could not be found
+ */
+ private static Method getMethod(final Class<?> type, final String methodName, final Class<?>[] parameterTypes)
+ throws NoSuchMethodException {
+ try {
+ return type.getDeclaredMethod(methodName, parameterTypes);
+ } catch (NoSuchMethodException e) {
+ if (type.getSuperclass() == null)
+ {
+ throw e;
+ }
+ return getMethod(type.getSuperclass(), methodName, parameterTypes);
+ }
+ }
+
+ /**
+ * Gets the method with the given name and parameters from the given instance or class. If instanceOrClass is a class, then we get a
+ * static method.
+ *
+ * @param instanceOrClass the instance or class to get the method of
+ * @param methodName the name of the method
+ * @param parameterTypes the parameter-types of the method to get
+ * @return the method
+ * @throws NoSuchMethodException if the method could not be found
+ */
+ private static Method getMethod(final Object instanceOrClass, final String methodName, final Class<?>[] parameterTypes)
+ throws NoSuchMethodException {
+ Class<?> type;
+
+ type = getClass(instanceOrClass);
+
+ Method accessMethod = getMethod(type, methodName, parameterTypes);
+ accessMethod.setAccessible(true);
+ return accessMethod;
+ }
+
+ /**
+ * Gets the name of a method.
+ *
+ * @param methodSignature the signature of the method
+ * @return the name of the method
+ */
+ private static String getMethodName(final String methodSignature) {
+ try {
+ return methodSignature.substring(0, methodSignature.indexOf('(')).trim();
+ } catch (StringIndexOutOfBoundsException e) {
+ assert false : "Signature must have been checked before this method was called";
+ return null;
+ }
+ }
+
+ /**
+ * Gets the types of the parameters.
+ *
+ * @param parameters the parameters
+ * @return the class-types of the arguments
+ */
+ private static Class<?>[] getParameterTypes(final Object[] parameters) {
+ if (parameters == null)
+ {
+ return new Class[0];
+ }
+
+ Class<?>[] typesOfParameters = new Class[parameters.length];
+
+ for (int i = 0; i < parameters.length; i++) {
+ typesOfParameters[i] = parameters[i].getClass();
+ }
+ return typesOfParameters;
+ }
+
+ /**
+ * Gets the types of the given parameters. If the parameters don't match the given methodSignature an IllegalArgumentException is
+ * thrown.
+ *
+ * @param methodSignature the signature of the method
+ * @return the parameter types as class[]
+ * @throws NoSuchMethodException if the method could not be found
+ * @throws IllegalArgumentException if one of the given parameters doesn't math the given methodSignature
+ */
+ private static Class<?>[] getParameterTypes(final String methodSignature) throws NoSuchMethodException, IllegalArgumentException {
+ String signature = getSignatureWithoutBraces(methodSignature);
+
+ StringTokenizer tokenizer = new StringTokenizer(signature, ", *");
+ Class<?>[] typesInSignature = new Class[tokenizer.countTokens()];
+
+ for (int x = 0; tokenizer.hasMoreTokens(); x++) {
+ String className = tokenizer.nextToken();
+ try {
+ typesInSignature[x] = getClassForName(className);
+ } catch (ClassNotFoundException e) {
+ NoSuchMethodException noSuchMethodException = new NoSuchMethodException(methodSignature);
+ noSuchMethodException.initCause(e);
+ throw noSuchMethodException;
+ }
+ }
+ return typesInSignature;
+ }
+
+ /**
+ * Gets the parameter types as a string.
+ *
+ * @param classTypes the types to get as names.
+ * @return the parameter types as a string
+ *
+ * @see java.lang.Class#argumentTypesToString(Class[])
+ */
+ private static String getParameterTypesAsString(final Class<?>[] classTypes) {
+ assert classTypes != null : "getParameterTypes() should have been called before this method and should have provided not-null classTypes";
+ if (classTypes.length == 0)
+ {
+ return "";
+ }
+
+ StringBuilder parameterTypes = new StringBuilder();
+ for (Class<?> clazz : classTypes) {
+ assert clazz != null : "getParameterTypes() should have been called before this method and should have provided not-null classTypes";
+ parameterTypes.append(clazz.getName()).append(", ");
+ }
+
+ return parameterTypes.substring(0, parameterTypes.length() - 2);
+ }
+
+ /**
+ * Removes the braces around the methods signature.
+ *
+ * @param methodSignature the signature with braces
+ * @return the signature without braces
+ */
+ private static String getSignatureWithoutBraces(final String methodSignature) {
+ try {
+ return methodSignature.substring(methodSignature.indexOf('(') + 1, methodSignature.indexOf(')'));
+ } catch (IndexOutOfBoundsException e) {
+ assert false : "signature must have been checked before this method";
+ return null;
+ }
+ }
+
+}