Merge branch 'develop' into features/r2_11_2_alphafold/JAL-629
authorBen Soares <b.soares@dundee.ac.uk>
Wed, 12 Apr 2023 14:49:00 +0000 (15:49 +0100)
committerBen Soares <b.soares@dundee.ac.uk>
Wed, 12 Apr 2023 14:49:00 +0000 (15:49 +0100)
112 files changed:
schemas/jalview.xsd
schemas/vamsas.xsd
src/jalview/analysis/AlignmentSorter.java
src/jalview/analysis/AlignmentUtils.java
src/jalview/analysis/AnnotationSorter.java
src/jalview/analysis/AverageDistanceEngine.java [new file with mode: 0644]
src/jalview/analysis/AverageDistanceTree.java
src/jalview/analysis/NJTree.java
src/jalview/analysis/TreeBuilder.java
src/jalview/analysis/TreeEngine.java [new file with mode: 0644]
src/jalview/analysis/TreeModel.java
src/jalview/api/AlignViewportI.java
src/jalview/appletgui/TreeCanvas.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/BinaryNode.java
src/jalview/datamodel/ContactListImpl.java
src/jalview/datamodel/ContactMapHolder.java
src/jalview/datamodel/ContactMapHolderI.java
src/jalview/datamodel/ContactMatrix.java
src/jalview/datamodel/ContactMatrixI.java
src/jalview/datamodel/SeqDistanceContactMatrix.java
src/jalview/datamodel/SequenceNode.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/AnnotationPanel.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/SeqPanel.java
src/jalview/gui/TreeCanvas.java
src/jalview/gui/TreePanel.java
src/jalview/io/NewickFile.java
src/jalview/io/PContactPredictionFile.java
src/jalview/io/vamsas/Tree.java
src/jalview/project/Jalview2XML.java
src/jalview/renderer/ContactMapRenderer.java
src/jalview/viewmodel/AlignmentViewport.java
src/jalview/ws/datamodel/alphafold/PAEContactMatrix.java
src/jalview/ws/dbsources/EBIAlfaFold.java
src/jalview/xml/binding/embl/EntrySetType.java
src/jalview/xml/binding/embl/EntryType.java
src/jalview/xml/binding/embl/ObjectFactory.java
src/jalview/xml/binding/embl/ROOT.java
src/jalview/xml/binding/embl/XrefType.java
src/jalview/xml/binding/jalview/AlcodonFrame.java
src/jalview/xml/binding/jalview/Annotation.java
src/jalview/xml/binding/jalview/AnnotationColourScheme.java
src/jalview/xml/binding/jalview/AnnotationElement.java
src/jalview/xml/binding/jalview/DoubleMatrix.java
src/jalview/xml/binding/jalview/DoubleVector.java
src/jalview/xml/binding/jalview/Feature.java
src/jalview/xml/binding/jalview/FeatureMatcher.java
src/jalview/xml/binding/jalview/FeatureMatcherSet.java
src/jalview/xml/binding/jalview/FilterBy.java
src/jalview/xml/binding/jalview/JalviewModel.java
src/jalview/xml/binding/jalview/JalviewUserColours.java
src/jalview/xml/binding/jalview/MapListType.java
src/jalview/xml/binding/jalview/Mapping.java
src/jalview/xml/binding/jalview/MatrixType.java
src/jalview/xml/binding/jalview/NoValueColour.java
src/jalview/xml/binding/jalview/ObjectFactory.java
src/jalview/xml/binding/jalview/PcaDataType.java
src/jalview/xml/binding/jalview/Pdbentry.java
src/jalview/xml/binding/jalview/Property.java [new file with mode: 0644]
src/jalview/xml/binding/jalview/Sequence.java
src/jalview/xml/binding/jalview/SequenceSet.java
src/jalview/xml/binding/jalview/SequenceType.java
src/jalview/xml/binding/jalview/ThresholdType.java
src/jalview/xml/binding/jalview/VAMSAS.java
src/jalview/xml/binding/jalview/WebServiceParameterSet.java
src/jalview/xml/binding/jalview/package-info.java
src/jalview/xml/binding/uniprot/CitationType.java
src/jalview/xml/binding/uniprot/CofactorType.java
src/jalview/xml/binding/uniprot/CommentType.java
src/jalview/xml/binding/uniprot/ConsortiumType.java
src/jalview/xml/binding/uniprot/DbReferenceType.java
src/jalview/xml/binding/uniprot/Entry.java
src/jalview/xml/binding/uniprot/EventType.java
src/jalview/xml/binding/uniprot/EvidenceType.java
src/jalview/xml/binding/uniprot/EvidencedStringType.java
src/jalview/xml/binding/uniprot/FeatureType.java
src/jalview/xml/binding/uniprot/GeneLocationType.java
src/jalview/xml/binding/uniprot/GeneNameType.java
src/jalview/xml/binding/uniprot/GeneType.java
src/jalview/xml/binding/uniprot/ImportedFromType.java
src/jalview/xml/binding/uniprot/InteractantType.java
src/jalview/xml/binding/uniprot/IsoformType.java
src/jalview/xml/binding/uniprot/KeywordType.java
src/jalview/xml/binding/uniprot/LocationType.java
src/jalview/xml/binding/uniprot/MoleculeType.java
src/jalview/xml/binding/uniprot/NameListType.java
src/jalview/xml/binding/uniprot/ObjectFactory.java
src/jalview/xml/binding/uniprot/OrganismNameType.java
src/jalview/xml/binding/uniprot/OrganismType.java
src/jalview/xml/binding/uniprot/PersonType.java
src/jalview/xml/binding/uniprot/PhysiologicalReactionType.java
src/jalview/xml/binding/uniprot/PositionType.java
src/jalview/xml/binding/uniprot/PropertyType.java
src/jalview/xml/binding/uniprot/ProteinExistenceType.java
src/jalview/xml/binding/uniprot/ProteinType.java
src/jalview/xml/binding/uniprot/ReactionType.java
src/jalview/xml/binding/uniprot/ReferenceType.java
src/jalview/xml/binding/uniprot/SequenceType.java
src/jalview/xml/binding/uniprot/SourceDataType.java
src/jalview/xml/binding/uniprot/SourceType.java
src/jalview/xml/binding/uniprot/StatusType.java
src/jalview/xml/binding/uniprot/SubcellularLocationType.java
src/jalview/xml/binding/uniprot/Uniprot.java
src/jalview/xml/binding/uniprot/package-info.java
test/jalview/analysis/AlignmentUtilsTests.java
test/jalview/analysis/AverageDistanceEngineTest.java [new file with mode: 0644]
test/jalview/datamodel/ContactMatrixTest.java
test/jalview/io/NewickFileTests.java
test/jalview/project/Jalview2xmlTests.java

index 7a18d59..adaa3ee 100755 (executable)
                                                <xs:attribute name="markUnlinked" type="xs:boolean" />
                                                <xs:attribute name="fitToWindow" type="xs:boolean" />
                                                <xs:attribute name="currentTree" type="xs:boolean" />
+                                               <xs:attribute name="columnWise" type="xs:boolean" use="optional" default="false"><xs:annotation><xs:documentation>Set for trees associated with columns of an alignment, sequence or annotation row</xs:documentation></xs:annotation></xs:attribute>
+                                               <xs:attribute name="columnReference" type="xs:string" use="optional"><xs:annotation><xs:documentation>Refers to annotation row the tree is provided by</xs:documentation></xs:annotation></xs:attribute>
                                                <xs:attribute name="id" type="xs:ID" use="optional">
                                                        <xs:annotation>
                                                                <xs:documentation>
index 5fd2bab..abfabb1 100755 (executable)
                                <xs:element name="contactmatrix" type="vamsas:MatrixType"
                                        maxOccurs="unbounded" minOccurs="0">
                                </xs:element>
-                               <xs:element name="property" minOccurs="0" maxOccurs="unbounded">
-                                       <xs:complexType>
-                                               <xs:attribute name="name" type="xs:string" />
-                                               <xs:attribute name="value" type="xs:string" />
-                                       </xs:complexType>
-                               </xs:element>
+                               <xs:element name="property" type="vamsas:property" minOccurs="0" maxOccurs="unbounded"/>
                        </xs:sequence>
                        <xs:attribute name="graph" type="xs:boolean" use="required" />
                        <xs:attribute name="graphType" type="xs:int" use="optional" />
                <xs:attribute name="description" type="xs:string"/>
        </xs:complexType>
        <xs:complexType name="MatrixType">
-       <xs:simpleContent><xs:extension base="xs:string">
-       <xs:attribute name="id" type="xs:string"/>
-       <xs:attribute name="type" type="xs:string" use="required"/>
-       <xs:attribute name="rows" type="xs:integer" use="required"/>
-       <xs:attribute name="cols" type="xs:integer" use="required"/>
-       </xs:extension>
-       </xs:simpleContent>
+               <xs:sequence>
+                       <xs:element name="elements" type="xs:string" minOccurs="1"
+                               maxOccurs="1">
+                               <xs:annotation>
+                                       <xs:documentation>serialised representation of matrix as one or
+                                               more sets of comma separated values</xs:documentation>
+                               </xs:annotation>
+                       </xs:element>
+                       <xs:element name="groups" type="xs:string" minOccurs="0"
+                               maxOccurs="unbounded">
+                               <xs:annotation>
+                                       <xs:documentation>Comma separated series of BigIntegers formed from
+                                               bitsets defining partitions on the rows/columns of the matrix
+                                       </xs:documentation>
+                               </xs:annotation>
+                       </xs:element>
+                       <xs:element name="newick" type="xs:string" minOccurs="0"
+                               maxOccurs="unbounded">
+                               <xs:annotation>
+                                       <xs:documentation>tree computed for this</xs:documentation>
+                               </xs:annotation>
+                       </xs:element>
+                       <xs:element name="property" type="vamsas:property"
+                               minOccurs="0" maxOccurs="unbounded" />
+               </xs:sequence>
+
+               <xs:attribute name="type" type="xs:string" use="required" />
+               <xs:attribute name="rows" type="xs:integer"
+                       use="required" />
+               <xs:attribute name="cols" type="xs:integer"
+                       use="required" />
+               <xs:attribute name="treeMethod" type="xs:string"
+                       use="optional" />
+               <xs:attribute name="cutHeight" type="xs:double"
+                       use="optional" />
+               <xs:attribute name="id" type="xs:string" use="optional" />
+
        </xs:complexType>
+       <xs:complexType name="property">
+               <xs:attribute name="name" type="xs:string" />
+               <xs:attribute name="value" type="xs:string" />
+       </xs:complexType>
+                               
        
 </xs:schema>
index 81bddc2..0f3edfd 100755 (executable)
@@ -25,6 +25,7 @@ import jalview.analysis.scoremodels.SimilarityParams;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
+import jalview.datamodel.BinaryNode;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -534,7 +535,7 @@ public class AlignmentSorter
    * 
    * @return DOCUMENT ME!
    */
-  private static List<SequenceI> _sortByTree(SequenceNode node,
+  private static List<SequenceI> _sortByTree(BinaryNode node,
           List<SequenceI> tmp, List<SequenceI> seqset)
   {
     if (node == null)
@@ -542,12 +543,12 @@ public class AlignmentSorter
       return tmp;
     }
 
-    SequenceNode left = (SequenceNode) node.left();
-    SequenceNode right = (SequenceNode) node.right();
+    BinaryNode left = (BinaryNode) node.left();
+    BinaryNode right = (BinaryNode) node.right();
 
     if ((left == null) && (right == null))
     {
-      if (!node.isPlaceholder() && (node.element() != null))
+      if (!(node instanceof SequenceNode && ((SequenceNode)node).isPlaceholder()) && (node.element() != null))
       {
         if (node.element() instanceof SequenceI)
         {
index 42c4b76..0906872 100644 (file)
@@ -1471,9 +1471,19 @@ public class AlignmentUtils
          */
         final Iterable<AlignmentAnnotation> matchedAlignmentAnnotations = al
                 .findAnnotations(seq, dsann.getCalcId(), dsann.label);
-        if (matchedAlignmentAnnotations == null
-                || !matchedAlignmentAnnotations.iterator().hasNext())
+        boolean found=false;
+        if (matchedAlignmentAnnotations != null)
         {
+          for (AlignmentAnnotation matched:matchedAlignmentAnnotations)
+          {
+            if (dsann.description.equals(matched.description))
+            {
+              found=true;
+              break;
+            }
+          }
+        }
+        if (!found) {
           result.add(dsann);
           if (labelForCalcId != null)
           {
index 92ed9be..0f0cf68 100644 (file)
@@ -156,8 +156,15 @@ public class AnnotationSorter
       {
         return showAutocalcAbove ? 1 : -1;
       }
-      int sequenceOrder = compareSequences(o1, o2);
-      return sequenceOrder == 0 ? compareLabels(o1, o2) : sequenceOrder;
+      int computedOrder = compareSequences(o1, o2);
+      if (computedOrder==0) {
+        computedOrder = compareLabels(o1, o2);
+      }
+      if (computedOrder==0)
+      {
+        computedOrder = compareDescriptions(o1,o2);
+      }
+      return computedOrder;
     }
 
     @Override
@@ -358,6 +365,29 @@ public class AnnotationSorter
     }
     String label1 = o1.label;
     String label2 = o2.label;
+    return compareString(label1,label2);
+  }
+
+  /**
+   * Non-case-sensitive comparison of annotation descriptions. Returns zero if either
+   * argument is null.
+   * 
+   * @param o1
+   * @param o2
+   * @return
+   */
+  private int compareDescriptions(AlignmentAnnotation o1, AlignmentAnnotation o2)
+  {
+    if (o1 == null || o2 == null)
+    {
+      return 0;
+    }
+    String label1 = o1.description;
+    String label2 = o2.description;
+    return compareString(label1,label2);
+  }
+  private int compareString(String label1, String label2)
+  {
     if (label1 == null && label2 == null)
     {
       return 0;
diff --git a/src/jalview/analysis/AverageDistanceEngine.java b/src/jalview/analysis/AverageDistanceEngine.java
new file mode 100644 (file)
index 0000000..e6a763b
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+import java.util.Vector;
+
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.BinaryNode;
+import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactMatrixI;
+import jalview.math.Matrix;
+import jalview.viewmodel.AlignmentViewport;
+
+/**
+ * This class implements distance calculations used in constructing a Average
+ * Distance tree (also known as UPGMA)
+ */
+public class AverageDistanceEngine extends TreeEngine
+{
+  ContactMatrixI cm;
+
+  AlignmentViewport av;
+
+  AlignmentAnnotation aa;
+
+  /**
+   * compute cosine distance matrix for a given contact matrix and create a
+   * UPGMA tree
+   * 
+   * @param cm
+   */
+  public AverageDistanceEngine(AlignmentViewport av, AlignmentAnnotation aa,
+          ContactMatrixI cm)
+  {
+    this.av = av;
+    this.aa = aa;
+    this.cm = cm;
+    calculate(cm);
+
+  }
+
+  // 0 - normalised dot product
+  // 1 - L1 - ie (abs(v_1-v_2)/dim(v))
+  // L1 is more rational - since can reason about value of difference,
+  // normalised dot product might give cleaner clusters, but more difficult to
+  // understand.
+
+  int mode = 1;
+
+  public void calculate(ContactMatrixI cm)
+  {
+    this.cm = cm;
+    node = new Vector<BinaryNode>();
+    clusters = new Vector<BitSet>();
+    distances = new Matrix(new double[cm.getWidth()][cm.getWidth()]);
+    noseqs = cm.getWidth();
+    done = new BitSet();
+    double moduli[] = new double[cm.getWidth()];
+    double max;
+    if (mode == 0)
+    {
+      max = 1;
+    }
+    else
+    {
+      max = cm.getMax() * cm.getMax();
+    }
+
+    for (int i = 0; i < cm.getWidth(); i++)
+    {
+      // init the tree engine node for this column
+      BinaryNode cnode = new BinaryNode();
+      cnode.setElement(Integer.valueOf(i));
+      cnode.setName("c" + i);
+      node.addElement(cnode);
+      BitSet bs = new BitSet();
+      bs.set(i);
+      clusters.addElement(bs);
+
+      // compute distance matrix element
+      ContactListI ith = cm.getContactList(i);
+
+      for (int j = 0; j < i; j++)
+      {
+        distances.setValue(i, i, 0);
+        ContactListI jth = cm.getContactList(j);
+        double prd = 0;
+        for (int indx = 0; indx < cm.getHeight(); indx++)
+        {
+          if (mode == 0)
+          {
+            if (j == 0)
+            {
+              moduli[i] += ith.getContactAt(indx) * ith.getContactAt(indx);
+            }
+            prd += ith.getContactAt(indx) * jth.getContactAt(indx);
+          }
+          else
+          {
+            prd += Math
+                    .abs(ith.getContactAt(indx) - jth.getContactAt(indx));
+          }
+        }
+        if (mode == 0)
+        {
+          if (j == 0)
+          {
+            moduli[i] = Math.sqrt(moduli[i]);
+          }
+          prd = (moduli[i] != 0 && moduli[j] != 0)
+                  ? prd / (moduli[i] * moduli[j])
+                  : 0;
+          prd = 1 - prd;
+        }
+        else
+        {
+          prd /= cm.getHeight();
+        }
+        distances.setValue(i, j, prd);
+        distances.setValue(j, i, prd);
+      }
+    }
+
+    noClus = clusters.size();
+    cluster();
+  }
+
+  /**
+   * 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(BinaryNode nodei, BinaryNode nodej,
+          double dist)
+  {
+    double ih = 0;
+    double jh = 0;
+
+    BinaryNode sni = nodei;
+    BinaryNode snj = nodej;
+
+    while (sni != null)
+    {
+      ih = ih + sni.dist;
+      sni = (BinaryNode) sni.left();
+    }
+
+    while (snj != null)
+    {
+      jh = jh + snj.dist;
+      snj = (BinaryNode) snj.left();
+    }
+
+    nodei.dist = ((dist / 2) - ih);
+    nodej.dist = ((dist / 2) - jh);
+  }
+
+  /***
+   * not the right place - OH WELL!
+   */
+
+  /**
+   * 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<BinaryNode> groupNodes(float threshold)
+  {
+    List<BinaryNode> groups = new ArrayList<BinaryNode>();
+    _groupNodes(groups, getTopNode(), threshold);
+    return groups;
+  }
+
+  protected void _groupNodes(List<BinaryNode> groups, BinaryNode nd,
+          float threshold)
+  {
+    if (nd == null)
+    {
+      return;
+    }
+
+    if ((nd.height / maxheight) > threshold)
+    {
+      groups.add(nd);
+    }
+    else
+    {
+      _groupNodes(groups, nd.left(), threshold);
+      _groupNodes(groups, nd.right(), threshold);
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param nd
+   *          DOCUMENT ME!
+   * 
+   * @return DOCUMENT ME!
+   */
+  public double findHeight(BinaryNode nd)
+  {
+    if (nd == null)
+    {
+      return maxheight;
+    }
+
+    if ((nd.left() == null) && (nd.right() == null))
+    {
+      nd.height = ((BinaryNode) nd.parent()).height + nd.dist;
+
+      if (nd.height > maxheight)
+      {
+        return nd.height;
+      }
+      else
+      {
+        return maxheight;
+      }
+    }
+    else
+    {
+      if (nd.parent() != null)
+      {
+        nd.height = ((BinaryNode) nd.parent()).height + nd.dist;
+      }
+      else
+      {
+        maxheight = 0;
+        nd.height = (float) 0.0;
+      }
+
+      maxheight = findHeight((BinaryNode) (nd.left()));
+      maxheight = findHeight((BinaryNode) (nd.right()));
+    }
+
+    return maxheight;
+  }
+
+  /**
+   * Search for leaf nodes below (or at) the given node
+   * 
+   * @param top2
+   *          root node to search from
+   * 
+   * @return
+   */
+  public Vector<BinaryNode> findLeaves(BinaryNode top2)
+  {
+    Vector<BinaryNode> leaves = new Vector<BinaryNode>();
+    findLeaves(top2, 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<BinaryNode> findLeaves(BinaryNode nd, Vector<BinaryNode> 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(nd.left(), leaves);
+      findLeaves(nd.right(), leaves);
+    }
+
+    return leaves;
+  }
+
+}
index c726627..760962e 100644 (file)
@@ -22,7 +22,7 @@ package jalview.analysis;
 
 import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.SimilarityParamsI;
-import jalview.datamodel.SequenceNode;
+import jalview.datamodel.BinaryNode;
 import jalview.viewmodel.AlignmentViewport;
 
 /**
@@ -113,25 +113,25 @@ public class AverageDistanceTree extends TreeBuilder
    * {@inheritDoc}
    */
   @Override
-  protected void findNewDistances(SequenceNode nodei, SequenceNode nodej,
+  protected void findNewDistances(BinaryNode nodei, BinaryNode nodej,
           double dist)
   {
     double ih = 0;
     double jh = 0;
 
-    SequenceNode sni = nodei;
-    SequenceNode snj = nodej;
+    BinaryNode sni = nodei;
+    BinaryNode snj = nodej;
 
     while (sni != null)
     {
       ih = ih + sni.dist;
-      sni = (SequenceNode) sni.left();
+      sni = (BinaryNode) sni.left();
     }
 
     while (snj != null)
     {
       jh = jh + snj.dist;
-      snj = (SequenceNode) snj.left();
+      snj = (BinaryNode) snj.left();
     }
 
     nodei.dist = ((dist / 2) - ih);
index 522c2b1..9a39ac0 100644 (file)
@@ -22,7 +22,7 @@ package jalview.analysis;
 
 import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.SimilarityParamsI;
-import jalview.datamodel.SequenceNode;
+import jalview.datamodel.BinaryNode;
 import jalview.viewmodel.AlignmentViewport;
 
 /**
@@ -81,7 +81,7 @@ public class NJTree extends TreeBuilder
    * {@inheritDoc}
    */
   @Override
-  protected void findNewDistances(SequenceNode nodei, SequenceNode nodej,
+  protected void findNewDistances(BinaryNode nodei, BinaryNode nodej,
           double dist)
   {
     nodei.dist = ((dist + ri) - rj) / 2;
index 0601dd9..61f65ff 100644 (file)
@@ -23,56 +23,26 @@ package jalview.analysis;
 import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.SimilarityParamsI;
 import jalview.datamodel.AlignmentView;
+import jalview.datamodel.BinaryNode;
 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 abstract class TreeBuilder extends TreeEngine
 {
   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;
 
   /**
@@ -114,116 +84,6 @@ public abstract class TreeBuilder
   }
 
   /**
-   * 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
    */
@@ -247,40 +107,6 @@ public abstract class TreeBuilder
   }
 
   /**
-   * 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>
@@ -304,67 +130,9 @@ public abstract class TreeBuilder
     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>();
+    this.node = new Vector<BinaryNode>();
     if (seqView != null)
     {
       this.seqData = seqView;
@@ -398,62 +166,6 @@ public abstract class TreeBuilder
   }
 
   /**
-   * 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()
diff --git a/src/jalview/analysis/TreeEngine.java b/src/jalview/analysis/TreeEngine.java
new file mode 100644 (file)
index 0000000..daf7836
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * 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 java.util.BitSet;
+import java.util.Vector;
+
+import jalview.datamodel.BinaryNode;
+import jalview.datamodel.SequenceNode;
+import jalview.math.MatrixI;
+
+public abstract class TreeEngine
+{
+
+  protected Vector<BitSet> clusters;
+
+  protected BitSet done;
+
+  protected int noseqs;
+
+  protected int noClus;
+
+  protected MatrixI distances;
+
+  protected double ri;
+
+  protected double rj;
+
+  protected Vector<BinaryNode> node;
+
+  BinaryNode maxdist;
+
+  double maxDistValue;
+
+  protected int mini;
+
+  protected int minj;
+
+  protected BinaryNode top;
+
+  protected int ycount;
+
+  double maxheight;
+
+  /**
+   * 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;
+  }
+
+  /**
+   * Merges cluster(j) to cluster(i) and recalculates cluster and node distances
+   * 
+   * @param i
+   * @param j
+   */
+  protected 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);
+
+    BinaryNode sn = new BinaryNode();
+
+    sn.setLeft((node.elementAt(i)));
+    sn.setRight((node.elementAt(j)));
+
+    BinaryNode tmpi = (node.elementAt(i));
+    BinaryNode 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);
+  }
+
+  protected abstract void findNewDistances(BinaryNode nodei,
+          BinaryNode 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);
+
+  /**
+   * Finds the node, at or below the given node, with the maximum distance, and
+   * saves the node and the distance value
+   * 
+   * @param nd
+   */
+  protected void findMaxDist(BinaryNode 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((BinaryNode) nd.left());
+      findMaxDist((BinaryNode) nd.right());
+    }
+  }
+
+  /**
+   * Form clusters by grouping sub-clusters, starting from one sequence per
+   * cluster, and finishing when only two clusters remain
+   */
+  protected 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();
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param nd
+   *          DOCUMENT ME!
+   */
+  protected void _reCount(BinaryNode 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(nd.left());
+      _reCount((BinaryNode) nd.right());
+
+      BinaryNode l = nd.left();
+      BinaryNode r = 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!
+   * 
+   * @return DOCUMENT ME!
+   */
+  double findHeight(BinaryNode nd)
+  {
+    if (nd == null)
+    {
+      return maxheight;
+    }
+
+    if ((nd.left() == null) && (nd.right() == null))
+    {
+      nd.height = ((BinaryNode) nd.parent()).height + nd.dist;
+
+      if (nd.height > maxheight)
+      {
+        return nd.height;
+      }
+      else
+      {
+        return maxheight;
+      }
+    }
+    else
+    {
+      if (nd.parent() != null)
+      {
+        nd.height = ((BinaryNode) nd.parent()).height + nd.dist;
+      }
+      else
+      {
+        maxheight = 0;
+        nd.height = (float) 0.0;
+      }
+
+      maxheight = findHeight((BinaryNode) (nd.left()));
+      maxheight = findHeight((BinaryNode) (nd.right()));
+    }
+
+    return maxheight;
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param nd
+   *          DOCUMENT ME!
+   */
+  void reCount(BinaryNode nd)
+  {
+    ycount = 0;
+    // _lycount = 0;
+    // _lylimit = this.node.size();
+    _reCount(nd);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @return DOCUMENT ME!
+   */
+  public BinaryNode getTopNode()
+  {
+    return top;
+  }
+
+}
index 4d5e4b2..dd56424 100644 (file)
@@ -20,7 +20,6 @@
  */
 package jalview.analysis;
 
-import jalview.bin.Cache;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.BinaryNode;
 import jalview.datamodel.NodeTransformI;
@@ -51,7 +50,7 @@ public class TreeModel
 
   int noseqs;
 
-  SequenceNode top;
+  BinaryNode top;
 
   double maxDistValue;
 
@@ -59,7 +58,7 @@ public class TreeModel
 
   int ycount;
 
-  Vector<SequenceNode> node;
+  Vector<BinaryNode> node;
 
   boolean hasDistances = true; // normal case for jalview trees
 
@@ -81,7 +80,7 @@ public class TreeModel
   public TreeModel(SequenceI[] seqs, AlignmentView odata,
           NewickFile treefile)
   {
-    this(seqs, treefile.getTree(), treefile.HasDistances(),
+    this(seqs,  treefile.getTree(), treefile.HasDistances(),
             treefile.HasBootstrap(), treefile.HasRootDistance());
     seqData = odata;
 
@@ -95,7 +94,7 @@ public class TreeModel
    */
   public TreeModel(TreeBuilder tree)
   {
-    this(tree.getSequences(), tree.getTopNode(), tree.hasDistances(),
+    this(tree.getSequences(),  tree.getTopNode(), tree.hasDistances(),
             tree.hasBootstrap(), tree.hasRootDistance());
     seqData = tree.getOriginalData();
   }
@@ -109,7 +108,7 @@ public class TreeModel
    * @param hasBoot
    * @param hasRootDist
    */
-  public TreeModel(SequenceI[] seqs, SequenceNode root, boolean hasDist,
+  public TreeModel(SequenceI[] seqs, BinaryNode root, boolean hasDist,
           boolean hasBoot, boolean hasRootDist)
   {
     this.sequences = seqs;
@@ -129,7 +128,7 @@ public class TreeModel
   {
     SequenceIdMatcher algnIds = new SequenceIdMatcher(seqs);
 
-    Vector<SequenceNode> leaves = findLeaves(top);
+    Vector<BinaryNode> leaves = findLeaves(top);
 
     int i = 0;
     int namesleft = seqs.length;
@@ -141,7 +140,8 @@ public class TreeModel
     // int countOne2Many = 0;
     while (i < leaves.size())
     {
-      j = leaves.elementAt(i++);
+      // TODO - decide if we get rid of the polymorphism here ?
+      j = (SequenceNode)leaves.elementAt(i++);
       realnam = j.getName();
       nam = null;
 
@@ -206,7 +206,7 @@ public class TreeModel
    */
   public void updatePlaceHolders(List<SequenceI> list)
   {
-    Vector<SequenceNode> leaves = findLeaves(top);
+    Vector<BinaryNode> leaves = findLeaves(top);
 
     int sz = leaves.size();
     SequenceIdMatcher seqmatcher = null;
@@ -214,7 +214,7 @@ public class TreeModel
 
     while (i < sz)
     {
-      SequenceNode leaf = leaves.elementAt(i++);
+      SequenceNode leaf = (SequenceNode) leaves.elementAt(i++);
 
       if (list.contains(leaf.element()))
       {
@@ -289,15 +289,15 @@ public class TreeModel
   /**
    * Search for leaf nodes below (or at) the given node
    * 
-   * @param nd
+   * @param top2
    *          root node to search from
    * 
    * @return
    */
-  public Vector<SequenceNode> findLeaves(SequenceNode nd)
+  public Vector<BinaryNode> findLeaves(BinaryNode top2)
   {
-    Vector<SequenceNode> leaves = new Vector<SequenceNode>();
-    findLeaves(nd, leaves);
+    Vector<BinaryNode> leaves = new Vector<BinaryNode>();
+    findLeaves(top2, leaves);
     return leaves;
   }
 
@@ -311,8 +311,8 @@ public class TreeModel
    * 
    * @return Vector of leaf nodes on binary tree
    */
-  Vector<SequenceNode> findLeaves(SequenceNode nd,
-          Vector<SequenceNode> leaves)
+  Vector<BinaryNode> findLeaves(BinaryNode nd,
+          Vector<BinaryNode> leaves)
   {
     if (nd == null)
     {
@@ -332,8 +332,8 @@ public class TreeModel
        * TODO: Identify internal nodes... if (node.isSequenceLabel()) {
        * leaves.addElement(node); }
        */
-      findLeaves((SequenceNode) nd.left(), leaves);
-      findLeaves((SequenceNode) nd.right(), leaves);
+      findLeaves(nd.left(), leaves);
+      findLeaves(nd.right(), leaves);
     }
 
     return leaves;
@@ -345,7 +345,7 @@ public class TreeModel
    * @param nd
    *          SequenceNode
    */
-  void printNode(SequenceNode nd)
+  void printNode(BinaryNode nd)
   {
     if (nd == null)
     {
@@ -361,8 +361,8 @@ public class TreeModel
     else
     {
       System.out.println("Dist " + nd.dist);
-      printNode((SequenceNode) nd.left());
-      printNode((SequenceNode) nd.right());
+      printNode((BinaryNode) nd.left());
+      printNode((BinaryNode) nd.right());
     }
   }
 
@@ -388,14 +388,14 @@ public class TreeModel
    * @param threshold
    * @see #getGroups()
    */
-  public List<SequenceNode> groupNodes(float threshold)
+  public List<BinaryNode> groupNodes(float threshold)
   {
-    List<SequenceNode> groups = new ArrayList<SequenceNode>();
+    List<BinaryNode> groups = new ArrayList<BinaryNode>();
     _groupNodes(groups, getTopNode(), threshold);
     return groups;
   }
 
-  protected void _groupNodes(List<SequenceNode> groups, SequenceNode nd,
+  protected void _groupNodes(List<BinaryNode> groups, BinaryNode nd,
           float threshold)
   {
     if (nd == null)
@@ -422,7 +422,7 @@ public class TreeModel
    * 
    * @return DOCUMENT ME!
    */
-  public double findHeight(SequenceNode nd)
+  public double findHeight(BinaryNode nd)
   {
     if (nd == null)
     {
@@ -431,7 +431,7 @@ public class TreeModel
 
     if ((nd.left() == null) && (nd.right() == null))
     {
-      nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
+      nd.height = ((BinaryNode) nd.parent()).height + nd.dist;
 
       if (nd.height > maxheight)
       {
@@ -446,7 +446,7 @@ public class TreeModel
     {
       if (nd.parent() != null)
       {
-        nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
+        nd.height = ((BinaryNode) nd.parent()).height + nd.dist;
       }
       else
       {
@@ -454,8 +454,8 @@ public class TreeModel
         nd.height = (float) 0.0;
       }
 
-      maxheight = findHeight((SequenceNode) (nd.left()));
-      maxheight = findHeight((SequenceNode) (nd.right()));
+      maxheight = findHeight((BinaryNode) (nd.left()));
+      maxheight = findHeight((BinaryNode) (nd.right()));
     }
 
     return maxheight;
@@ -467,7 +467,7 @@ public class TreeModel
    * @param nd
    *          DOCUMENT ME!
    */
-  void printN(SequenceNode nd)
+  void printN(BinaryNode nd)
   {
     if (nd == null)
     {
@@ -476,8 +476,8 @@ public class TreeModel
 
     if ((nd.left() != null) && (nd.right() != null))
     {
-      printN((SequenceNode) nd.left());
-      printN((SequenceNode) nd.right());
+      printN((BinaryNode) nd.left());
+      printN((BinaryNode) nd.right());
     }
     else
     {
@@ -494,7 +494,7 @@ public class TreeModel
    * @param nd
    *          DOCUMENT ME!
    */
-  public void reCount(SequenceNode nd)
+  public void reCount(BinaryNode nd)
   {
     ycount = 0;
     // _lycount = 0;
@@ -510,7 +510,7 @@ public class TreeModel
    * @param nd
    *          DOCUMENT ME!
    */
-  void _reCount(SequenceNode nd)
+  void _reCount(BinaryNode nd)
   {
     // if (_lycount<_lylimit)
     // {
@@ -526,11 +526,11 @@ public class TreeModel
     if ((nd.left() != null) && (nd.right() != null))
     {
 
-      _reCount((SequenceNode) nd.left());
-      _reCount((SequenceNode) nd.right());
+      _reCount((BinaryNode) nd.left());
+      _reCount((BinaryNode) nd.right());
 
-      SequenceNode l = (SequenceNode) nd.left();
-      SequenceNode r = (SequenceNode) nd.right();
+      BinaryNode l = (BinaryNode) nd.left();
+      BinaryNode r = (BinaryNode) nd.right();
 
       nd.count = l.count + r.count;
       nd.ycount = (l.ycount + r.ycount) / 2;
@@ -549,14 +549,14 @@ public class TreeModel
    * @param nd
    *          DOCUMENT ME!
    */
-  public void swapNodes(SequenceNode nd)
+  public void swapNodes(BinaryNode nd)
   {
     if (nd == null)
     {
       return;
     }
 
-    SequenceNode tmp = (SequenceNode) nd.left();
+    BinaryNode tmp = (BinaryNode) nd.left();
 
     nd.setLeft(nd.right());
     nd.setRight(tmp);
@@ -570,7 +570,7 @@ public class TreeModel
    * @param dir
    *          DOCUMENT ME!
    */
-  void changeDirection(SequenceNode nd, SequenceNode dir)
+  void changeDirection(BinaryNode nd, BinaryNode dir)
   {
     if (nd == null)
     {
@@ -579,9 +579,9 @@ public class TreeModel
 
     if (nd.parent() != top)
     {
-      changeDirection((SequenceNode) nd.parent(), nd);
+      changeDirection((BinaryNode) nd.parent(), nd);
 
-      SequenceNode tmp = (SequenceNode) nd.parent();
+      BinaryNode tmp = (BinaryNode) nd.parent();
 
       if (dir == nd.left())
       {
@@ -630,7 +630,7 @@ public class TreeModel
    * 
    * @return DOCUMENT ME!
    */
-  public SequenceNode getTopNode()
+  public BinaryNode getTopNode()
   {
     return top;
   }
@@ -665,7 +665,7 @@ public class TreeModel
    */
   public void applyToNodes(NodeTransformI nodeTransformI)
   {
-    for (Enumeration<SequenceNode> nodes = node.elements(); nodes
+    for (Enumeration<BinaryNode> nodes = node.elements(); nodes
             .hasMoreElements(); nodeTransformI
                     .transform(nodes.nextElement()))
     {
index b09538e..03efec5 100644 (file)
@@ -28,6 +28,7 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.ProfilesI;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceCollectionI;
@@ -555,4 +556,6 @@ public interface AlignViewportI extends ViewStyleI
    * @return
    */
   Iterator<int[]> getViewAsVisibleContigs(boolean selectedRegionOnly);
+
+  ContactMatrixI getContactMatrix(AlignmentAnnotation alignmentAnnotation);
 }
index 2e5f938..8c3e39a 100755 (executable)
@@ -23,6 +23,7 @@ package jalview.appletgui;
 import jalview.analysis.Conservation;
 import jalview.analysis.TreeModel;
 import jalview.api.AlignViewportI;
+import jalview.datamodel.BinaryNode;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -86,7 +87,7 @@ public class TreeCanvas extends Panel
 
   Hashtable nodeHash = new Hashtable();
 
-  SequenceNode highlightNode;
+  BinaryNode highlightNode;
 
   AlignmentPanel ap;
 
@@ -122,15 +123,15 @@ public class TreeCanvas extends Panel
     tree2.findHeight(tree2.getTopNode());
 
     // Now have to calculate longest name based on the leaves
-    Vector<SequenceNode> leaves = tree2.findLeaves(tree2.getTopNode());
+    Vector<BinaryNode> leaves = tree2.findLeaves(tree2.getTopNode());
     boolean has_placeholders = false;
     longestName = "";
 
     for (int i = 0; i < leaves.size(); i++)
     {
-      SequenceNode lf = leaves.elementAt(i);
+      BinaryNode lf = leaves.elementAt(i);
 
-      if (lf.isPlaceholder())
+      if (lf instanceof SequenceNode && ((SequenceNode)lf).isPlaceholder())
       {
         has_placeholders = true;
       }
@@ -146,7 +147,7 @@ public class TreeCanvas extends Panel
     setMarkPlaceholders(has_placeholders);
   }
 
-  public void drawNode(Graphics g, SequenceNode node, float chunk,
+  public void drawNode(Graphics g, BinaryNode node, float chunk,
           double scale, int width, int offx, int offy)
   {
     if (node == null)
@@ -210,7 +211,7 @@ public class TreeCanvas extends Panel
         g.drawString(nodeLabel, xstart + 2, ypos - 2);
       }
 
-      String name = (markPlaceholders && node.isPlaceholder())
+      String name = (markPlaceholders && node instanceof SequenceNode && ((SequenceNode) node).isPlaceholder())
               ? (PLACEHOLDER + node.getName())
               : node.getName();
       FontMetrics fm = g.getFontMetrics(font);
@@ -237,9 +238,9 @@ public class TreeCanvas extends Panel
     }
     else
     {
-      drawNode(g, (SequenceNode) node.left(), chunk, scale, width, offx,
+      drawNode(g, (BinaryNode) node.left(), chunk, scale, width, offx,
               offy);
-      drawNode(g, (SequenceNode) node.right(), chunk, scale, width, offx,
+      drawNode(g, (BinaryNode) node.right(), chunk, scale, width, offx,
               offy);
 
       double height = node.height;
@@ -263,9 +264,9 @@ public class TreeCanvas extends Panel
       }
 
       int ystart = (int) (node.left() == null ? 0
-              : (((SequenceNode) node.left()).ycount * chunk)) + offy;
+              : (((BinaryNode) node.left()).ycount * chunk)) + offy;
       int yend = (int) (node.right() == null ? 0
-              : (((SequenceNode) node.right()).ycount * chunk)) + offy;
+              : (((BinaryNode) node.right()).ycount * chunk)) + offy;
 
       Rectangle pos = new Rectangle(xend - 2, ypos - 2, 5, 5);
       nodeHash.put(node, pos);
@@ -338,20 +339,20 @@ public class TreeCanvas extends Panel
     int width = getSize().width;
     int height = getSize().height;
 
-    SequenceNode top = tree.getTopNode();
+    BinaryNode top = tree.getTopNode();
 
     double wscale = (float) (width * .8 - offx * 2) / tree.getMaxHeight();
     if (top.count == 0)
     {
-      top.count = ((SequenceNode) top.left()).count
-              + ((SequenceNode) top.right()).count;
+      top.count = ((BinaryNode) top.left()).count
+              + ((BinaryNode) top.right()).count;
     }
     float chunk = (float) (height - offy) / top.count;
 
     pickNode(pickBox, top, chunk, wscale, width, offx, offy);
   }
 
-  public void pickNode(Rectangle pickBox, SequenceNode node, float chunk,
+  public void pickNode(Rectangle pickBox, BinaryNode node, float chunk,
           double scale, int width, int offx, int offy)
   {
     if (node == null)
@@ -384,14 +385,14 @@ public class TreeCanvas extends Panel
     }
     else
     {
-      pickNode(pickBox, (SequenceNode) node.left(), chunk, scale, width,
+      pickNode(pickBox, (BinaryNode) node.left(), chunk, scale, width,
               offx, offy);
-      pickNode(pickBox, (SequenceNode) node.right(), chunk, scale, width,
+      pickNode(pickBox, (BinaryNode) node.right(), chunk, scale, width,
               offx, offy);
     }
   }
 
-  public void setColor(SequenceNode node, Color c)
+  public void setColor(BinaryNode node, Color c)
   {
     if (node == null)
     {
@@ -410,8 +411,8 @@ public class TreeCanvas extends Panel
     else
     {
       node.color = c;
-      setColor((SequenceNode) node.left(), c);
-      setColor((SequenceNode) node.right(), c);
+      setColor((BinaryNode) node.left(), c);
+      setColor((BinaryNode) node.right(), c);
     }
   }
 
@@ -469,12 +470,12 @@ public class TreeCanvas extends Panel
 
     double wscale = (width - labelLength - offx * 2) / tree.getMaxHeight();
 
-    SequenceNode top = tree.getTopNode();
+    BinaryNode top = tree.getTopNode();
 
     if (top.count == 0)
     {
-      top.count = ((SequenceNode) top.left()).count
-              + ((SequenceNode) top.right()).count;
+      top.count = ((BinaryNode) top.left()).count
+              + ((BinaryNode) top.right()).count;
     }
     float chunk = (float) (height - offy) / top.count;
 
@@ -527,7 +528,7 @@ public class TreeCanvas extends Panel
       }
       else
       {
-        Vector<SequenceNode> leaves = tree.findLeaves(highlightNode);
+        Vector<BinaryNode> leaves = tree.findLeaves(highlightNode);
 
         for (int i = 0; i < leaves.size(); i++)
         {
@@ -554,9 +555,9 @@ public class TreeCanvas extends Panel
 
     Object ob = findElement(evt.getX(), evt.getY());
 
-    if (ob instanceof SequenceNode)
+    if (ob instanceof BinaryNode)
     {
-      highlightNode = (SequenceNode) ob;
+      highlightNode = (BinaryNode) ob;
       repaint();
     }
     else
@@ -596,7 +597,7 @@ public class TreeCanvas extends Panel
         threshold = (float) (x - offx)
                 / (float) (getSize().width - labelLength - 2 * offx);
 
-        List<SequenceNode> groups = tree.groupNodes(threshold);
+        List<BinaryNode> groups = tree.groupNodes(threshold);
         setColor(tree.getTopNode(), Color.black);
 
         av.setSelectionGroup(null);
@@ -620,7 +621,7 @@ public class TreeCanvas extends Panel
 
   }
 
-  void colourGroups(List<SequenceNode> groups)
+  void colourGroups(List<BinaryNode> groups)
   {
     for (int i = 0; i < groups.size(); i++)
     {
@@ -629,7 +630,7 @@ public class TreeCanvas extends Panel
               (int) (Math.random() * 255), (int) (Math.random() * 255));
       setColor(groups.get(i), col.brighter());
 
-      Vector<SequenceNode> l = tree.findLeaves(groups.get(i));
+      Vector<BinaryNode> l = tree.findLeaves(groups.get(i));
 
       Vector<SequenceI> sequences = new Vector<>();
       for (int j = 0; j < l.size(); j++)
index 7f97f33..517a6dd 100755 (executable)
@@ -2047,9 +2047,23 @@ public class Alignment implements AlignmentI, AutoCloseable
   }
 
   @Override
-  public ContactMatrixI getContactMatrixFor(AlignmentAnnotation ann)
+  public ContactMatrixI getContactMatrixFor(AlignmentAnnotation _aa)
   {
-    return cmholder.getContactMatrixFor(ann);
+    ContactMatrixI cm = cmholder.getContactMatrixFor(_aa);
+    if (cm==null && _aa.groupRef!=null)
+    {
+      cm = _aa.groupRef.getContactMatrixFor(_aa);
+    }
+    if (cm==null && _aa.sequenceRef!=null)
+    {
+      cm = _aa.sequenceRef.getContactMatrixFor(_aa);
+      if (cm==null)
+      {
+        // TODO fix up this logic and unify with getContactListFor
+        cm = _aa.sequenceRef.getDatasetSequence().getContactMatrixFor(_aa);
+      }
+    }
+    return cm;
   }
 
   @Override
@@ -2066,10 +2080,10 @@ public class Alignment implements AlignmentI, AutoCloseable
       if (spos >= _aa.sequenceRef.getStart()
               && spos <= 1 + _aa.sequenceRef.getEnd())
       {
-        cl = _aa.sequenceRef.getContactListFor(_aa, spos);
+        cl = _aa.sequenceRef.getContactListFor(_aa, spos-_aa.sequenceRef.getStart());
         if (cl == null && _aa.sequenceRef.getDatasetSequence() != null)
         {
-          _aa.sequenceRef.getDatasetSequence().getContactListFor(_aa, spos);
+          _aa.sequenceRef.getDatasetSequence().getContactListFor(_aa, spos-_aa.sequenceRef.getStart());
         }
       }
     }
index c0ff0e4..5b55594 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.datamodel;
 
+import java.awt.Color;
+
 /**
  * DOCUMENT ME!
  * 
@@ -38,9 +40,27 @@ public class BinaryNode
 
   BinaryNode parent;
 
-  /** DOCUMENT ME!! */
+  /** Bootstrap value */
   public int bootstrap;
 
+  /** DOCUMENT ME!! */
+  public double dist;
+
+  /** DOCUMENT ME!! */
+  public int count;
+
+  /** DOCUMENT ME!! */
+  public double height;
+
+  /** DOCUMENT ME!! */
+  public float ycount;
+
+  /** DOCUMENT ME!! */
+  public Color color = Color.black;
+
+  /** DOCUMENT ME!! */
+  public boolean dummy = false;
+
   /**
    * Creates a new BinaryNode object.
    */
@@ -48,6 +68,7 @@ public class BinaryNode
   {
     left = right = parent = null;
     bootstrap = 0;
+    dist = 0;
   }
 
   /**
@@ -60,13 +81,28 @@ public class BinaryNode
    * @param name
    *          DOCUMENT ME!
    */
-  public BinaryNode(Object element, BinaryNode parent, String name)
+  public BinaryNode(Object element, BinaryNode parent, String name,
+          double dist)
   {
+    this();
     this.element = element;
     this.parent = parent;
     this.name = name;
+    this.dist = dist;
+  }
+
+  public BinaryNode(Object element, BinaryNode parent, String name,
+          double dist, int bootstrap)
+  {
+    this(element, parent, name, dist);
+    this.bootstrap = bootstrap;
+  }
 
-    left = right = null;
+  public BinaryNode(Object val, BinaryNode parent, String name, double dist,
+          int bootstrap, boolean dummy)
+  {
+    this(val, parent, name, dist, bootstrap);
+    this.dummy = dummy;
   }
 
   /**
@@ -300,4 +336,45 @@ public class BinaryNode
   {
     return bootstrap;
   }
+
+  /**
+   * @param dummy
+   *          true if node is created for the representation of polytomous trees
+   */
+  public boolean isDummy()
+  {
+    return dummy;
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param newstate
+   *          DOCUMENT ME!
+   * 
+   * @return DOCUMENT ME!
+   */
+  public boolean setDummy(boolean newstate)
+  {
+    boolean oldstate = dummy;
+    dummy = newstate;
+
+    return oldstate;
+  }
+
+  /**
+   * ascends the tree but doesn't stop until a non-dummy node is discovered.
+   * 
+   */
+  public BinaryNode AscendTree()
+  {
+    BinaryNode c = this;
+
+    do
+    {
+      c = c.parent();
+    } while ((c != null) && c.dummy);
+
+    return c;
+  }
 }
index beb557f..8e806e4 100644 (file)
@@ -41,6 +41,7 @@ public class ContactListImpl implements ContactListI
   @Override
   public ContactRange getRangeFor(int from_column, int to_column)
   {
+    // TODO: consider caching ContactRange for a particular call ?
     if (clist instanceof ContactListI)
     {
       // clist may implement getRangeFor in a more efficient way, so use theirs
index a555a17..296feaf 100644 (file)
@@ -72,8 +72,15 @@ public class ContactMapHolder implements ContactMapHolderI
     annotation.editable = false;
     annotation.graph = AlignmentAnnotation.CONTACT_MAP;
     annotation.calcId = cm.getType();
-    annotation.label = cm.getAnnotLabel();
-    annotation.description = cm.getAnnotDescr();
+    if (annotation.label == null || "".equals(annotation.label))
+    {
+      annotation.label = cm.getAnnotLabel();
+
+    }
+    if (annotation.description == null || "".equals(annotation.description))
+    {
+      annotation.description = cm.getAnnotDescr();
+    }
     contactmaps.put(annotation.annotationId, cm);
   }
 }
index ba23e67..342abf8 100644 (file)
@@ -6,10 +6,13 @@ public interface ContactMapHolderI
 {
   /**
    * resolve a contact list instance (if any) associated with the annotation row
-   * and column position
+   * and column position Columns of ContactMap are indexed relative to context
+   * object (columns of alignment, positions on sequence relative to
+   * sequence.getStart())
    * 
    * @param _aa
    * @param column
+   *          - base 0 column index
    * @return
    */
   ContactListI getContactListFor(AlignmentAnnotation _aa, int column);
index 25aefd3..8434b4a 100644 (file)
@@ -1,6 +1,9 @@
 package jalview.datamodel;
 
+import java.awt.Color;
 import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashMap;
 import java.util.List;
 import java.util.StringTokenizer;
 
@@ -170,6 +173,63 @@ public abstract class ContactMatrix implements ContactMatrixI
     return "Contact Matrix";
   }
 
+  List<BitSet> groups = null;
+
+  @Override
+  public void updateGroups(List<BitSet> colGroups)
+  {
+    groups = colGroups;
+    colorMap = new HashMap<>();
+  }
+
+  @Override
+  public boolean hasGroups()
+  {
+    return groups != null && groups.size() > 0;
+  }
+
+  @Override
+  public List<BitSet> getGroups()
+  {
+    return groups;
+  }
+
+  @Override
+  public BitSet getGroupsFor(int column)
+  {
+    for (BitSet gp : groups)
+    {
+      if (gp.get(column))
+      {
+        return gp;
+      }
+    }
+    return ContactMatrixI.super.getGroupsFor(column);
+  }
+
+  HashMap<BitSet, Color> colorMap = new HashMap<>();
+
+  @Override
+  public Color getColourForGroup(BitSet bs)
+  {
+    if (bs == null)
+    {
+      return Color.white;
+    }
+    Color groupCol = colorMap.get(bs);
+    if (groupCol == null)
+    {
+      return Color.white;
+    }
+    return groupCol;
+  }
+
+  @Override
+  public void setColorForGroup(BitSet bs, Color color)
+  {
+    colorMap.put(bs, color);
+  }
+
   public static String contactToFloatString(ContactMatrixI cm)
   {
     StringBuilder sb = new StringBuilder();
index bac3abf..3510ed1 100644 (file)
@@ -1,5 +1,10 @@
 package jalview.datamodel;
 
+import java.awt.Color;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.List;
+
 public interface ContactMatrixI
 {
 
@@ -28,5 +33,47 @@ public interface ContactMatrixI
   int getWidth();
 
   int getHeight();
+  
+  default boolean hasGroups() {
+    return false;
+  }
+  default BitSet getGroupsFor(int column) {
+    BitSet colbitset  = new BitSet();
+    colbitset.set(column);
+    return colbitset;
+  }
+
+  default List<BitSet> getGroups() {
+    return Arrays.asList();
+  }
+
+  default boolean hasTree() {
+    return false;
+  }
+
+  /**
+   * Newick representation of clustered matrix
+   * @return null unless hasTree is true
+   */
+  default String getNewick() {
+    return null;
+  }
+
+  default String getTreeMethod() {
+    return null;
+  }
+
+  default boolean hasCutHeight() {
+    return false;
+  }
+
+  default double getCutHeight() {
+    return 0;
+  }
+
+  void updateGroups(List<BitSet> colGroups);
+
+  void setColorForGroup(BitSet bs, Color color);
 
+  default Color getColourForGroup(BitSet bs) { return Color.white;};
 }
index e8424ea..e37a5b2 100644 (file)
@@ -1,5 +1,10 @@
 package jalview.datamodel;
 
+import java.awt.Color;
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.List;
+
 /**
  * Dummy contact matrix based on sequence distance
  * 
@@ -119,4 +124,40 @@ public class SeqDistanceContactMatrix implements ContactMatrixI
   {
     return width;
   }
+  private List<BitSet> groups=null;
+  @Override
+  public void updateGroups(List<BitSet> colGroups)
+  {
+    groups = colGroups;
+  }
+  @Override
+  public boolean hasGroups()
+  {
+    return groups!=null;
+  }
+  @Override
+  public List<BitSet> getGroups()
+  {
+    return groups;
+  }  
+
+  HashMap<BitSet,Color> colorMap = new HashMap<>();
+  @Override 
+  public Color getColourForGroup(BitSet bs)
+  {
+    if (bs==null) {
+      return Color.white;
+    }
+    Color groupCol=colorMap.get(bs);
+    if (groupCol==null)
+    {
+      return Color.white;
+    }
+    return groupCol;
+  }
+  @Override 
+  public void setColorForGroup(BitSet bs,Color color)
+  {
+    colorMap.put(bs,color);
+  }
 }
index 0a694c2..010d4aa 100755 (executable)
@@ -20,8 +20,6 @@
  */
 package jalview.datamodel;
 
-import java.awt.Color;
-
 /**
  * DOCUMENT ME!
  * 
@@ -30,24 +28,6 @@ import java.awt.Color;
  */
 public class SequenceNode extends BinaryNode
 {
-  /** DOCUMENT ME!! */
-  public double dist;
-
-  /** DOCUMENT ME!! */
-  public int count;
-
-  /** DOCUMENT ME!! */
-  public double height;
-
-  /** DOCUMENT ME!! */
-  public float ycount;
-
-  /** DOCUMENT ME!! */
-  public Color color = Color.black;
-
-  /** DOCUMENT ME!! */
-  public boolean dummy = false;
-
   private boolean placeholder = false;
 
   /**
@@ -58,57 +38,22 @@ public class SequenceNode extends BinaryNode
     super();
   }
 
-  /**
-   * Creates a new SequenceNode object.
-   * 
-   * @param val
-   *          DOCUMENT ME!
-   * @param parent
-   *          DOCUMENT ME!
-   * @param dist
-   *          DOCUMENT ME!
-   * @param name
-   *          DOCUMENT ME!
-   */
-  public SequenceNode(Object val, SequenceNode parent, double dist,
-          String name)
+  public SequenceNode(SequenceI val, BinaryNode parent, String name,
+          double dist, int bootstrap, boolean dummy)
   {
-    super(val, parent, name);
-    this.dist = dist;
+    super(val, parent, name, dist, bootstrap, dummy);
   }
 
-  /**
-   * Creates a new SequenceNode object.
-   * 
-   * @param val
-   *          DOCUMENT ME!
-   * @param parent
-   *          DOCUMENT ME!
-   * @param name
-   *          DOCUMENT ME!
-   * @param dist
-   *          DOCUMENT ME!
-   * @param bootstrap
-   *          DOCUMENT ME!
-   * @param dummy
-   *          DOCUMENT ME!
-   */
-  public SequenceNode(Object val, SequenceNode parent, String name,
-          double dist, int bootstrap, boolean dummy)
+  public SequenceNode(SequenceI element, BinaryNode parent, String name,
+          double dist, int bootstrap)
   {
-    super(val, parent, name);
-    this.dist = dist;
-    this.bootstrap = bootstrap;
-    this.dummy = dummy;
+    super(element, parent, name, dist, bootstrap);
   }
 
-  /**
-   * @param dummy
-   *          true if node is created for the representation of polytomous trees
-   */
-  public boolean isDummy()
+  public SequenceNode(SequenceI element, BinaryNode parent, String name,
+          double dist)
   {
-    return dummy;
+    super(element, parent, name, dist);
   }
 
   /*
@@ -123,22 +68,6 @@ public class SequenceNode extends BinaryNode
   /**
    * DOCUMENT ME!
    * 
-   * @param newstate
-   *          DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
-  public boolean setDummy(boolean newstate)
-  {
-    boolean oldstate = dummy;
-    dummy = newstate;
-
-    return oldstate;
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
    * @param Placeholder
    *          DOCUMENT ME!
    */
@@ -148,23 +77,6 @@ public class SequenceNode extends BinaryNode
   }
 
   /**
-   * ascends the tree but doesn't stop until a non-dummy node is discovered.
-   * This will probably break if the tree is a mixture of BinaryNodes and
-   * SequenceNodes.
-   */
-  public SequenceNode AscendTree()
-  {
-    SequenceNode c = this;
-
-    do
-    {
-      c = (SequenceNode) c.parent();
-    } while ((c != null) && c.dummy);
-
-    return c;
-  }
-
-  /**
    * test if this node has a name that might be a label rather than a bootstrap
    * value
    * 
index 7b310b1..2d02e79 100644 (file)
@@ -155,6 +155,7 @@ import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.ViewportRanges;
 import jalview.ws.DBRefFetcher;
 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
+import jalview.ws.datamodel.alphafold.PAEContactMatrix;
 import jalview.ws.jws1.Discoverer;
 import jalview.ws.jws2.Jws2Discoverer;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
@@ -2635,6 +2636,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     viewport.invertColumnSelection();
     alignPanel.paintAlignment(true, false);
+    PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
 
@@ -4131,6 +4133,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     return showNewickTree(nf, treeTitle, null, w, h, x, y);
   }
 
+
   /**
    * Add a treeviewer for the tree extracted from a Newick file object to the
    * current alignment view
@@ -4181,6 +4184,56 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     return tp;
   }
 
+
+  public void showContactMapTree(AlignmentAnnotation aa,
+          PAEContactMatrix cm)
+  {
+    int x = 4, y = 5;
+    int w = 400, h = 500;
+    
+    try
+    {
+      NewickFile fin = new NewickFile(
+              new FileParse(cm.getNewick(), DataSourceType.PASTE));
+      String title = "PAE Matrix Tree for "
+              + cm.getReferenceSeq().getDisplayId(false);
+
+      showColumnWiseTree(fin, aa, title, w,h, x,y);
+    } catch (Throwable xx)
+    {
+      Console.error("Unexpected exception showing tree for contact matrix",
+              xx);
+    }
+  }
+  public TreePanel showColumnWiseTree(NewickFile nf, AlignmentAnnotation aa, String treeTitle,
+           int w, int h, int x, int y)
+  {
+      try
+      {
+        nf.parse();
+        if (nf.getTree() == null)
+        {
+          return null;
+        }
+        TreePanel tp = new TreePanel(alignPanel, nf, aa, title);
+
+        tp.setSize(w, h);
+
+        if (x > 0 && y > 0)
+        {
+          tp.setLocation(x, y);
+        }
+
+        Desktop.addInternalFrame(tp, title, w, h);
+        return tp;
+      } catch (Throwable xx)
+      {
+        Console.error("Unexpected exception showing tree for contact matrix",
+                xx);
+      }
+      return null;
+  }
+  
   private boolean buildingMenu = false;
 
   /**
@@ -5930,6 +5983,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     return lastFeatureSettingsBounds;
   }
+
 }
 
 class PrintThread extends Thread
index 804ab7b..52a6066 100755 (executable)
@@ -36,6 +36,7 @@ import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
 import java.awt.geom.AffineTransform;
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Iterator;
@@ -50,18 +51,23 @@ import javax.swing.ToolTipManager;
 
 import jalview.analysis.AlignSeq;
 import jalview.analysis.AlignmentUtils;
+import jalview.bin.Console;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
 import jalview.io.FileFormat;
 import jalview.io.FormatAdapter;
+import jalview.io.NewickFile;
 import jalview.util.Comparison;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.ws.datamodel.alphafold.PAEContactMatrix;
 
 /**
  * The panel that holds the labels for alignment annotations, providing
@@ -416,6 +422,31 @@ public class AnnotationLabels extends JPanel
         consclipbrd.addActionListener(this);
         pop.add(consclipbrd);
       }
+       if (aa[selectedRow].graph == AlignmentAnnotation.CONTACT_MAP
+              && PAEContactMatrix.PAEMATRIX
+                      .equals(aa[selectedRow].getCalcId()))
+      {
+        final PAEContactMatrix cm = (PAEContactMatrix) av
+                .getContactMatrix(aa[selectedRow]);
+        if (cm!=null && cm.getNewick()!=null && cm.getNewick().length()>0)
+        {
+          item = new JMenuItem("Show Tree for Matrix");
+          item.addActionListener(new ActionListener()
+          {
+
+            @Override
+            public void actionPerformed(ActionEvent e)
+            {
+
+                ap.alignFrame.showContactMapTree(aa[selectedRow],cm);
+
+            }
+          });
+          pop.addSeparator();
+          pop.add(item);
+        }
+
+      }
     }
     pop.show(this, evt.getX(), evt.getY());
   }
@@ -1056,6 +1087,7 @@ public class AnnotationLabels extends JPanel
     g.translate(0, getScrollOffset());
     g.setColor(Color.black);
     SequenceI lastSeqRef = null;
+    String lastLabel = null;
     AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
     int fontHeight = g.getFont().getSize();
     int y = 0;
@@ -1080,6 +1112,7 @@ public class AnnotationLabels extends JPanel
     {
       hasHiddenRows = false;
       int olY = 0;
+      int nexAA = 0;
       for (int i = 0; i < aa.length; i++)
       {
         visible = true;
@@ -1089,6 +1122,9 @@ public class AnnotationLabels extends JPanel
           continue;
         }
         olY = y;
+        // look ahead to next annotation
+        for (nexAA=i+1; nexAA<aa.length && !aa[nexAA].visible; nexAA++)
+          ;
         y += aa[i].height;
         if (clip)
         {
@@ -1136,6 +1172,24 @@ public class AnnotationLabels extends JPanel
         }
         String label = aa[i].label;
         boolean vertBar = false;
+        if ((lastLabel != null && lastLabel.equals(label)))
+        {
+          label = aa[i].description;
+        }
+        else
+        {
+          if (nexAA < aa.length && label.equals(aa[nexAA].label)) // &&
+                                                                  // aa[nexY].sequenceRef==aa[i].sequenceRef)
+          {
+            lastLabel = label;
+            // next label is the same as this label
+            label = aa[i].description;
+          }
+          else
+          {
+            lastLabel = label;
+          }
+        }
         if (aa[i].sequenceRef != null)
         {
           if (aa[i].sequenceRef != lastSeqRef)
@@ -1219,8 +1273,8 @@ public class AnnotationLabels extends JPanel
         {
           if (vertBar)
           {
-            g.drawLine(20, y + offset, 20, y - aa[i].height);
-            g.drawLine(20, y + offset, x - 20, y + offset);
+            g.drawLine(width-3, y + offset-fontHeight, width-3, (int)(y - 1.5*aa[i].height-offset-fontHeight));
+            // g.drawLine(20, y + offset, x - 20, y + offset);
 
           }
           g.drawString(label, x, y + offset);
index b68ff01..eeda585 100755 (executable)
@@ -41,6 +41,7 @@ import java.awt.event.MouseWheelListener;
 import java.awt.image.BufferedImage;
 import java.beans.PropertyChangeEvent;
 import java.util.ArrayList;
+import java.util.BitSet;
 import java.util.Collections;
 import java.util.List;
 
@@ -56,6 +57,7 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.ContactRange;
 import jalview.datamodel.GraphLine;
 import jalview.datamodel.HiddenColumns;
@@ -599,79 +601,157 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
           firstDragX = mouseDragLastX;
           firstDragY = mouseDragLastY;
         }
-        else
+      }
+    }
+    else
+    {
+      // no row (or row that can be adjusted) was pressed. Simulate a ruler click
+      ap.getScalePanel().mousePressed(evt);
+    }
+  }
+
+  /**
+   * checks whether the annotation row under the mouse click evt's handles the
+   * event
+   * 
+   * @param evt
+   * @return false if evt was not handled
+   */
+  boolean matrix_clicked(MouseEvent evt)
+  {
+    int[] rowIndex = getRowIndexAndOffset(evt.getY(),
+            av.getAlignment().getAlignmentAnnotation());
+    if (rowIndex == null)
+    {
+      jalview.bin.Console
+              .error("IMPLEMENTATION ERROR: matrix click out of range.");
+      return false;
+    }
+    int yOffset = rowIndex[1];
+
+    AlignmentAnnotation clicked = av.getAlignment()
+            .getAlignmentAnnotation()[rowIndex[0]];
+    if (clicked.graph != AlignmentAnnotation.CONTACT_MAP)
+    {
+      return false;
+    }
+
+    // TODO - use existing threshold to select related sections of matrix
+    GraphLine thr = clicked.getThreshold();
+
+    int currentX = getColumnForXPos(evt.getX());
+    ContactListI forCurrentX = av.getContactList(clicked, currentX);
+    if (forCurrentX != null)
+    {
+      ContactGeometry cXcgeom = new ContactGeometry(forCurrentX,
+              clicked.graphHeight);
+      ContactGeometry.contactInterval cXci = cXcgeom.mapFor(yOffset,
+              yOffset);
+      /**
+       * start and end range corresponding to the row range under the mouse at
+       * column currentX
+       */
+      int fr, to;
+      fr = Math.min(cXci.cStart, cXci.cEnd);
+      to = Math.max(cXci.cStart, cXci.cEnd);
+
+      if (evt.isControlDown())
+      {
+        ContactMatrixI matrix = av.getContactMatrix(clicked);
+
+        if (matrix != null)
         {
-          GraphLine thr = aa[graphStretch].getThreshold();
-          int currentX = getColumnForXPos(evt.getX());
-          ContactListI forCurrentX = av.getContactList(aa[graphStretch],
-                  currentX);
-          if (forCurrentX != null)
+          // simplest approach is to select all group containing column
+          if (matrix.hasGroups())
           {
-            ContactGeometry cXcgeom = new ContactGeometry(forCurrentX,
-                    aa[graphStretch].graphHeight);
-            ContactGeometry.contactInterval cXci = cXcgeom.mapFor(yOffset,
-                    yOffset);
-            int fr, to;
-            fr = Math.min(cXci.cStart, cXci.cEnd);
-            to = Math.max(cXci.cStart, cXci.cEnd);
-            // select corresponding range in segment under mouse
+            SequenceI rseq = clicked.sequenceRef;
+            BitSet grp = matrix.getGroupsFor(currentX);
+            for (int c = fr; c <= to; c++)
             {
-              for (int c = fr; c <= to; c++)
-              {
-                av.getColumnSelection().addElement(c);
-              }
-              av.getColumnSelection().addElement(currentX);
+              BitSet additionalGrp = matrix.getGroupsFor(c);
+              grp.or(additionalGrp);
             }
-            // PAE SPECIFIC
-            // and also select everything lower than the max range adjacent
-            // (kind of works)
-            if (PAEContactMatrix.PAEMATRIX.equals(aa[graphStretch].getCalcId()))
+            HiddenColumns hc = av.getAlignment().getHiddenColumns();
+            for (int p = grp.nextSetBit(0); p >= 0; p = grp
+                    .nextSetBit(p + 1))
             {
-              int c = fr - 1;
-              ContactRange cr = forCurrentX.getRangeFor(fr, to);
-              double cval;
-              // TODO: could use GraphLine instead of arbitrary picking
-              // TODO: could report mean/median/variance for partitions (contiguous selected vs unselected regions and inter-contig regions)
-              // controls feathering - what other elements in row/column should we select
-              double thresh=cr.getMean()+(cr.getMax()-cr.getMean())*.15;
-              while (c > 0)
-              {
-                cval = forCurrentX.getContactAt(c);
-                if (// cr.getMin() <= cval &&
-                cval <= thresh)
-                {
-                  av.getColumnSelection().addElement(c--);
-                }
-                else
-                {
-                  break;
-                }
-              }
-              c = to;
-              while (c < forCurrentX.getContactHeight())
+              int offp = (rseq != null)
+                      ? rseq.findIndex(rseq.getStart() - 1 + p)
+                      : p;
+
+              if (!av.hasHiddenColumns() || hc.isVisible(offp))
               {
-                cval = forCurrentX.getContactAt(c);
-                if (// cr.getMin() <= cval &&
-                cval <= thresh)
-                {
-                  av.getColumnSelection().addElement(c++);
-                }
-                else
-                {
-                  break;
-                }
+                av.getColumnSelection().addElement(offp);
               }
             }
           }
+          // possible alternative for interactive selection - threshold
+          // gives 'ceiling' for forming a cluster
+          // when a row+column is selected, farthest common ancestor less
+          // than thr is used to compute cluster
+
+        }
+      }
+      else
+      {
+        // select corresponding range in segment under mouse
+        {
+          for (int c = fr; c <= to; c++)
+          {
+            av.getColumnSelection().addElement(c);
+          }
+          av.getColumnSelection().addElement(currentX);
+        }
+        // PAE SPECIFIC
+        // and also select everything lower than the max range adjacent
+        // (kind of works)
+        if (PAEContactMatrix.PAEMATRIX.equals(clicked.getCalcId()))
+        {
+          int c = fr - 1;
+          ContactRange cr = forCurrentX.getRangeFor(fr, to);
+          double cval;
+          // TODO: could use GraphLine instead of arbitrary picking
+          // TODO: could report mean/median/variance for partitions
+          // (contiguous selected vs unselected regions and inter-contig
+          // regions)
+          // controls feathering - what other elements in row/column
+          // should we select
+          double thresh = cr.getMean() + (cr.getMax() - cr.getMean()) * .15;
+          while (c > 0)
+          {
+            cval = forCurrentX.getContactAt(c);
+            if (// cr.getMin() <= cval &&
+            cval <= thresh)
+            {
+              av.getColumnSelection().addElement(c--);
+            }
+            else
+            {
+              break;
+            }
+          }
+          c = to;
+          while (c < forCurrentX.getContactHeight())
+          {
+            cval = forCurrentX.getContactAt(c);
+            if (// cr.getMin() <= cval &&
+            cval <= thresh)
+            {
+              av.getColumnSelection().addElement(c++);
+            }
+            else
+            {
+              break;
+            }
+          }
         }
       }
     }
-    else
-    {
-      ap.getScalePanel().mousePressed(evt);
-    }
+    ap.paintAlignment(false, false);
+    PaintRefresher.Refresh(ap, av.getSequenceSetId());
+    av.sendSelection();
+    return true;
   }
-
   /**
    * Construct and display a context menu at the right-click position
    * 
@@ -744,7 +824,10 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       ap.adjustAnnotationHeight();
     }
     dragMode = DragMode.Undefined;
-    ap.getScalePanel().mouseReleased(evt);
+    if (!matrix_clicked(evt))
+    {
+      ap.getScalePanel().mouseReleased(evt);
+    }
 
     /*
      * isPopupTrigger is set in mouseReleased on Windows
@@ -928,12 +1011,12 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
     if (rowIndex == null || toRowIndex == null)
     {
-      System.out.println("Drag out of range. needs to be clipped");
+      jalview.bin.Console.trace("Drag out of range. needs to be clipped");
 
     }
     if (rowIndex[0] != toRowIndex[0])
     {
-      System.out.println("Drag went to another row. needs to be clipped");
+      jalview.bin.Console.trace("Drag went to another row. needs to be clipped");
     }
 
     // rectangular selection on matrix style annotation
@@ -960,13 +1043,13 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
               rowIndex[1] - deltaY);
 
       // mark rectangular region formed by drag
-      System.err.println("Matrix Selection from last(" + fromXc + ",["
+      jalview.bin.Console.trace("Matrix Selection from last(" + fromXc + ",["
               + lastXci.cStart + "," + lastXci.cEnd + "]) to cur(" + toXc
               + ",[" + cXci.cStart + "," + cXci.cEnd + "])");
       int fr, to;
       fr = Math.min(lastXci.cStart, lastXci.cEnd);
       to = Math.max(lastXci.cStart, lastXci.cEnd);
-      System.err.println("Marking " + fr + " to " + to);
+      jalview.bin.Console.trace("Marking " + fr + " to " + to);
       for (int c = fr; c <= to; c++)
       {
         if (cma.sequenceRef != null)
@@ -981,7 +1064,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       }
       fr = Math.min(cXci.cStart, cXci.cEnd);
       to = Math.max(cXci.cStart, cXci.cEnd);
-      System.err.println("Marking " + fr + " to " + to);
+      jalview.bin.Console.trace("Marking " + fr + " to " + to);
       for (int c = fr; c <= to; c++)
       {
         if (cma.sequenceRef != null)
@@ -997,7 +1080,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       fr = Math.min(lastX, currentX);
       to = Math.max(lastX, currentX);
 
-      System.err.println("Marking " + fr + " to " + to);
+      jalview.bin.Console.trace("Marking " + fr + " to " + to);
       for (int c = fr; c <= to; c++)
       {
         av.getColumnSelection().addElement(c);
index 4e4a274..930ba79 100755 (executable)
@@ -333,6 +333,7 @@ public class ScalePanel extends JPanel
     ap.paintAlignment(false, false);
     av.isSelectionGroupChanged(true);
     av.isColSelChanged(true);
+    PaintRefresher.Refresh(ap, av.getSequenceSetId());
     av.sendSelection();
   }
 
index 20ec5e4..55f06fc 100644 (file)
@@ -2931,6 +2931,8 @@ public class SeqPanel extends JPanel
      * if hidden column selection has changed
      */
     ap.paintAlignment(hiddenChanged, hiddenChanged);
+    // propagate any selection changes
+    PaintRefresher.Refresh(ap, av.getSequenceSetId());
 
     return true;
   }
index 6f143db..29826f0 100755 (executable)
@@ -36,6 +36,9 @@ import java.awt.print.PageFormat;
 import java.awt.print.Printable;
 import java.awt.print.PrinterException;
 import java.awt.print.PrinterJob;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
@@ -50,6 +53,11 @@ import javax.swing.ToolTipManager;
 import jalview.analysis.Conservation;
 import jalview.analysis.TreeModel;
 import jalview.api.AlignViewportI;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.BinaryNode;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.ContactMatrixI;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -106,9 +114,9 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
 
   Map<Object, Rectangle> nameHash = new Hashtable<>();
 
-  Map<SequenceNode, Rectangle> nodeHash = new Hashtable<>();
+  Map<BinaryNode, Rectangle> nodeHash = new Hashtable<>();
 
-  SequenceNode highlightNode;
+  BinaryNode highlightNode;
 
   boolean applyToAllViews = false;
 
@@ -173,15 +181,15 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     tree.findHeight(tree.getTopNode());
 
     // Now have to calculate longest name based on the leaves
-    Vector<SequenceNode> leaves = tree.findLeaves(tree.getTopNode());
+    Vector<BinaryNode> leaves = tree.findLeaves(tree.getTopNode());
     boolean has_placeholders = false;
     longestName = "";
 
     for (int i = 0; i < leaves.size(); i++)
     {
-      SequenceNode lf = leaves.elementAt(i);
+      BinaryNode lf = leaves.elementAt(i);
 
-      if (lf.isPlaceholder())
+      if (lf instanceof SequenceNode && ((SequenceNode)lf).isPlaceholder())
       {
         has_placeholders = true;
       }
@@ -215,7 +223,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
    * @param offy
    *          DOCUMENT ME!
    */
-  public void drawNode(Graphics g, SequenceNode node, float chunk,
+  public void drawNode(Graphics g, BinaryNode node, float chunk,
           double wscale, int width, int offx, int offy)
   {
     if (node == null)
@@ -277,7 +285,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
         g.drawString(nodeLabel, xstart + 2, ypos - 2);
       }
 
-      String name = (markPlaceholders && node.isPlaceholder())
+      String name = (markPlaceholders && ((node instanceof SequenceNode && ((SequenceNode)node).isPlaceholder())))
               ? (PLACEHOLDER + node.getName())
               : node.getName();
 
@@ -290,10 +298,22 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
       nameHash.put(node.element(), rect);
 
       // Colour selected leaves differently
-      SequenceGroup selected = av.getSelectionGroup();
+      boolean isSelected = false;
+      if (tp.isColumnWise())
+      {
+        isSelected = isColumnForNodeSelected(node);
+      }
+      else
+      {
+        SequenceGroup selected = av.getSelectionGroup();
 
-      if ((selected != null)
-              && selected.getSequences(null).contains(node.element()))
+        if ((selected != null)
+                && selected.getSequences(null).contains(node.element()))
+        {
+          isSelected = true;
+        }
+      }
+      if (isSelected)
       {
         g.setColor(Color.gray);
 
@@ -306,9 +326,9 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     }
     else
     {
-      drawNode(g, (SequenceNode) node.left(), chunk, wscale, width, offx,
+      drawNode(g, (BinaryNode) node.left(), chunk, wscale, width, offx,
               offy);
-      drawNode(g, (SequenceNode) node.right(), chunk, wscale, width, offx,
+      drawNode(g, (BinaryNode) node.right(), chunk, wscale, width, offx,
               offy);
 
       double height = node.height;
@@ -332,9 +352,9 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
       }
 
       int ystart = (node.left() == null ? 0
-              : (int) (((SequenceNode) node.left()).ycount * chunk)) + offy;
+              : (int) (((BinaryNode) node.left()).ycount * chunk)) + offy;
       int yend = (node.right() == null ? 0
-              : (int) (((SequenceNode) node.right()).ycount * chunk))
+              : (int) (((BinaryNode) node.right()).ycount * chunk))
               + offy;
 
       Rectangle pos = new Rectangle(xend - 2, ypos - 2, 5, 5);
@@ -390,7 +410,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
       }
     }
 
-    for (Entry<SequenceNode, Rectangle> entry : nodeHash.entrySet())
+    for (Entry<BinaryNode, Rectangle> entry : nodeHash.entrySet())
     {
       Rectangle rect = entry.getValue();
 
@@ -415,14 +435,14 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     int width = getWidth();
     int height = getHeight();
 
-    SequenceNode top = tree.getTopNode();
+    BinaryNode top = tree.getTopNode();
 
     double wscale = ((width * .8) - (offx * 2)) / tree.getMaxHeight();
 
     if (top.count == 0)
     {
-      top.count = ((SequenceNode) top.left()).count
-              + ((SequenceNode) top.right()).count;
+      top.count = ((BinaryNode) top.left()).count
+              + ((BinaryNode) top.right()).count;
     }
 
     float chunk = (float) (height - (offy)) / top.count;
@@ -448,7 +468,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
    * @param offy
    *          DOCUMENT ME!
    */
-  public void pickNode(Rectangle pickBox, SequenceNode node, float chunk,
+  public void pickNode(Rectangle pickBox, BinaryNode node, float chunk,
           double wscale, int width, int offx, int offy)
   {
     if (node == null)
@@ -481,9 +501,9 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     }
     else
     {
-      pickNode(pickBox, (SequenceNode) node.left(), chunk, wscale, width,
+      pickNode(pickBox, (BinaryNode) node.left(), chunk, wscale, width,
               offx, offy);
-      pickNode(pickBox, (SequenceNode) node.right(), chunk, wscale, width,
+      pickNode(pickBox, (BinaryNode) node.right(), chunk, wscale, width,
               offx, offy);
     }
   }
@@ -496,7 +516,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
    * @param c
    *          DOCUMENT ME!
    */
-  public void setColor(SequenceNode node, Color c)
+  public void setColor(BinaryNode node, Color c)
   {
     if (node == null)
     {
@@ -516,8 +536,8 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
         }
       }
     }
-    setColor((SequenceNode) node.left(), c);
-    setColor((SequenceNode) node.right(), c);
+    setColor((BinaryNode) node.left(), c);
+    setColor((BinaryNode) node.right(), c);
   }
 
   /**
@@ -703,6 +723,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     if (longestName == null || tree == null)
     {
       g2.drawString("Calculating tree.", 20, 20);
+      return;
     }
     offy = font.getSize() + 10;
 
@@ -713,12 +734,12 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     double wscale = (width - labelLength - (offx * 2))
             / tree.getMaxHeight();
 
-    SequenceNode top = tree.getTopNode();
+    BinaryNode top = tree.getTopNode();
 
     if (top.count == 0)
     {
-      top.count = ((SequenceNode) top.left()).count
-              + ((SequenceNode) top.right()).count;
+      top.count = ((BinaryNode) top.left()).count
+              + ((BinaryNode) top.right()).count;
     }
 
     float chunk = (float) (height - (offy)) / top.count;
@@ -804,13 +825,16 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     }
     else
     {
-      Vector<SequenceNode> leaves = tree.findLeaves(highlightNode);
-
+      Vector<BinaryNode> leaves = tree.findLeaves(highlightNode);
+      if (tp.isColumnWise()) {
+        markColumnsFor(getAssociatedPanels(), leaves, Color.red);
+      } else {
       for (int i = 0; i < leaves.size(); i++)
       {
         SequenceI seq = (SequenceI) leaves.elementAt(i).element();
         treeSelectionChanged(seq);
       }
+      }
       av.sendSelection();
     }
 
@@ -847,9 +871,9 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
 
     Object ob = findElement(evt.getX(), evt.getY());
 
-    if (ob instanceof SequenceNode)
+    if (ob instanceof BinaryNode)
     {
-      highlightNode = (SequenceNode) ob;
+      highlightNode = (BinaryNode) ob;
       this.setToolTipText(
               "<html>" + MessageManager.getString("label.highlightnode"));
       repaint();
@@ -922,7 +946,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
       av.sendSelection();
       return;
     }
-    else if (!(ob instanceof SequenceNode))
+    else if (!(ob instanceof BinaryNode))
     {
       // Find threshold
       if (tree.getMaxHeight() != 0)
@@ -930,7 +954,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
         threshold = (float) (x - offx)
                 / (float) (getWidth() - labelLength - (2 * offx));
 
-        List<SequenceNode> groups = tree.groupNodes(threshold);
+        List<BinaryNode> groups = tree.groupNodes(threshold);
         setColor(tree.getTopNode(), Color.black);
 
         AlignmentPanel[] aps = getAssociatedPanels();
@@ -970,64 +994,40 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
 
   }
 
-  void colourGroups(List<SequenceNode> groups)
+  void colourGroups(List<BinaryNode> groups)
   {
     AlignmentPanel[] aps = getAssociatedPanels();
+    List<BitSet> colGroups = new ArrayList<>();
+    Map<BitSet,Color> colors=new HashMap();
     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(groups.get(i), col.brighter());
 
-      Vector<SequenceNode> l = tree.findLeaves(groups.get(i));
+      Vector<BinaryNode> l = tree.findLeaves(groups.get(i));
+      if (!tp.isColumnWise()) {
+        createSeqGroupFor(aps, l, col);
+      } else {
+        BitSet gp=createColumnGroupFor(l,col);
 
-      Vector<SequenceI> sequences = new Vector<>();
-
-      for (int j = 0; j < l.size(); j++)
-      {
-        SequenceI s1 = (SequenceI) l.elementAt(j).element();
-
-        if (!sequences.contains(s1))
-        {
-          sequences.addElement(s1);
-        }
+        colGroups.add(gp);
+        colors.put(gp, col);
       }
-
-      ColourSchemeI cs = null;
-      SequenceGroup _sg = new SequenceGroup(sequences, null, cs, true, true,
-              false, 0, av.getAlignment().getWidth() - 1);
-
-      _sg.setName("JTreeGroup:" + _sg.hashCode());
-      _sg.setIdColour(col);
-
-      for (int a = 0; a < aps.length; a++)
-      {
-        SequenceGroup sg = new SequenceGroup(_sg);
-        AlignViewport viewport = aps[a].av;
-
-        // Propagate group colours in each view
-        if (viewport.getGlobalColourScheme() != null)
+    }
+    if (tp.isColumnWise())
+    {
+      AlignmentAnnotation aa = tp.getAssocAnnotation();
+      if (aa!=null) {
+        ContactMatrixI cm = av.getContactMatrix(aa);
+        if (cm!=null)
         {
-          cs = viewport.getGlobalColourScheme().getInstance(viewport, sg);
-          sg.setColourScheme(cs);
-          sg.getGroupColourScheme().setThreshold(
-                  viewport.getResidueShading().getThreshold(),
-                  viewport.isIgnoreGapsConsensus());
-
-          if (viewport.getResidueShading().conservationApplied())
+          cm.updateGroups(colGroups);
+          for (BitSet gp:colors.keySet())
           {
-            Conservation c = new Conservation("Group",
-                    sg.getSequences(null), sg.getStartRes(),
-                    sg.getEndRes());
-            c.calculate();
-            c.verdict(false, viewport.getConsPercGaps());
-            sg.cs.setConservation(c);
+            cm.setColorForGroup(gp, colors.get(gp));
           }
         }
-        // indicate that associated structure views will need an update
-        viewport.setUpdateStructures(true);
-        // propagate structure view update and sequence group to complement view
-        viewport.addSequenceGroup(sg);
       }
     }
 
@@ -1046,6 +1046,154 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     }
   }
 
+  private boolean isColumnForNodeSelected(BinaryNode bn)
+  {
+    SequenceI rseq = tp.assocAnnotation.sequenceRef;
+    int colm = -1;
+    try
+    {
+      colm = Integer.parseInt(
+              bn.getName().substring(bn.getName().indexOf("c") + 1));
+    } catch (Exception e)
+    {
+      return false;
+    }
+    if (av==null||av.getAlignment()==null)
+    {
+      // alignment is closed
+      return false;
+    }
+    ColumnSelection cs = av.getColumnSelection();
+    
+    HiddenColumns hc = av.getAlignment().getHiddenColumns();
+    int offp = (rseq != null) ? rseq.findIndex(rseq.getStart() + colm)
+            : colm;
+
+    if (!av.hasHiddenColumns())
+    {
+      return cs.contains(offp-1);
+    }
+    if (hc.isVisible(offp-1))
+    {
+      return cs.contains(offp-1);
+//      return cs.contains(hc.absoluteToVisibleColumn(offp));
+    }
+    return false;
+  }
+  
+  private BitSet createColumnGroupFor(Vector<BinaryNode> l,
+          Color col)
+  {
+    BitSet gp=new BitSet();
+    for (BinaryNode bn:l)
+    {
+      int colm=-1;
+      if (bn.element()!=null && bn.element()instanceof Integer)
+      { colm = (Integer)bn.element();
+      } else {
+        // parse out from nodename
+      try {
+        colm = Integer.parseInt(bn.getName().substring(bn.getName().indexOf("c")+1));
+      } catch (Exception e)
+      {
+        continue;
+      }
+      }
+      gp.set(colm);
+    }
+    return gp;
+  }
+
+  private void markColumnsFor(AlignmentPanel[] aps, Vector<BinaryNode> l,
+          Color col)
+  {
+    SequenceI rseq = tp.assocAnnotation.sequenceRef;
+    if (av==null||av.getAlignment()==null)
+    {
+      // alignment is closed
+      return;
+    }
+
+    for (BinaryNode bn:l)
+    {
+      int colm=-1;
+      try {
+        colm = Integer.parseInt(bn.getName().substring(bn.getName().indexOf("c")+1));
+      } catch (Exception e)
+      {
+        continue;
+      }
+      ColumnSelection cs = av.getColumnSelection();
+      HiddenColumns hc = av.getAlignment().getHiddenColumns();
+      {
+        int offp = (rseq!=null) ? rseq.findIndex(rseq.getStart()+colm) : colm;
+        
+        if (!av.hasHiddenColumns() || hc.isVisible(offp-1))
+        { 
+          if (cs.contains(offp-1))
+          {
+            cs.removeElement(offp-1);
+          } else {
+            cs.addElement(offp-1);
+          }
+        }
+      }
+    } 
+  }
+
+  public void createSeqGroupFor(AlignmentPanel[] aps, Vector<BinaryNode> l,
+          Color col)
+  {
+
+    Vector<SequenceI> sequences = new Vector<>();
+
+    for (int j = 0; j < l.size(); j++)
+    {
+      SequenceI s1 = (SequenceI) 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);
+
+    _sg.setName("JTreeGroup:" + _sg.hashCode());
+    _sg.setIdColour(col);
+
+    for (int a = 0; a < aps.length; a++)
+    {
+      SequenceGroup sg = new SequenceGroup(_sg);
+      AlignViewport viewport = aps[a].av;
+
+      // Propagate group colours in each view
+      if (viewport.getGlobalColourScheme() != null)
+      {
+        cs = viewport.getGlobalColourScheme().getInstance(viewport, sg);
+        sg.setColourScheme(cs);
+        sg.getGroupColourScheme().setThreshold(
+                viewport.getResidueShading().getThreshold(),
+                viewport.isIgnoreGapsConsensus());
+
+        if (viewport.getResidueShading().conservationApplied())
+        {
+          Conservation c = new Conservation("Group", sg.getSequences(null),
+                  sg.getStartRes(), sg.getEndRes());
+          c.calculate();
+          c.verdict(false, viewport.getConsPercGaps());
+          sg.cs.setConservation(c);
+        }
+      }
+      // indicate that associated structure views will need an update
+      viewport.setUpdateStructures(true);
+      // propagate structure view update and sequence group to complement view
+      viewport.addSequenceGroup(sg);
+    }
+  }
+
   /**
    * DOCUMENT ME!
    * 
index 76e1884..30e4305 100755 (executable)
@@ -53,6 +53,7 @@ import jalview.bin.Console;
 import jalview.commands.CommandI;
 import jalview.commands.OrderCommand;
 import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.BinaryNode;
@@ -123,6 +124,35 @@ public class TreePanel extends GTreePanel
     initTreePanel(alignPanel, null, null, newtree, inputData);
   }
 
+  /**
+   * columnwise tree associated with positions in aa
+   * 
+   * @param alignPanel
+   * @param fin
+   * @param title
+   * @param aa
+   */
+  public TreePanel(AlignmentPanel alignPanel, NewickFile fin,
+          AlignmentAnnotation aa, String title)
+  {
+    super();
+    columnWise=true;
+    assocAnnotation = aa;
+    this.setFrameIcon(null);
+    this.treeTitle = title;
+    initTreePanel(alignPanel, null, null, fin, null);
+  }
+  
+  boolean columnWise=false;
+  AlignmentAnnotation assocAnnotation=null;
+  public boolean isColumnWise()
+  {
+    return columnWise;
+  }
+  public AlignmentAnnotation getAssocAnnotation() {
+    return assocAnnotation;
+  }
+
   public AlignmentI getAlignment()
   {
     return getTreeCanvas().getViewport().getAlignment();
@@ -142,6 +172,15 @@ public class TreePanel extends GTreePanel
     this.treeType = type;
     this.scoreModelName = modelName;
 
+    if (columnWise)
+    {
+      bootstrapMenu.setVisible(false);
+      placeholdersMenu.setSelected(false);
+      placeholdersMenu.setVisible(false);
+      fitToWindow.setSelected(false);
+      sortAssocViews.setVisible(false);
+    }
+
     treeCanvas = new TreeCanvas(this, ap, scrollPane);
     scrollPane.setViewportView(treeCanvas);
 
@@ -721,7 +760,7 @@ public class TreePanel extends GTreePanel
                 && !((SequenceNode) node).isDummy())
         {
           String newname = null;
-          SequenceI sq = (SequenceI) ((SequenceNode) node).element();
+          SequenceI sq = (SequenceI) ((BinaryNode) node).element();
           if (sq != null)
           {
             // search dbrefs, features and annotation
@@ -763,7 +802,7 @@ public class TreePanel extends GTreePanel
           {
             // String oldname = ((SequenceNode) node).getName();
             // TODO : save oldname in the undo object for this modification.
-            ((SequenceNode) node).setName(newname);
+            ((BinaryNode) node).setName(newname);
           }
         }
       }
index 98978d0..b3c0011 100755 (executable)
@@ -36,6 +36,7 @@ import java.util.StringTokenizer;
 import com.stevesoft.pat.Regex;
 
 import jalview.bin.Jalview;
+import jalview.datamodel.BinaryNode;
 import jalview.datamodel.SequenceNode;
 import jalview.util.MessageManager;
 
@@ -78,7 +79,7 @@ import jalview.util.MessageManager;
  */
 public class NewickFile extends FileParse
 {
-  SequenceNode root;
+  BinaryNode root;
 
   private boolean HasBootstrap = false;
 
@@ -145,7 +146,7 @@ public class NewickFile extends FileParse
    * @param newtree
    *          DOCUMENT ME!
    */
-  public NewickFile(SequenceNode newtree)
+  public NewickFile(BinaryNode newtree)
   {
     root = newtree;
   }
@@ -174,7 +175,7 @@ public class NewickFile extends FileParse
    * @param distances
    *          DOCUMENT ME!
    */
-  public NewickFile(SequenceNode newtree, boolean bootstrap,
+  public NewickFile(BinaryNode newtree, boolean bootstrap,
           boolean distances)
   {
     root = newtree;
@@ -194,7 +195,7 @@ public class NewickFile extends FileParse
    * @param rootdistance
    *          DOCUMENT ME!
    */
-  public NewickFile(SequenceNode newtree, boolean bootstrap,
+  public NewickFile(BinaryNode newtree, boolean bootstrap,
           boolean distances, boolean rootdistance)
   {
     root = newtree;
@@ -275,8 +276,8 @@ public class NewickFile extends FileParse
 
     root = new SequenceNode();
 
-    SequenceNode realroot = null;
-    SequenceNode c = root;
+    BinaryNode realroot = null;
+    BinaryNode c = root;
 
     int d = -1;
     int cp = 0;
@@ -323,21 +324,21 @@ public class NewickFile extends FileParse
         {
           c.setRight(new SequenceNode(null, c, null, DefDistance,
                   DefBootstrap, false));
-          c = (SequenceNode) c.right();
+          c = (BinaryNode) c.right();
         }
         else
         {
           if (c.left() != null)
           {
             // Dummy node for polytomy - keeps c.left free for new node
-            SequenceNode tmpn = new SequenceNode(null, c, null, 0, 0, true);
+            BinaryNode tmpn = new SequenceNode(null, c, null, 0, 0, true);
             tmpn.SetChildren(c.left(), c.right());
             c.setRight(tmpn);
           }
 
           c.setLeft(new SequenceNode(null, c, null, DefDistance,
                   DefBootstrap, false));
-          c = (SequenceNode) c.left();
+          c = (BinaryNode) c.left();
         }
 
         if (realroot == null)
@@ -519,7 +520,7 @@ public class NewickFile extends FileParse
         else
         {
           // Find a place to put the leaf
-          SequenceNode newnode = new SequenceNode(null, c, nodename,
+          BinaryNode newnode = new SequenceNode(null, c, nodename,
                   (HasDistances) ? distance : DefDistance,
                   (HasBootstrap) ? bootstrap : DefBootstrap, false);
           parseNHXNodeProps(c, commentString2);
@@ -539,7 +540,7 @@ public class NewickFile extends FileParse
             {
               // Insert a dummy node for polytomy
               // dummy nodes have distances
-              SequenceNode newdummy = new SequenceNode(null, c, null,
+              BinaryNode newdummy = new SequenceNode(null, c, null,
                       (HasDistances ? 0 : DefDistance), 0, true);
               newdummy.SetChildren(c.left(), newnode);
               c.setLeft(newdummy);
@@ -578,7 +579,7 @@ public class NewickFile extends FileParse
               // Just advance focus, if we need to
               if ((c.left() != null) && (!c.left().isLeaf()))
               {
-                c = (SequenceNode) c.left();
+                c = (BinaryNode) c.left();
               }
             }
           }
@@ -632,7 +633,7 @@ public class NewickFile extends FileParse
    * @param commentString
    * @param commentString2
    */
-  private void parseNHXNodeProps(SequenceNode c, String commentString)
+  private void parseNHXNodeProps(BinaryNode c, String commentString)
   {
     // TODO: store raw comment on the sequenceNode so it can be recovered when
     // tree is output
@@ -679,7 +680,7 @@ public class NewickFile extends FileParse
    * 
    * @return DOCUMENT ME!
    */
-  public SequenceNode getTree()
+  public BinaryNode getTree()
   {
     return root;
   }
@@ -833,7 +834,7 @@ public class NewickFile extends FileParse
    * 
    * @return DOCUMENT ME!
    */
-  private String printNodeField(SequenceNode c)
+  private String printNodeField(BinaryNode c)
   {
     return ((c.getName() == null) ? "" : nodeName(c.getName()))
             + ((HasBootstrap) ? ((c.getBootstrap() > -1)
@@ -850,7 +851,7 @@ public class NewickFile extends FileParse
    * 
    * @return DOCUMENT ME!
    */
-  private String printRootField(SequenceNode root)
+  private String printRootField(BinaryNode root)
   {
     return (printRootInfo)
             ? (((root.getName() == null) ? "" : nodeName(root.getName()))
@@ -865,7 +866,7 @@ public class NewickFile extends FileParse
   }
 
   // Non recursive call deals with root node properties
-  public void print(StringBuffer tf, SequenceNode root)
+  public void print(StringBuffer tf, BinaryNode root)
   {
     if (root != null)
     {
@@ -877,20 +878,20 @@ public class NewickFile extends FileParse
       {
         if (root.isDummy())
         {
-          _print(tf, (SequenceNode) root.right());
-          _print(tf, (SequenceNode) root.left());
+          _print(tf, root.right());
+          _print(tf, root.left());
         }
         else
         {
           tf.append("(");
-          _print(tf, (SequenceNode) root.right());
+          _print(tf, root.right());
 
           if (root.left() != null)
           {
             tf.append(",");
           }
 
-          _print(tf, (SequenceNode) root.left());
+          _print(tf, root.left());
           tf.append(")" + printRootField(root));
         }
       }
@@ -898,7 +899,7 @@ public class NewickFile extends FileParse
   }
 
   // Recursive call for non-root nodes
-  public void _print(StringBuffer tf, SequenceNode c)
+  public void _print(StringBuffer tf, BinaryNode c)
   {
     if (c != null)
     {
@@ -910,24 +911,24 @@ public class NewickFile extends FileParse
       {
         if (c.isDummy())
         {
-          _print(tf, (SequenceNode) c.left());
+          _print(tf, c.left());
           if (c.left() != null)
           {
             tf.append(",");
           }
-          _print(tf, (SequenceNode) c.right());
+          _print(tf, c.right());
         }
         else
         {
           tf.append("(");
-          _print(tf, (SequenceNode) c.right());
+          _print(tf, c.right());
 
           if (c.left() != null)
           {
             tf.append(",");
           }
 
-          _print(tf, (SequenceNode) c.left());
+          _print(tf, c.left());
           tf.append(")" + printNodeField(c));
         }
       }
index e1ef021..3df9804 100644 (file)
@@ -25,6 +25,7 @@ import jalview.datamodel.SequenceI;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.BitSet;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
index e8f6f6b..c0d1774 100644 (file)
@@ -322,7 +322,7 @@ public class Tree extends DatastoreItem
       Console.warn("Not updating SequenceTreeMap for " + tree.getVorbaId());
       return;
     }
-    Vector<SequenceNode> leaves = tp.getTree()
+    Vector<BinaryNode> leaves = tp.getTree()
             .findLeaves(tp.getTree().getTopNode());
     Treenode[] tn = tree.getTreenode(); // todo: select nodes for this
     // particular tree
@@ -381,7 +381,7 @@ public class Tree extends DatastoreItem
    */
   public Treenode[] makeTreeNodes(TreeModel treeModel, Newick newick)
   {
-    Vector<SequenceNode> leaves = treeModel
+    Vector<BinaryNode> leaves = treeModel
             .findLeaves(treeModel.getTopNode());
     Vector tnv = new Vector();
     Enumeration l = leaves.elements();
@@ -394,7 +394,7 @@ public class Tree extends DatastoreItem
       {
         if (!((jalview.datamodel.SequenceNode) tnode).isPlaceholder())
         {
-          Object assocseq = ((jalview.datamodel.SequenceNode) tnode)
+          Object assocseq = ((BinaryNode) tnode)
                   .element();
           if (assocseq instanceof SequenceI)
           {
index 14803df..ddf2afd 100644 (file)
@@ -45,6 +45,7 @@ import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.BitSet;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.GregorianCalendar;
@@ -1324,6 +1325,13 @@ public class Jalview2XML
               tree.setLinkToAllViews(
                       tp.getTreeCanvas().isApplyToAllViews());
 
+              // columnWiseTree
+              if (tp.isColumnWise())
+              {
+                tree.setColumnWise(true);
+                String annId = tp.getAssocAnnotation().annotationId;
+                tree.setColumnReference(annId);
+              }
               // jms.addTree(tree);
               object.getTree().add(tree);
             }
@@ -2307,7 +2315,28 @@ public class Jalview2XML
               xmlmat.setType(cm.getType());
               xmlmat.setRows(BigInteger.valueOf(cm.getWidth()));
               xmlmat.setCols(BigInteger.valueOf(cm.getHeight()));
-              xmlmat.setValue(ContactMatrix.contactToFloatString(cm));
+              // consider using an opaque to/from -> allow instance to control its representation ?
+              xmlmat.setElements(ContactMatrix.contactToFloatString(cm));
+              if (cm.hasGroups())
+              {
+                for (BitSet gp: cm.getGroups())
+                {
+                  BigInteger val = new BigInteger(gp.toByteArray());
+                  xmlmat.getGroups().add(val.toString());
+                }
+              }
+              if (cm.hasTree())
+              {
+                // provenance object for tree ?
+                xmlmat.getNewick().add(cm.getNewick());
+                xmlmat.setTreeMethod(cm.getTreeMethod());
+              }
+              if (cm.hasCutHeight())
+              {
+                xmlmat.setCutHeight(cm.getCutHeight());
+              }
+              
+              // set/get properties
               an.getContactmatrix().add(xmlmat);
             }
           }
@@ -2342,10 +2371,9 @@ public class Jalview2XML
       {
         for (String pr : annotation.getProperties())
         {
-          jalview.xml.binding.jalview.Annotation.Property prop = new jalview.xml.binding.jalview.Annotation.Property();
+          jalview.xml.binding.jalview.Property prop = new jalview.xml.binding.jalview.Property();
           prop.setName(pr);
           prop.setValue(annotation.getProperty(pr));
-          // an.addProperty(prop);
           an.getProperty().add(prop);
         }
       }
@@ -3920,7 +3948,7 @@ public class Jalview2XML
         jaa.setCalcId(annotation.getCalcId());
         if (annotation.getProperty().size() > 0)
         {
-          for (Annotation.Property prop : annotation.getProperty())
+          for (jalview.xml.binding.jalview.Property prop : annotation.getProperty())
           {
             jaa.setProperty(prop.getName(), prop.getValue());
           }
@@ -3941,12 +3969,36 @@ public class Jalview2XML
                 else
                 {
                   float[][] elements = ContactMatrix
-                          .fromFloatStringToContacts(xmlmat.getValue(),
+                          .fromFloatStringToContacts(xmlmat.getElements(),
                                   xmlmat.getCols().intValue(),
                                   xmlmat.getRows().intValue());
 
                   PAEContactMatrix newpae = new PAEContactMatrix(
                           jaa.sequenceRef, elements);
+                  List<BitSet> newgroups=new ArrayList<BitSet>();
+                  if (xmlmat.getGroups().size()>0)
+                  {
+                    for (String sgroup:xmlmat.getGroups())
+                    {
+                      try {
+                        BigInteger group = new BigInteger(sgroup);
+                        newgroups.add(BitSet.valueOf(group.toByteArray()));
+                      } catch (NumberFormatException nfe)
+                      {
+                        Console.error("Problem parsing groups for a contact matrix (\""+sgroup+"\"",nfe);
+                      }
+                    }
+                  }
+                  String nwk=xmlmat.getNewick().size()>0 ? xmlmat.getNewick().get(0):null;
+                  if  (xmlmat.getNewick().size()>1)
+                  {
+                    Console.log.info(
+                            "Ignoring additional clusterings for contact matrix");
+                  }
+                  
+                  String treeMethod = xmlmat.getTreeMethod();
+                  double thresh = xmlmat.getCutHeight()!=null ? xmlmat.getCutHeight() : 0;
+                  newpae.restoreGroups(newgroups, treeMethod, nwk, thresh);
                   jaa.sequenceRef.addContactListFor(jaa, newpae);
                 }
               }
@@ -4340,10 +4392,28 @@ public class Jalview2XML
         TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
         if (tp == null)
         {
-          tp = af.showNewickTree(new NewickFile(tree.getNewick()),
-                  tree.getTitle(), safeInt(tree.getWidth()),
-                  safeInt(tree.getHeight()), safeInt(tree.getXpos()),
-                  safeInt(tree.getYpos()));
+          if (tree.isColumnWise())
+          {
+            AlignmentAnnotation aa = (AlignmentAnnotation) annotationIds.get(tree
+                    .getColumnReference());
+            if (aa == null)
+            {
+              Console.warn(
+                      "Null alignment annotation when restoring columnwise tree");
+            }
+            tp = af.showColumnWiseTree(new NewickFile(tree.getNewick()), aa,
+                    tree.getTitle(), safeInt(tree.getWidth()),
+                    safeInt(tree.getHeight()), safeInt(tree.getXpos()),
+                    safeInt(tree.getYpos()));
+
+          }
+          else
+          {
+            tp = af.showNewickTree(new NewickFile(tree.getNewick()),
+                    tree.getTitle(), safeInt(tree.getWidth()),
+                    safeInt(tree.getHeight()), safeInt(tree.getXpos()),
+                    safeInt(tree.getYpos()));
+          }
           if (tree.getId() != null)
           {
             // perhaps bind the tree id to something ?
index 0a2278b..e54f471 100644 (file)
@@ -12,6 +12,7 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.ContactRange;
 import jalview.datamodel.HiddenColumns;
 import jalview.renderer.api.AnnotationRowRendererI;
@@ -114,6 +115,7 @@ public abstract class ContactMapRenderer implements AnnotationRowRendererI
 
     int column;
     int aaMax = aa_annotations.length - 1;
+    ContactMatrixI cm = viewport.getContactMatrix(_aa);
     while (x < eRes - sRes)
     {
       column = sRes + x;
@@ -144,6 +146,7 @@ public abstract class ContactMapRenderer implements AnnotationRowRendererI
         x++;
         continue;
       }
+      Color gpcol = (cm==null) ? Color.white: cm.getColourForGroup(cm.getGroupsFor(column));
       // feature still in development - highlight or omit regions hidden in
       // the alignment - currently marks them as red rows
       boolean maskHiddenCols = false;
@@ -213,7 +216,14 @@ public abstract class ContactMapRenderer implements AnnotationRowRendererI
         {
           col = shade.hidden;
         }
+        if (gpcol!=null && gpcol!=Color.white) {
+          // todo - could overlay group as a transparent rectangle ?
+          col = new Color((int)(((float)(col.getRed()+gpcol.getRed()))/2f),
+                  (int)(((float)(col.getGreen()+gpcol.getGreen()))/2f),
+                  (int)(((float)(col.getBlue()+gpcol.getBlue()))/2f));
+        }
         g.setColor(col);
+        
         if (cgeom.pixels_step > 1)
         {
           g.fillRect(x * charWidth, ht, charWidth, 1 + cgeom.pixels_step);
index a42a2a4..36b0851 100644 (file)
@@ -51,6 +51,7 @@ import jalview.datamodel.AlignmentView;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.ProfilesI;
@@ -2948,6 +2949,14 @@ public abstract class AlignmentViewport
     return alignment.getContactListFor(_aa, column);
   }
 
+  @Override
+  public ContactMatrixI getContactMatrix(
+          AlignmentAnnotation alignmentAnnotation)
+  {
+    return alignment.getContactMatrixFor(alignmentAnnotation);
+  }
+
+
   /**
    * get the consensus sequence as displayed under the PID consensus annotation
    * row.
index cefdbd2..1ec856b 100644 (file)
@@ -1,9 +1,16 @@
 package jalview.ws.datamodel.alphafold;
 
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import jalview.analysis.AverageDistanceEngine;
+import jalview.bin.Console;
+import jalview.datamodel.BinaryNode;
 import jalview.datamodel.ContactListI;
 import jalview.datamodel.ContactListImpl;
 import jalview.datamodel.ContactListProviderI;
@@ -217,15 +224,18 @@ public class PAEContactMatrix implements ContactMatrixI
   @Override
   public String getAnnotDescr()
   {
-    return "Predicted Alignment Error for " + refSeq.getName();
+    return "Predicted Alignment Error"
+            + ((refSeq == null) ? "" : (" for " + refSeq.getName()));
   }
 
   @Override
   public String getAnnotLabel()
   {
-    StringBuilder label = new StringBuilder("pAE Matrix");
+    StringBuilder label = new StringBuilder("PAE Matrix");
     // if (this.getReferenceSeq() != null)
+    // {
     // label.append(":").append(this.getReferenceSeq().getDisplayId(false));
+    // }
     return label.toString();
   }
 
@@ -248,4 +258,142 @@ public class PAEContactMatrix implements ContactMatrixI
   {
     return length;
   }
+
+  List<BitSet> groups = null;
+
+  @Override
+  public boolean hasGroups()
+  {
+    return groups != null;
+  }
+
+  String newick = null;
+
+  @Override
+  public String getNewick()
+  {
+    return newick;
+  }
+
+  @Override
+  public boolean hasTree()
+  {
+    return newick != null && newick.length() > 0;
+  }
+
+  boolean abs;
+
+  double thresh;
+
+  String treeType = null;
+
+  public void makeGroups(float thresh, boolean abs)
+  {
+    AverageDistanceEngine clusterer = new AverageDistanceEngine(null, null,
+            this);
+    double height = clusterer.findHeight(clusterer.getTopNode());
+    newick = new jalview.io.NewickFile(clusterer.getTopNode(), false, true)
+            .print();
+    treeType = "UPGMA";
+    Console.trace("Newick string\n" + newick);
+
+    List<BinaryNode> nodegroups;
+    if (abs ? height > thresh : 0 < thresh && thresh < 1)
+    {
+      float cut = abs ? (float) (thresh / height) : thresh;
+      Console.debug("Threshold " + cut + " for height=" + height);
+
+      nodegroups = clusterer.groupNodes(cut);
+    }
+    else
+    {
+      nodegroups = new ArrayList<BinaryNode>();
+      nodegroups.add(clusterer.getTopNode());
+    }
+    this.abs = abs;
+    this.thresh = thresh;
+    groups = new ArrayList<>();
+    for (BinaryNode root : nodegroups)
+    {
+      BitSet gpset = new BitSet();
+      for (BinaryNode leaf : clusterer.findLeaves(root))
+      {
+        gpset.set((Integer) leaf.element());
+      }
+      groups.add(gpset);
+    }
+  }
+
+  @Override
+  public void updateGroups(List<BitSet> colGroups)
+  {
+    if (colGroups != null)
+    {
+      groups = colGroups;
+    }
+  }
+
+  @Override
+  public BitSet getGroupsFor(int column)
+  {
+    for (BitSet gp : groups)
+    {
+      if (gp.get(column))
+      {
+        return gp;
+      }
+    }
+    return ContactMatrixI.super.getGroupsFor(column);
+  }
+
+  HashMap<BitSet, Color> colorMap = new HashMap<>();
+
+  @Override
+  public Color getColourForGroup(BitSet bs)
+  {
+    if (bs == null)
+    {
+      return Color.white;
+    }
+    Color groupCol = colorMap.get(bs);
+    if (groupCol == null)
+    {
+      return Color.white;
+    }
+    return groupCol;
+  }
+
+  @Override
+  public void setColorForGroup(BitSet bs, Color color)
+  {
+    colorMap.put(bs, color);
+  }
+
+  public void restoreGroups(List<BitSet> newgroups, String treeMethod,
+          String tree, double thresh2)
+  {
+    treeType = treeMethod;
+    groups = newgroups;
+    thresh = thresh2;
+    newick = tree;
+
+  }
+
+  @Override
+  public boolean hasCutHeight()
+  {
+    return groups != null && thresh != 0;
+  }
+
+  @Override
+  public double getCutHeight()
+  {
+    return thresh;
+  }
+
+  @Override
+  public String getTreeMethod()
+  {
+    return treeType;
+  }
 }
index 19eaf78..d0538c1 100644 (file)
@@ -445,6 +445,7 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
     }
     ContactMatrixI matrix = new PAEContactMatrix(sequence,
             (Map<String, Object>) paeDict);
+    ((PAEContactMatrix) matrix).makeGroups(5f, true);
 
     AlignmentAnnotation cmannot = sequence.addContactList(matrix);
     if (label != null)
@@ -500,14 +501,11 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
 
     SequenceI seq = sm.getSequence();
     Console.debug("##### SEQUENCE FOUND=" + seq.getName());
-    Map<String, Object> paeObject = (Map<String, Object>) pae_obj;
-
-    ContactMatrixI matrix = new PAEContactMatrix(seq, paeObject);
+    ContactMatrixI matrix = new PAEContactMatrix(seq,
+            (Map<String, Object>) pae_obj);
+    ((PAEContactMatrix) matrix).makeGroups(5f, true);
     AlignmentAnnotation cmannot = seq.addContactList(matrix);
-    if (label != null)
-    {
-      cmannot.label = label;
-    }
+    seq.addAlignmentAnnotation(cmannot);
     // seq.addAlignmentAnnotation(cmannot);
 
     return true;
index d72dd8d..0479a34 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:45 PM GMT 
 //
 
 
index f744eb5..6336ef1 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:45 PM GMT 
 //
 
 
index 4a5bf19..e1a917a 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:45 PM GMT 
 //
 
 
index 6d98c82..958cdbc 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:45 PM GMT 
 //
 
 
index a53c82b..244d0fe 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:45 PM GMT 
 //
 
 
index 53bc217..2a40e11 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index 8df1313..8d99141 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
@@ -43,16 +43,7 @@ import javax.xml.bind.annotation.XmlType;
  *           &lt;/complexType>
  *         &lt;/element>
  *         &lt;element name="contactmatrix" type="{www.vamsas.ac.uk/jalview/version2}MatrixType" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element name="property" maxOccurs="unbounded" minOccurs="0">
- *           &lt;complexType>
- *             &lt;complexContent>
- *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                 &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                 &lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}string" />
- *               &lt;/restriction>
- *             &lt;/complexContent>
- *           &lt;/complexType>
- *         &lt;/element>
+ *         &lt;element name="property" type="{www.vamsas.ac.uk/jalview/version2}property" maxOccurs="unbounded" minOccurs="0"/>
  *       &lt;/sequence>
  *       &lt;attribute name="graph" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
  *       &lt;attribute name="graphType" type="{http://www.w3.org/2001/XMLSchema}int" />
@@ -96,7 +87,7 @@ public class Annotation {
     protected String description;
     protected Annotation.ThresholdLine thresholdLine;
     protected List<MatrixType> contactmatrix;
-    protected List<Annotation.Property> property;
+    protected List<Property> property;
     @XmlAttribute(name = "graph", required = true)
     protected boolean graph;
     @XmlAttribute(name = "graphType")
@@ -280,13 +271,13 @@ public class Annotation {
      * 
      * <p>
      * Objects of the following type(s) are allowed in the list
-     * {@link Annotation.Property }
+     * {@link Property }
      * 
      * 
      */
-    public List<Annotation.Property> getProperty() {
+    public List<Property> getProperty() {
         if (property == null) {
-            property = new ArrayList<Annotation.Property>();
+            property = new ArrayList<Property>();
         }
         return this.property;
     }
@@ -713,84 +704,6 @@ public class Annotation {
      * &lt;complexType>
      *   &lt;complexContent>
      *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
-     * 
-     * 
-     */
-    @XmlAccessorType(XmlAccessType.FIELD)
-    @XmlType(name = "")
-    public static class Property {
-
-        @XmlAttribute(name = "name")
-        protected String name;
-        @XmlAttribute(name = "value")
-        protected String value;
-
-        /**
-         * Gets the value of the name property.
-         * 
-         * @return
-         *     possible object is
-         *     {@link String }
-         *     
-         */
-        public String getName() {
-            return name;
-        }
-
-        /**
-         * Sets the value of the name property.
-         * 
-         * @param value
-         *     allowed object is
-         *     {@link String }
-         *     
-         */
-        public void setName(String value) {
-            this.name = value;
-        }
-
-        /**
-         * Gets the value of the value property.
-         * 
-         * @return
-         *     possible object is
-         *     {@link String }
-         *     
-         */
-        public String getValue() {
-            return value;
-        }
-
-        /**
-         * Sets the value of the value property.
-         * 
-         * @param value
-         *     allowed object is
-         *     {@link String }
-         *     
-         */
-        public void setValue(String value) {
-            this.value = value;
-        }
-
-    }
-
-
-    /**
-     * <p>Java class for anonymous complex type.
-     * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
-     * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      *       &lt;attribute name="label" type="{http://www.w3.org/2001/XMLSchema}string" />
      *       &lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}float" />
      *       &lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}int" />
index fe0f49d..27e0cc6 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index 4d34ce2..c5f75e0 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index 8ab2f67..9be9876 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index 5c34abf..6546be9 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index 41771fd..a124e62 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index 94c26e0..61e66ce 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index ea26bed..24190b8 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index e13905d..3a9428c 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index cbe06b4..22b2533 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
@@ -260,6 +260,8 @@ import javax.xml.datatype.XMLGregorianCalendar;
  *                   &lt;attribute name="markUnlinked" type="{http://www.w3.org/2001/XMLSchema}boolean" />
  *                   &lt;attribute name="fitToWindow" type="{http://www.w3.org/2001/XMLSchema}boolean" />
  *                   &lt;attribute name="currentTree" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ *                   &lt;attribute name="columnWise" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ *                   &lt;attribute name="columnReference" type="{http://www.w3.org/2001/XMLSchema}string" />
  *                   &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" />
  *                   &lt;attribute name="linkToAllViews" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
  *                 &lt;/restriction>
@@ -310,8 +312,8 @@ import javax.xml.datatype.XMLGregorianCalendar;
  *                     &lt;/element>
  *                     &lt;element name="pcaData" type="{www.jalview.org}PcaDataType"/>
  *                   &lt;/sequence>
- *                   &lt;attGroup ref="{www.jalview.org}swingwindow"/>
  *                   &lt;attGroup ref="{www.jalview.org}SimilarityParams"/>
+ *                   &lt;attGroup ref="{www.jalview.org}swingwindow"/>
  *                   &lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
  *                   &lt;attribute name="scoreModelName" type="{http://www.w3.org/2001/XMLSchema}string" />
  *                   &lt;attribute name="xDim" type="{http://www.w3.org/2001/XMLSchema}int" />
@@ -3124,8 +3126,8 @@ public class JalviewModel {
      *         &lt;/element>
      *         &lt;element name="pcaData" type="{www.jalview.org}PcaDataType"/>
      *       &lt;/sequence>
-     *       &lt;attGroup ref="{www.jalview.org}swingwindow"/>
      *       &lt;attGroup ref="{www.jalview.org}SimilarityParams"/>
+     *       &lt;attGroup ref="{www.jalview.org}swingwindow"/>
      *       &lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
      *       &lt;attribute name="scoreModelName" type="{http://www.w3.org/2001/XMLSchema}string" />
      *       &lt;attribute name="xDim" type="{http://www.w3.org/2001/XMLSchema}int" />
@@ -3180,14 +3182,6 @@ public class JalviewModel {
         protected Boolean showLabels;
         @XmlAttribute(name = "linkToAllViews")
         protected Boolean linkToAllViews;
-        @XmlAttribute(name = "width")
-        protected Integer width;
-        @XmlAttribute(name = "height")
-        protected Integer height;
-        @XmlAttribute(name = "xpos")
-        protected Integer xpos;
-        @XmlAttribute(name = "ypos")
-        protected Integer ypos;
         @XmlAttribute(name = "includeGaps")
         protected Boolean includeGaps;
         @XmlAttribute(name = "matchGaps")
@@ -3196,6 +3190,14 @@ public class JalviewModel {
         protected Boolean includeGappedColumns;
         @XmlAttribute(name = "denominateByShortestLength")
         protected Boolean denominateByShortestLength;
+        @XmlAttribute(name = "width")
+        protected Integer width;
+        @XmlAttribute(name = "height")
+        protected Integer height;
+        @XmlAttribute(name = "xpos")
+        protected Integer xpos;
+        @XmlAttribute(name = "ypos")
+        protected Integer ypos;
 
         /**
          * Gets the value of the sequencePoint property.
@@ -3544,195 +3546,195 @@ public class JalviewModel {
         }
 
         /**
-         * Gets the value of the width property.
+         * Gets the value of the includeGaps property.
          * 
          * @return
          *     possible object is
-         *     {@link Integer }
+         *     {@link Boolean }
          *     
          */
-        public Integer getWidth() {
-            return width;
+        public Boolean isIncludeGaps() {
+            return includeGaps;
         }
 
         /**
-         * Sets the value of the width property.
+         * Sets the value of the includeGaps property.
          * 
          * @param value
          *     allowed object is
-         *     {@link Integer }
+         *     {@link Boolean }
          *     
          */
-        public void setWidth(Integer value) {
-            this.width = value;
+        public void setIncludeGaps(Boolean value) {
+            this.includeGaps = value;
         }
 
         /**
-         * Gets the value of the height property.
+         * Gets the value of the matchGaps property.
          * 
          * @return
          *     possible object is
-         *     {@link Integer }
+         *     {@link Boolean }
          *     
          */
-        public Integer getHeight() {
-            return height;
+        public Boolean isMatchGaps() {
+            return matchGaps;
         }
 
         /**
-         * Sets the value of the height property.
+         * Sets the value of the matchGaps property.
          * 
          * @param value
          *     allowed object is
-         *     {@link Integer }
+         *     {@link Boolean }
          *     
          */
-        public void setHeight(Integer value) {
-            this.height = value;
+        public void setMatchGaps(Boolean value) {
+            this.matchGaps = value;
         }
 
         /**
-         * Gets the value of the xpos property.
+         * Gets the value of the includeGappedColumns property.
          * 
          * @return
          *     possible object is
-         *     {@link Integer }
+         *     {@link Boolean }
          *     
          */
-        public Integer getXpos() {
-            return xpos;
+        public Boolean isIncludeGappedColumns() {
+            return includeGappedColumns;
         }
 
         /**
-         * Sets the value of the xpos property.
+         * Sets the value of the includeGappedColumns property.
          * 
          * @param value
          *     allowed object is
-         *     {@link Integer }
+         *     {@link Boolean }
          *     
          */
-        public void setXpos(Integer value) {
-            this.xpos = value;
+        public void setIncludeGappedColumns(Boolean value) {
+            this.includeGappedColumns = value;
         }
 
         /**
-         * Gets the value of the ypos property.
+         * Gets the value of the denominateByShortestLength property.
          * 
          * @return
          *     possible object is
-         *     {@link Integer }
+         *     {@link Boolean }
          *     
          */
-        public Integer getYpos() {
-            return ypos;
+        public Boolean isDenominateByShortestLength() {
+            return denominateByShortestLength;
         }
 
         /**
-         * Sets the value of the ypos property.
+         * Sets the value of the denominateByShortestLength property.
          * 
          * @param value
          *     allowed object is
-         *     {@link Integer }
+         *     {@link Boolean }
          *     
          */
-        public void setYpos(Integer value) {
-            this.ypos = value;
+        public void setDenominateByShortestLength(Boolean value) {
+            this.denominateByShortestLength = value;
         }
 
         /**
-         * Gets the value of the includeGaps property.
+         * Gets the value of the width property.
          * 
          * @return
          *     possible object is
-         *     {@link Boolean }
+         *     {@link Integer }
          *     
          */
-        public Boolean isIncludeGaps() {
-            return includeGaps;
+        public Integer getWidth() {
+            return width;
         }
 
         /**
-         * Sets the value of the includeGaps property.
+         * Sets the value of the width property.
          * 
          * @param value
          *     allowed object is
-         *     {@link Boolean }
+         *     {@link Integer }
          *     
          */
-        public void setIncludeGaps(Boolean value) {
-            this.includeGaps = value;
+        public void setWidth(Integer value) {
+            this.width = value;
         }
 
         /**
-         * Gets the value of the matchGaps property.
+         * Gets the value of the height property.
          * 
          * @return
          *     possible object is
-         *     {@link Boolean }
+         *     {@link Integer }
          *     
          */
-        public Boolean isMatchGaps() {
-            return matchGaps;
+        public Integer getHeight() {
+            return height;
         }
 
         /**
-         * Sets the value of the matchGaps property.
+         * Sets the value of the height property.
          * 
          * @param value
          *     allowed object is
-         *     {@link Boolean }
+         *     {@link Integer }
          *     
          */
-        public void setMatchGaps(Boolean value) {
-            this.matchGaps = value;
+        public void setHeight(Integer value) {
+            this.height = value;
         }
 
         /**
-         * Gets the value of the includeGappedColumns property.
+         * Gets the value of the xpos property.
          * 
          * @return
          *     possible object is
-         *     {@link Boolean }
+         *     {@link Integer }
          *     
          */
-        public Boolean isIncludeGappedColumns() {
-            return includeGappedColumns;
+        public Integer getXpos() {
+            return xpos;
         }
 
         /**
-         * Sets the value of the includeGappedColumns property.
+         * Sets the value of the xpos property.
          * 
          * @param value
          *     allowed object is
-         *     {@link Boolean }
+         *     {@link Integer }
          *     
          */
-        public void setIncludeGappedColumns(Boolean value) {
-            this.includeGappedColumns = value;
+        public void setXpos(Integer value) {
+            this.xpos = value;
         }
 
         /**
-         * Gets the value of the denominateByShortestLength property.
+         * Gets the value of the ypos property.
          * 
          * @return
          *     possible object is
-         *     {@link Boolean }
+         *     {@link Integer }
          *     
          */
-        public Boolean isDenominateByShortestLength() {
-            return denominateByShortestLength;
+        public Integer getYpos() {
+            return ypos;
         }
 
         /**
-         * Sets the value of the denominateByShortestLength property.
+         * Sets the value of the ypos property.
          * 
          * @param value
          *     allowed object is
-         *     {@link Boolean }
+         *     {@link Integer }
          *     
          */
-        public void setDenominateByShortestLength(Boolean value) {
-            this.denominateByShortestLength = value;
+        public void setYpos(Integer value) {
+            this.ypos = value;
         }
 
 
@@ -4200,6 +4202,8 @@ public class JalviewModel {
      *       &lt;attribute name="markUnlinked" type="{http://www.w3.org/2001/XMLSchema}boolean" />
      *       &lt;attribute name="fitToWindow" type="{http://www.w3.org/2001/XMLSchema}boolean" />
      *       &lt;attribute name="currentTree" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+     *       &lt;attribute name="columnWise" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+     *       &lt;attribute name="columnReference" type="{http://www.w3.org/2001/XMLSchema}string" />
      *       &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" />
      *       &lt;attribute name="linkToAllViews" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
      *     &lt;/restriction>
@@ -4238,6 +4242,10 @@ public class JalviewModel {
         protected Boolean fitToWindow;
         @XmlAttribute(name = "currentTree")
         protected Boolean currentTree;
+        @XmlAttribute(name = "columnWise")
+        protected Boolean columnWise;
+        @XmlAttribute(name = "columnReference")
+        protected String columnReference;
         @XmlAttribute(name = "id")
         @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
         @XmlID
@@ -4519,6 +4527,58 @@ public class JalviewModel {
         }
 
         /**
+         * Gets the value of the columnWise property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Boolean }
+         *     
+         */
+        public boolean isColumnWise() {
+            if (columnWise == null) {
+                return false;
+            } else {
+                return columnWise;
+            }
+        }
+
+        /**
+         * Sets the value of the columnWise property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Boolean }
+         *     
+         */
+        public void setColumnWise(Boolean value) {
+            this.columnWise = value;
+        }
+
+        /**
+         * Gets the value of the columnReference property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link String }
+         *     
+         */
+        public String getColumnReference() {
+            return columnReference;
+        }
+
+        /**
+         * Sets the value of the columnReference property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link String }
+         *     
+         */
+        public void setColumnReference(String value) {
+            this.columnReference = value;
+        }
+
+        /**
          * Gets the value of the id property.
          * 
          * @return
index f383f52..b62cf15 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index 752b37d..7a86123 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index b1dbda2..10d3d5b 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index f201c32..d884100 100644 (file)
@@ -2,18 +2,20 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
 package jalview.xml.binding.jalview;
 
 import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
 
 
 /**
@@ -23,14 +25,22 @@ import javax.xml.bind.annotation.XmlValue;
  * 
  * <pre>
  * &lt;complexType name="MatrixType">
- *   &lt;simpleContent>
- *     &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
- *       &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="elements" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         &lt;element name="groups" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ *         &lt;element name="newick" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
+ *         &lt;element name="property" type="{www.vamsas.ac.uk/jalview/version2}property" maxOccurs="unbounded" minOccurs="0"/>
+ *       &lt;/sequence>
  *       &lt;attribute name="type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
  *       &lt;attribute name="rows" use="required" type="{http://www.w3.org/2001/XMLSchema}integer" />
  *       &lt;attribute name="cols" use="required" type="{http://www.w3.org/2001/XMLSchema}integer" />
- *     &lt;/extension>
- *   &lt;/simpleContent>
+ *       &lt;attribute name="treeMethod" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *       &lt;attribute name="cutHeight" type="{http://www.w3.org/2001/XMLSchema}double" />
+ *       &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
  * &lt;/complexType>
  * </pre>
  * 
@@ -38,67 +48,140 @@ import javax.xml.bind.annotation.XmlValue;
  */
 @XmlAccessorType(XmlAccessType.FIELD)
 @XmlType(name = "MatrixType", propOrder = {
-    "value"
+    "elements",
+    "groups",
+    "newick",
+    "property"
 })
 public class MatrixType {
 
-    @XmlValue
-    protected String value;
-    @XmlAttribute(name = "id")
-    protected String id;
+    @XmlElement(required = true)
+    protected String elements;
+    protected List<String> groups;
+    protected List<String> newick;
+    protected List<Property> property;
     @XmlAttribute(name = "type", required = true)
     protected String type;
     @XmlAttribute(name = "rows", required = true)
     protected BigInteger rows;
     @XmlAttribute(name = "cols", required = true)
     protected BigInteger cols;
+    @XmlAttribute(name = "treeMethod")
+    protected String treeMethod;
+    @XmlAttribute(name = "cutHeight")
+    protected Double cutHeight;
+    @XmlAttribute(name = "id")
+    protected String id;
 
     /**
-     * Gets the value of the value property.
+     * Gets the value of the elements property.
      * 
      * @return
      *     possible object is
      *     {@link String }
      *     
      */
-    public String getValue() {
-        return value;
+    public String getElements() {
+        return elements;
     }
 
     /**
-     * Sets the value of the value property.
+     * Sets the value of the elements property.
      * 
      * @param value
      *     allowed object is
      *     {@link String }
      *     
      */
-    public void setValue(String value) {
-        this.value = value;
+    public void setElements(String value) {
+        this.elements = value;
     }
 
     /**
-     * Gets the value of the id property.
+     * Gets the value of the groups property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the groups property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getGroups().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link String }
+     * 
      * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
      */
-    public String getId() {
-        return id;
+    public List<String> getGroups() {
+        if (groups == null) {
+            groups = new ArrayList<String>();
+        }
+        return this.groups;
     }
 
     /**
-     * Sets the value of the id property.
+     * Gets the value of the newick property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the newick property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getNewick().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link String }
+     * 
      * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
      */
-    public void setId(String value) {
-        this.id = value;
+    public List<String> getNewick() {
+        if (newick == null) {
+            newick = new ArrayList<String>();
+        }
+        return this.newick;
+    }
+
+    /**
+     * Gets the value of the property property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the property property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getProperty().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Property }
+     * 
+     * 
+     */
+    public List<Property> getProperty() {
+        if (property == null) {
+            property = new ArrayList<Property>();
+        }
+        return this.property;
     }
 
     /**
@@ -173,4 +256,76 @@ public class MatrixType {
         this.cols = value;
     }
 
+    /**
+     * Gets the value of the treeMethod property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getTreeMethod() {
+        return treeMethod;
+    }
+
+    /**
+     * Sets the value of the treeMethod property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setTreeMethod(String value) {
+        this.treeMethod = value;
+    }
+
+    /**
+     * Gets the value of the cutHeight property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Double }
+     *     
+     */
+    public Double getCutHeight() {
+        return cutHeight;
+    }
+
+    /**
+     * Sets the value of the cutHeight property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Double }
+     *     
+     */
+    public void setCutHeight(Double value) {
+        this.cutHeight = value;
+    }
+
+    /**
+     * Gets the value of the id property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Sets the value of the id property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setId(String value) {
+        this.id = value;
+    }
+
 }
index dd1357d..22b78a5 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index ea5428a..f034a2a 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
@@ -283,11 +283,11 @@ public class ObjectFactory {
     }
 
     /**
-     * Create an instance of {@link Annotation.Property }
+     * Create an instance of {@link jalview.xml.binding.jalview.Property }
      * 
      */
-    public Annotation.Property createAnnotationProperty() {
-        return new Annotation.Property();
+    public jalview.xml.binding.jalview.Property createProperty() {
+        return new jalview.xml.binding.jalview.Property();
     }
 
     /**
index a510399..06aecab 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index 8c3a499..401022a 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
diff --git a/src/jalview/xml/binding/jalview/Property.java b/src/jalview/xml/binding/jalview/Property.java
new file mode 100644 (file)
index 0000000..3c0879d
--- /dev/null
@@ -0,0 +1,92 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
+//
+
+
+package jalview.xml.binding.jalview;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for property complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="property">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *       &lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "property")
+public class Property {
+
+    @XmlAttribute(name = "name")
+    protected String name;
+    @XmlAttribute(name = "value")
+    protected String value;
+
+    /**
+     * Gets the value of the name property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the value of the name property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setName(String value) {
+        this.name = value;
+    }
+
+    /**
+     * Gets the value of the value property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * Sets the value of the value property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+}
index 09fdcb5..d02fd03 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index f50e4cb..a915d94 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index 0a360ed..fa65d58 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index f717f2e..192caf8 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index 0983075..dd41877 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index 9baa3bc..d3c2098 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 
index 5bb7db6..2cfefda 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:57 PM GMT 
+// Generated on: 2023.03.17 at 05:31:44 PM GMT 
 //
 
 @javax.xml.bind.annotation.XmlSchema(namespace = "www.vamsas.ac.uk/jalview/version2", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
index a7381a1..de12eb2 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 693e586..e9244e9 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 72ca25c..e0692c9 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index a2db65a..71db504 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index d3c111e..73ccfa8 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 7c485d5..21963a8 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index ed97121..0b4d4bd 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 4e99255..59c9857 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index caa9d94..0fa25a6 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index ca03a54..f818e2e 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 998d1b9..f2d5638 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index dc03075..71af71f 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index d419e09..5fa628e 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 1dacab8..3d6c308 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index d579506..c9cadc2 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 69b251e..ea55664 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 5497e6d..f6409ee 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 78a388b..62e9999 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index e734c27..8b52523 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index c638af7..be68867 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 0459e04..e2bb255 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 312c0ee..bc5c8c5 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 55774e3..bb76add 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 2b130f2..1354092 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 445f99f..e674452 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 05b6afc..a00d698 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index c9324b0..c9f169c 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index f7f989a..c34a0f5 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 5f1a018..7b106fb 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 806a8f7..8d9d51d 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index e00e9a7..e5f9fde 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index e747820..49cd130 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 9598976..9796260 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 755ca21..9293a64 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 63c281d..dd3308b 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index bebbd62..97522e2 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 1de89de..14f96df 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 
index 560368d..a7bc67c 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2023.02.22 at 10:08:58 PM GMT 
+// Generated on: 2023.03.17 at 05:31:46 PM GMT 
 //
 
 @javax.xml.bind.annotation.XmlSchema(namespace = "http://uniprot.org/uniprot", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
index 8b6f67d..4baa384 100644 (file)
@@ -2608,15 +2608,15 @@ public class AlignmentUtilsTests
     SequenceI sq = new Sequence("a", "SSSQ");
     ContactMatrixI cm = new SeqDistanceContactMatrix(4);
     AlignmentAnnotation cm_aan = sq.addContactList(cm);
+    cm_aan.description = cm_aan.description + " cm1";
     SequenceI dssq = sq.createDatasetSequence();
-    Alignment ds = new Alignment(new SequenceI[] { dssq });
 
     // remove annotation on our non-dataset sequence
     sq.removeAlignmentAnnotation(sq.getAnnotation()[0]);
     // test transfer
     Alignment al = new Alignment(new SequenceI[] { sq });
     SortedMap<String, String> tipEntries = new TreeMap<>();
-    final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
+    Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
 
     AlignmentUtils.findAddableReferenceAnnotations(al.getSequences(),
             tipEntries, candidates, al);
@@ -2630,6 +2630,23 @@ public class AlignmentUtilsTests
     assertNotNull(
             "No contact matrix recovered after reference annotation transfer",
             cl);
+    // semantics of sequence associated contact list is slightly tricky - column 3 in alignment should have data
+    cl = al.getContactListFor(alan, 3);
+    assertNotNull(
+            "Contact matrix should have data for last position in sequence",
+            cl);
+
+    ContactMatrixI cm2 = new SeqDistanceContactMatrix(4);
+    dssq.addContactList(cm2);
+    tipEntries = new TreeMap<>();
+    candidates = new LinkedHashMap<>();
+
+    AlignmentUtils.findAddableReferenceAnnotations(al.getSequences(),
+            tipEntries, candidates, al);
+    AlignmentUtils.addReferenceAnnotations(candidates, al, null);
+    assertTrue("Expected two contact map annotation transferred",
+            al.getAlignmentAnnotation() != null
+                    && al.getAlignmentAnnotation().length == 2);
 
   }
 }
diff --git a/test/jalview/analysis/AverageDistanceEngineTest.java b/test/jalview/analysis/AverageDistanceEngineTest.java
new file mode 100644 (file)
index 0000000..6d9ab50
--- /dev/null
@@ -0,0 +1,97 @@
+package jalview.analysis;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import jalview.bin.Cache;
+import jalview.bin.Console;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.BinaryNode;
+import jalview.datamodel.ContactMatrixI;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.JvOptionPane;
+import jalview.io.DataSourceType;
+import jalview.io.FastaFile;
+import jalview.io.FileLoader;
+import jalview.io.FormatAdapter;
+import jalview.util.Platform;
+import jalview.ws.datamodel.alphafold.PAEContactMatrix;
+
+public class AverageDistanceEngineTest
+{
+
+    @BeforeClass(alwaysRun = true)
+    public void setUpJvOptionPane()
+    {
+      JvOptionPane.setInteractiveMode(false);
+      JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+    }
+
+    @BeforeMethod(alwaysRun = true)
+    public void loadProperties()
+    {
+      Cache.loadProperties("test/jalview/bin/TestProps.jvprops");
+    }
+    @Test
+    public void testUPGMAEngine() throws Exception
+    {
+      AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded("examples/test_fab41.result/sample.a3m",DataSourceType.FILE);
+      AlignmentI seqs = af.getViewport().getAlignment();
+      SequenceI target = seqs.getSequenceAt(0);
+      File testPAE = new File("examples/test_fab41.result/test_fab41_predicted_aligned_error_v1.json");
+      List<Object> pae_obj = (List<Object>) Platform.parseJSON(new FileInputStream(testPAE));
+      if (pae_obj == null)
+      {
+        Assert.fail("JSON PAE file did not parse properly.");
+      }
+      ContactMatrixI matrix = new PAEContactMatrix(target,
+              (Map<String, Object>) pae_obj.get(0));
+      AlignmentAnnotation aa = target.addContactList(matrix);
+      System.out.println("Matrix has max="+matrix.getMax()+" and min="+matrix.getMin());
+      long start = System.currentTimeMillis();
+      AverageDistanceEngine clusterer = new AverageDistanceEngine(af.getViewport(), null, matrix);
+      System.out.println("built a tree in "+(System.currentTimeMillis()-start)*0.001+" seconds.");
+      StringBuffer sb = new StringBuffer(); 
+      System.out.println("Newick string\n"+      new jalview.io.NewickFile(clusterer.getTopNode(),true,true).print());
+      
+      double height = clusterer.findHeight(clusterer.getTopNode());
+      // compute height fraction to cut 
+      // PAE matrixes are absolute measure in angstrom, so 
+      // cluster all regions within threshold (e.g. 2A) - if height above threshold. Otherwise all nodes are in one cluster
+      double thr=.2;
+      List<BinaryNode> groups;
+      if (height>thr)
+      {
+        float cut = (float) (thr/height);
+        System.out.println("Threshold "+cut+" for height="+height);
+        groups = clusterer.groupNodes(cut);
+      } else{
+        groups=new ArrayList<BinaryNode>();
+        groups.add(clusterer.getTopNode());
+      }
+      int n=1;
+      for (BinaryNode root:groups)
+      {
+        System.out.println("Cluster "+n++);
+        for (BinaryNode leaf:clusterer.findLeaves(root))
+        {
+          System.out.print(" "+leaf.getName());
+        }
+        System.out.println("\\");
+      }
+      
+    }
+
+}
index 43be888..f6a7f42 100644 (file)
@@ -104,6 +104,7 @@ public class ContactMatrixTest
       }
 
     });
+    // TODO - write test !
   }
 
   /**
@@ -112,6 +113,7 @@ public class ContactMatrixTest
   @Test(groups = { "Functional" })
   public void testAsymmetricContactMatrix()
   {
+    // TODO - write test !
 
   }
 
@@ -121,6 +123,7 @@ public class ContactMatrixTest
   @Test(groups = { "Functional" })
   public void testSymmetricContactMatrix()
   {
+    // TODO - write test !
 
   }
 
index beedb11..466f218 100644 (file)
@@ -24,6 +24,7 @@ import static org.testng.ConversionUtils.wrapDataProvider;
 
 import jalview.analysis.SequenceIdMatcher;
 import jalview.analysis.TreeModel;
+import jalview.datamodel.BinaryNode;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.SequenceNode;
 import jalview.gui.JvOptionPane;
@@ -105,7 +106,7 @@ public class NewickFileTests
       AssertJUnit.assertTrue(
               stage + "Invalid Tree '" + nf.getWarningMessage() + "'",
               nf.isValid());
-      SequenceNode tree = nf.getTree();
+      BinaryNode tree = nf.getTree();
       AssertJUnit.assertTrue(stage + "Null Tree", tree != null);
       stage = "Creating newick file from testTree " + treename;
       String gentree = new NewickFile(tree).print(nf.HasBootstrap(),
@@ -119,11 +120,11 @@ public class NewickFileTests
               stage + "Newick file is invalid ('"
                       + nf_regen.getWarningMessage() + "')",
               nf_regen.isValid());
-      SequenceNode tree_regen = nf.getTree();
+      BinaryNode tree_regen = nf.getTree();
       AssertJUnit.assertTrue(stage + "Null Tree", tree_regen != null);
       stage = "Compare original and generated tree" + treename;
 
-      Vector<SequenceNode> oseqs, nseqs;
+      Vector<BinaryNode> oseqs, nseqs;
       oseqs = new TreeModel(new SequenceI[0], null, nf)
               .findLeaves(nf.getTree());
       AssertJUnit.assertTrue(stage + "No nodes in original tree.",
index 13df735..af52eda 100644 (file)
@@ -1571,7 +1571,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     float[][] vals = ContactMatrix.fromFloatStringToContacts(content,
             sq.getLength(), sq.getLength());
     assertEquals(vals[3][4], paevals[3][4]);
-
+    dummyMat.makeGroups(0.5f, false);
+    Assert.assertNotSame(dummyMat.getNewick(), "");
     AlignmentAnnotation paeCm = sq.addContactList(dummyMat);
     al.addAnnotation(paeCm);
     File tfile = File.createTempFile("testStoreAndRecoverPAEmatrix",
@@ -1602,6 +1603,10 @@ public class Jalview2xmlTests extends Jalview2xmlBase
         Assert.assertEquals(oldCM.getContactAt(j), newCM.getContactAt(j));
       }
     }
+    Assert.assertEquals(restoredMat.hasGroups(), dummyMat.hasGroups());
+    Assert.assertEquals(restoredMat.getGroups(), dummyMat.getGroups());
+    Assert.assertEquals(restoredMat.hasTree(), dummyMat.hasTree());
+    Assert.assertEquals(restoredMat.getNewick(), dummyMat.getNewick());
 
   }