Merge branch 'develop' into features/JAL-4134_use_annotation_row_for_colours_and_groups
authorJames Procter <j.procter@dundee.ac.uk>
Fri, 19 May 2023 17:07:01 +0000 (18:07 +0100)
committerJames Procter <j.procter@dundee.ac.uk>
Fri, 19 May 2023 17:07:01 +0000 (18:07 +0100)
 Conflicts:
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/ContactMatrix.java
src/jalview/datamodel/ContactMatrixI.java
src/jalview/datamodel/SeqDistanceContactMatrix.java
src/jalview/datamodel/annotations/AnnotationRowBuilder.java
src/jalview/ext/jmol/JmolParser.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/TreeCanvas.java
src/jalview/project/Jalview2XML.java
src/jalview/renderer/ContactMapRenderer.java
src/jalview/ws/datamodel/alphafold/PAEContactMatrix.java
src/jalview/ws/dbsources/EBIAlfaFold.java
src/jalview/xml/binding/jalview/MatrixType.java
test/jalview/analysis/AverageDistanceEngineTest.java
test/jalview/project/Jalview2xmlTests.java

110 files changed:
resources/lang/Messages.properties
schemas/vamsas.xsd
src/jalview/analysis/AlignmentUtils.java
src/jalview/analysis/AverageDistanceEngine.java
src/jalview/analysis/TreeModel.java
src/jalview/api/AlignViewportI.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/BinaryNode.java
src/jalview/datamodel/ColumnSelection.java
src/jalview/datamodel/ContactListI.java
src/jalview/datamodel/ContactListImpl.java
src/jalview/datamodel/ContactListProviderI.java
src/jalview/datamodel/ContactMapHolder.java
src/jalview/datamodel/ContactMatrix.java
src/jalview/datamodel/ContactMatrixI.java
src/jalview/datamodel/GroupSet.java [new file with mode: 0644]
src/jalview/datamodel/GroupSetI.java [new file with mode: 0644]
src/jalview/datamodel/SeqDistanceContactMatrix.java
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceNode.java
src/jalview/ext/jmol/JmolParser.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/AnnotationPanel.java
src/jalview/gui/StructureChooser.java
src/jalview/gui/TreeCanvas.java
src/jalview/io/vamsas/Tree.java
src/jalview/jbgui/GStructureChooser.java
src/jalview/project/Jalview2XML.java
src/jalview/renderer/ContactGeometry.java
src/jalview/renderer/ContactMapRenderer.java
src/jalview/structures/models/AAStructureBindingModel.java
src/jalview/ws/datamodel/MappableContactMatrixI.java [new file with mode: 0644]
src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java [new file with mode: 0644]
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
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
src/mc_view/PDBChain.java
test/jalview/analysis/AlignmentUtilsTests.java
test/jalview/analysis/AverageDistanceEngineTest.java
test/jalview/datamodel/PAEContactMatrixTest.java [new file with mode: 0644]
test/jalview/project/Jalview2xmlTests.java

index 006886f..36572ed 100644 (file)
@@ -449,6 +449,7 @@ label.input_cut_paste_params = Cut & Paste Input - {0}
 label.alignment_output_command = Alignment output - {0}
 label.annotations = Annotations
 label.structure_options = Structure Options
+label.structure_import_options = Structure Import Options
 label.features = Features
 label.overview_params = Overview {0}
 label.paste_newick_file = Paste Newick file
@@ -1448,5 +1449,7 @@ label.tftype_default = Default
 label.tftype_plddt = pLDDT
 label.optional = (optional)
 label.choose_tempfac_type = Choose Temperature Factor type
+label.interpret_tempfac_as = Interpret Temperature Factor as
 label.add_pae_matrix_file = Add PAE matrix file
 label.nothing_selected = Nothing selected
+label.working_ellipsis = Working ... 
\ No newline at end of file
index abfabb1..fedbae3 100755 (executable)
                        <xs:element name="groups" type="xs:string" minOccurs="0"
                                maxOccurs="unbounded">
                                <xs:annotation>
-                                       <xs:documentation>Comma separated series of BigIntegers formed from
+                                       <xs:documentation>Comma separated series of longs formed from
                                                bitsets defining partitions on the rows/columns of the matrix
                                        </xs:documentation>
                                </xs:annotation>
                        </xs:element>
                        <xs:element name="property" type="vamsas:property"
                                minOccurs="0" maxOccurs="unbounded" />
+                       <xs:element name="mapping" type="vamsas:mapListType"
+                               minOccurs="0" maxOccurs="1">
+                       <xs:annotation>
+                               <xs:documentation>mapping from the matrix row and column positions to
+                                       associated reference frame</xs:documentation>
+                               </xs:annotation>
+                       </xs:element>
                </xs:sequence>
 
                <xs:attribute name="type" type="xs:string" use="required" />
index 201f88b..1158c53 100644 (file)
@@ -1504,7 +1504,8 @@ public class AlignmentUtils
 
   /**
    * Adds annotations to the top of the alignment annotations, in the same order
-   * as their related sequences.
+   * as their related sequences. If you already have an annotation and want to
+   * add it to a sequence in an alignment use {@code addReferenceAnnotationTo}
    * 
    * @param annotations
    *          the annotations to add
@@ -1521,38 +1522,60 @@ public class AlignmentUtils
     {
       for (AlignmentAnnotation ann : annotations.get(seq))
       {
-        AlignmentAnnotation copyAnn = new AlignmentAnnotation(ann);
-        int startRes = 0;
-        int endRes = ann.annotations.length;
-        if (selectionGroup != null)
-        {
-          startRes = selectionGroup.getStartRes();
-          endRes = selectionGroup.getEndRes();
-        }
-        copyAnn.restrict(startRes, endRes + 0);
+        addReferenceAnnotationTo(alignment, seq, ann, selectionGroup);
+      }
+    }
+  }
 
-        /*
-         * Add to the sequence (sets copyAnn.datasetSequence), unless the
-         * original annotation is already on the sequence.
-         */
-        if (!seq.hasAnnotation(ann))
-        {
-          ContactMatrixI cm = seq.getDatasetSequence()
-                  .getContactMatrixFor(ann);
-          if (cm != null)
-          {
-            seq.addContactListFor(copyAnn, cm);
-          }
-          seq.addAlignmentAnnotation(copyAnn);
-        }
-        // adjust for gaps
-        copyAnn.adjustForAlignment();
-        // add to the alignment and set visible
-        alignment.addAnnotation(copyAnn);
-        copyAnn.visible = true;
+  /**
+   * Make a copy of a reference annotation {@code ann} and add it to an
+   * alignment sequence {@code seq} in {@code alignment}, optionally limited to
+   * the extent of {@code selectionGroup}
+   * 
+   * @param alignment
+   * @param seq
+   * @param ann
+   * @param selectionGroup
+   *          - may be null
+   * @return annotation added to {@code seq and {@code alignment}
+   */
+  public static AlignmentAnnotation addReferenceAnnotationTo(
+          final AlignmentI alignment, final SequenceI seq,
+          final AlignmentAnnotation ann, final SequenceGroup selectionGroup)
+  {
+    AlignmentAnnotation copyAnn = new AlignmentAnnotation(ann);
+    int startRes = 0;
+    int endRes = ann.annotations.length;
+    if (selectionGroup != null)
+    {
+      startRes = -1 + Math.min(seq.getEnd(), Math.max(seq.getStart(),
+              seq.findPosition(selectionGroup.getStartRes())));
+      endRes = -1 + Math.min(seq.getEnd(),
+              seq.findPosition(selectionGroup.getEndRes()));
+
+    }
+    copyAnn.restrict(startRes, endRes + 0);
+
+    /*
+     * Add to the sequence (sets copyAnn.datasetSequence), unless the
+     * original annotation is already on the sequence.
+     */
+    if (!seq.hasAnnotation(ann))
+    {
+      ContactMatrixI cm = seq.getDatasetSequence().getContactMatrixFor(ann);
+      if (cm != null)
+      {
+        seq.addContactListFor(copyAnn, cm);
       }
+      seq.addAlignmentAnnotation(copyAnn);
     }
+    // adjust for gaps
+    copyAnn.adjustForAlignment();
+    // add to the alignment and set visible
+    alignment.addAnnotation(copyAnn);
+    copyAnn.visible = true;
 
+    return copyAnn;
   }
 
   /**
index e6a763b..20b3e83 100644 (file)
@@ -105,6 +105,10 @@ public class AverageDistanceEngine extends TreeEngine
       {
         distances.setValue(i, i, 0);
         ContactListI jth = cm.getContactList(j);
+        if (jth == null)
+        {
+          break;
+        }
         double prd = 0;
         for (int indx = 0; indx < cm.getHeight(); indx++)
         {
index 6260067..0e57a58 100644 (file)
@@ -408,8 +408,8 @@ public class TreeModel
     }
     else
     {
-      _groupNodes(groups, (SequenceNode) nd.left(), threshold);
-      _groupNodes(groups, (SequenceNode) nd.right(), threshold);
+      _groupNodes(groups, nd.left(), threshold);
+      _groupNodes(groups, nd.right(), threshold);
     }
   }
 
index 03efec5..0cfd03d 100644 (file)
@@ -477,6 +477,15 @@ public interface AlignViewportI extends ViewStyleI
    */
   SearchResultsI getSearchResults();
 
+  /**
+   * Retrieve a ContactListI corresponding to column in an annotation row in an
+   * alignment.
+   * 
+   * @param _aa
+   *          - annotation with associated matrix data
+   * @param column
+   *          - column in alignment where _aa is associated
+   */
   ContactListI getContactList(AlignmentAnnotation _aa, int column);
 
   /**
index 4d3d578..514a326 100755 (executable)
@@ -2076,16 +2076,19 @@ public class Alignment implements AlignmentI, AutoCloseable
     }
     if (cl == null && _aa.sequenceRef != null)
     {
-      int spos = _aa.sequenceRef.findPosition(column);
-      if (spos >= _aa.sequenceRef.getStart()
-              && spos <= 1 + _aa.sequenceRef.getEnd())
+      if (_aa.annotations[column] != null)
       {
-        cl = _aa.sequenceRef.getContactListFor(_aa,
-                spos - _aa.sequenceRef.getStart());
+        // sequence associated
+        cl = _aa.sequenceRef.getContactListFor(_aa, column);
         if (cl == null && _aa.sequenceRef.getDatasetSequence() != null)
         {
-          _aa.sequenceRef.getDatasetSequence().getContactListFor(_aa,
-                  spos - _aa.sequenceRef.getStart());
+          int spos = _aa.sequenceRef.findPosition(column);
+          if (spos >= _aa.sequenceRef.getStart()
+                  && spos <= 1 + _aa.sequenceRef.getEnd())
+          {
+            cl = _aa.sequenceRef.getDatasetSequence().getContactListFor(_aa,
+                    spos - _aa.sequenceRef.getStart());
+          }
         }
       }
     }
@@ -2098,8 +2101,7 @@ public class Alignment implements AlignmentI, AutoCloseable
     AlignmentAnnotation aa = cmholder.addContactList(cm);
 
     Annotation _aa[] = new Annotation[getWidth()];
-    Annotation dummy = new Annotation(0.0f);
-    for (int i = 0; i < _aa.length; _aa[i++] = dummy)
+    for (int i = 0; i < _aa.length; _aa[i++] = new Annotation(0.0f))
     {
       ;
     }
index 5b55594..624c2b9 100755 (executable)
@@ -23,22 +23,22 @@ package jalview.datamodel;
 import java.awt.Color;
 
 /**
- * DOCUMENT ME!
+ * Represent a node in a binary tree
  * 
- * @author $author$
+ * @author $mclamp (probably!)$
  * @version $Revision$
  */
-public class BinaryNode
+public class BinaryNode<T>
 {
-  Object element;
+  T element;
 
   String name;
 
-  BinaryNode left;
+  BinaryNode<T> left;
 
-  BinaryNode right;
+  BinaryNode<T> right;
 
-  BinaryNode parent;
+  BinaryNode<T> parent;
 
   /** Bootstrap value */
   public int bootstrap;
@@ -58,7 +58,10 @@ public class BinaryNode
   /** DOCUMENT ME!! */
   public Color color = Color.black;
 
-  /** DOCUMENT ME!! */
+  /**
+   * if true, node is created to simulate polytomy between parent and its 3 or
+   * more children
+   */
   public boolean dummy = false;
 
   /**
@@ -81,7 +84,7 @@ public class BinaryNode
    * @param name
    *          DOCUMENT ME!
    */
-  public BinaryNode(Object element, BinaryNode parent, String name,
+  public BinaryNode(T element, BinaryNode<T> parent, String name,
           double dist)
   {
     this();
@@ -91,14 +94,14 @@ public class BinaryNode
     this.dist = dist;
   }
 
-  public BinaryNode(Object element, BinaryNode parent, String name,
+  public BinaryNode(T element, BinaryNode<T> parent, String name,
           double dist, int bootstrap)
   {
     this(element, parent, name, dist);
     this.bootstrap = bootstrap;
   }
 
-  public BinaryNode(Object val, BinaryNode parent, String name, double dist,
+  public BinaryNode(T val, BinaryNode<T> parent, String name, double dist,
           int bootstrap, boolean dummy)
   {
     this(val, parent, name, dist, bootstrap);
@@ -110,7 +113,7 @@ public class BinaryNode
    * 
    * @return DOCUMENT ME!
    */
-  public Object element()
+  public T element()
   {
     return element;
   }
@@ -123,7 +126,7 @@ public class BinaryNode
    * 
    * @return DOCUMENT ME!
    */
-  public Object setElement(Object v)
+  public T setElement(T v)
   {
     return element = v;
   }
@@ -133,7 +136,7 @@ public class BinaryNode
    * 
    * @return DOCUMENT ME!
    */
-  public BinaryNode left()
+  public BinaryNode<T> left()
   {
     return left;
   }
@@ -146,7 +149,7 @@ public class BinaryNode
    * 
    * @return DOCUMENT ME!
    */
-  public BinaryNode setLeft(BinaryNode n)
+  public BinaryNode<T> setLeft(BinaryNode<T> n)
   {
     return left = n;
   }
@@ -156,7 +159,7 @@ public class BinaryNode
    * 
    * @return DOCUMENT ME!
    */
-  public BinaryNode right()
+  public BinaryNode<T> right()
   {
     return right;
   }
@@ -169,7 +172,7 @@ public class BinaryNode
    * 
    * @return DOCUMENT ME!
    */
-  public BinaryNode setRight(BinaryNode n)
+  public BinaryNode<T> setRight(BinaryNode<T> n)
   {
     return right = n;
   }
@@ -179,7 +182,7 @@ public class BinaryNode
    * 
    * @return DOCUMENT ME!
    */
-  public BinaryNode parent()
+  public BinaryNode<T> parent()
   {
     return parent;
   }
@@ -192,7 +195,7 @@ public class BinaryNode
    * 
    * @return DOCUMENT ME!
    */
-  public BinaryNode setParent(BinaryNode n)
+  public BinaryNode<T> setParent(BinaryNode<T> n)
   {
     return parent = n;
   }
@@ -214,7 +217,7 @@ public class BinaryNode
    * setChild(null), or detach() for this.
    * 
    */
-  public void SetChildren(BinaryNode leftchild, BinaryNode rightchild)
+  public void SetChildren(BinaryNode<T> leftchild, BinaryNode<T> rightchild)
   {
     if (leftchild != null)
     {
@@ -236,7 +239,7 @@ public class BinaryNode
    * 
    * @return BinaryNode The detached node.
    */
-  public BinaryNode detach()
+  public BinaryNode<T> detach()
   {
     if (this.parent != null)
     {
@@ -264,9 +267,9 @@ public class BinaryNode
    * 
    * @return BinaryNode
    */
-  public BinaryNode ascendLeft()
+  public BinaryNode<T> ascendLeft()
   {
-    BinaryNode c = this;
+    BinaryNode<T> c = this;
 
     do
     {
@@ -283,9 +286,9 @@ public class BinaryNode
    * 
    * @return BinaryNode
    */
-  public BinaryNode ascendRight()
+  public BinaryNode<T> ascendRight()
   {
-    BinaryNode c = this;
+    BinaryNode<T> c = this;
 
     do
     {
@@ -366,9 +369,9 @@ public class BinaryNode
    * ascends the tree but doesn't stop until a non-dummy node is discovered.
    * 
    */
-  public BinaryNode AscendTree()
+  public BinaryNode<T> AscendTree()
   {
-    BinaryNode c = this;
+    BinaryNode<T> c = this;
 
     do
     {
index 3c2d166..4a38ec0 100644 (file)
@@ -278,6 +278,27 @@ public class ColumnSelection
   }
 
   /**
+   * add a series of start,end (inclusive) ranges to the column selection
+   * 
+   * @param rng
+   *          [start_0, end_0, start_1, end_1, ... ]
+   * @param baseOne
+   *          - when true, ranges are base 1 and will be mapped to base 0
+   */
+  public void addRangeOfElements(int[] rng, boolean baseOne)
+  {
+    int base = baseOne ? -1 : 0;
+    for (int c = 0; c < rng.length; c += 2)
+    {
+      for (int p = rng[c]; p <= rng[c + 1]; p++)
+      {
+        selection.add(base + p);
+      }
+    }
+
+  }
+
+  /**
    * clears column selection
    */
   public void clear()
index ac06adb..da55403 100644 (file)
@@ -1,5 +1,9 @@
 package jalview.datamodel;
 
+import java.awt.Color;
+
+import jalview.renderer.ContactGeometry.contactInterval;
+
 public interface ContactListI extends ContactListProviderI
 {
 
@@ -12,4 +16,8 @@ public interface ContactListI extends ContactListProviderI
    */
   ContactRange getRangeFor(int from_column, int to_column);
 
+  default Color getColourForGroup()
+  {
+    return null;
+  }
 }
index 8e806e4..69dcf71 100644 (file)
@@ -1,5 +1,9 @@
 package jalview.datamodel;
 
+import java.awt.Color;
+
+import jalview.renderer.ContactGeometry.contactInterval;
+
 /**
  * helper class to compute min/max/mean for a range on a contact list
  * 
@@ -95,4 +99,15 @@ public class ContactListImpl implements ContactListI
     return cr;
   }
 
+  @Override
+  public int[] getMappedPositionsFor(int cStart, int cEnd)
+  {
+    return clist.getMappedPositionsFor(cStart, cEnd);
+  }
+
+  @Override
+  public Color getColourForGroup()
+  {
+    return clist.getColourForGroup();
+  }
 }
index f027e01..d6e9ba9 100644 (file)
@@ -1,5 +1,7 @@
 package jalview.datamodel;
 
+import java.awt.Color;
+
 public interface ContactListProviderI
 {
 
@@ -26,4 +28,23 @@ public interface ContactListProviderI
    */
   double getContactAt(int column);
 
+  /**
+   * Return positions in local reference corresponding to cStart and cEnd in
+   * matrix data. Positions are base 1 column indices for sequence associated
+   * matrices.
+   * 
+   * @param cStart
+   * @param cEnd
+   * @return int[] { start, end (inclusive) for each contiguous segment}
+   */
+  default int[] getMappedPositionsFor(int cStart, int cEnd)
+  {
+    return new int[] { cStart, cEnd };
+  }
+
+  default Color getColourForGroup()
+  {
+    return null;
+  }
+
 }
index 296feaf..af083dd 100644 (file)
@@ -5,6 +5,8 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
+import jalview.ws.datamodel.MappableContactMatrixI;
+
 public class ContactMapHolder implements ContactMapHolderI
 {
 
@@ -28,6 +30,14 @@ public class ContactMapHolder implements ContactMapHolderI
     {
       return null;
     }
+    if (cm instanceof MappableContactMatrixI)
+    {
+      if (_aa.sequenceRef != null)
+      {
+        return ((MappableContactMatrixI) cm)
+                .getMappableContactList(_aa.sequenceRef, column);
+      }
+    }
     // TODO: could resolve sequence position to column position here
     // TODO: what about for complexes - where contactMatrix may involve two or
     // more sequences
@@ -49,9 +59,9 @@ public class ContactMapHolder implements ContactMapHolderI
     contactmaps.put(aa.annotationId, cm);
     // TODO: contact matrices could be intra or inter - more than one refseq
     // possible!
-    if (cm.hasReferenceSeq())
+    if (cm instanceof MappableContactMatrixI)
     {
-      aa.setSequenceRef(cm.getReferenceSeq());
+      aa.setSequenceRef(((MappableContactMatrixI) cm).getReferenceSeq());
     }
     return aa;
   }
index 8434b4a..48b6e6b 100644 (file)
@@ -1,10 +1,12 @@
 package jalview.datamodel;
 
 import java.awt.Color;
+import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Spliterator;
 import java.util.StringTokenizer;
 
 import jalview.bin.Console;
@@ -148,20 +150,6 @@ public abstract class ContactMatrix implements ContactMatrixI
   }
 
   @Override
-  public boolean hasReferenceSeq()
-  {
-    // TODO Auto-generated method stub
-    return false;
-  }
-
-  @Override
-  public SequenceI getReferenceSeq()
-  {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
   public String getAnnotLabel()
   {
     return "Contact Matrix";
@@ -172,64 +160,17 @@ 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<>();
-
+  GroupSet grps = new GroupSet();
   @Override
-  public Color getColourForGroup(BitSet bs)
+  public GroupSetI getGroupSet()
   {
-    if (bs == null)
-    {
-      return Color.white;
-    }
-    Color groupCol = colorMap.get(bs);
-    if (groupCol == null)
-    {
-      return Color.white;
-    }
-    return groupCol;
+    return grps;
   }
-
   @Override
-  public void setColorForGroup(BitSet bs, Color color)
+  public void setGroupSet(GroupSet makeGroups)
   {
-    colorMap.put(bs, color);
+    grps = makeGroups;
   }
-
   public static String contactToFloatString(ContactMatrixI cm)
   {
     StringBuilder sb = new StringBuilder();
@@ -257,7 +198,6 @@ public abstract class ContactMatrix implements ContactMatrixI
     float[][] vals = new float[cols][rows];
     StringTokenizer tabsep = new StringTokenizer(values, "" + '\t');
     int c = 0, r = 0;
-
     while (tabsep.hasMoreTokens())
     {
       double elem = Double.valueOf(tabsep.nextToken());
@@ -269,7 +209,6 @@ public abstract class ContactMatrix implements ContactMatrixI
       }
       if (c >= vals.length)
       {
-
         break;
       }
     }
@@ -278,7 +217,6 @@ public abstract class ContactMatrix implements ContactMatrixI
       Console.warn(
               "Ignoring additional elements for Float string to contact matrix parsing.");
     }
-
     return vals;
   }
 }
index 1d7391b..1d20987 100644 (file)
@@ -14,10 +14,6 @@ public interface ContactMatrixI
 
   float getMax();
 
-  boolean hasReferenceSeq();
-
-  SequenceI getReferenceSeq();
-
   String getAnnotDescr();
 
   String getAnnotLabel();
@@ -31,29 +27,45 @@ public interface ContactMatrixI
   String getType();
 
   int getWidth();
-
   int getHeight();
+  public GroupSetI getGroupSet();
+
+  /// proxy methods to simplify use of the interface
+  /// Mappable contact matrices can override these to perform mapping
+
+  default public boolean hasGroupSet()
+  {
+    return getGroupSet() != null;
+  }
 
   default boolean hasGroups()
   {
-    return false;
+    return hasGroupSet() && getGroupSet().hasGroups();
   }
 
   default BitSet getGroupsFor(int column)
   {
-    BitSet colbitset = new BitSet();
-    colbitset.set(column);
-    return colbitset;
+    if (!hasGroupSet())
+    {
+      BitSet colbitset = new BitSet();
+      colbitset.set(column);
+      return colbitset;
+    }
+    return getGroupSet().getGroupsFor(column);
   }
 
   default List<BitSet> getGroups()
   {
-    return Arrays.asList();
+    if (!hasGroupSet())
+    {
+      return Arrays.asList();
+    }
+    return getGroupSet().getGroups();
   }
 
   default boolean hasTree()
   {
-    return false;
+    return hasGroupSet() ? getGroupSet().hasTree() : false;
   }
 
   /**
@@ -63,30 +75,51 @@ public interface ContactMatrixI
    */
   default String getNewick()
   {
-    return null;
+    return hasGroupSet() ? getGroupSet().getNewick() : null;
   }
 
   default String getTreeMethod()
   {
-    return null;
+    return hasGroupSet() ? getGroupSet().getTreeMethod() : null;
   }
 
   default boolean hasCutHeight()
   {
-    return false;
+    return hasGroupSet() ? getGroupSet().hasCutHeight() : false;
   }
 
   default double getCutHeight()
   {
-    return 0;
+    return hasGroupSet() ? getGroupSet().getCutHeight() : 0;
   }
 
-  void updateGroups(List<BitSet> colGroups);
+  default void updateGroups(List<BitSet> colGroups)
+  {
+    if (hasGroupSet())
+    {
+      getGroupSet().updateGroups(colGroups);
+    }
+  }
 
-  void setColorForGroup(BitSet bs, Color color);
+  default void setColorForGroup(BitSet bs, Color color)
+  {
+    if (hasGroupSet())
+    {
+      getGroupSet().setColorForGroup(bs, color);
+    }
+  }
 
   default Color getColourForGroup(BitSet bs)
   {
-    return Color.white;
-  };
+    if (hasGroupSet())
+    {
+      return getGroupSet().getColourForGroup(bs);
+    }
+    else
+    {
+      return Color.white;
+    }
+  }
+
+  void setGroupSet(GroupSet makeGroups);
 }
diff --git a/src/jalview/datamodel/GroupSet.java b/src/jalview/datamodel/GroupSet.java
new file mode 100644 (file)
index 0000000..c7a73b7
--- /dev/null
@@ -0,0 +1,191 @@
+package jalview.datamodel;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.List;
+
+import jalview.analysis.AverageDistanceEngine;
+import jalview.bin.Console;
+
+public class GroupSet implements GroupSetI
+{
+  List<BitSet> groups = Arrays.asList();
+
+  public GroupSet(GroupSet grps)
+  {
+    abs = grps.abs;
+    colorMap = new HashMap<BitSet, Color>(grps.colorMap);
+    groups = new ArrayList<BitSet>(grps.groups);
+    newick = grps.newick;
+    thresh = grps.thresh;
+    treeType = grps.treeType;
+  }
+
+  public GroupSet()
+  {
+    // TODO Auto-generated constructor stub
+  }
+
+  public GroupSet(boolean abs2, float thresh2, List<BitSet> groups2,
+          String treeType2, String newick2)
+  {
+    abs = abs2;
+    thresh = thresh2;
+    groups = groups2;
+    treeType = treeType2;
+    newick = newick2;
+  }
+
+  @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 = false;
+
+  double thresh = 0;
+
+  String treeType = null;
+
+  @Override
+  public void updateGroups(List<BitSet> colGroups)
+  {
+    if (colGroups != null)
+    {
+      groups = colGroups;
+    }
+  }
+
+  @Override
+  public BitSet getGroupsFor(int column)
+  {
+    if (groups != null)
+    {
+      for (BitSet gp : groups)
+      {
+        if (gp.get(column))
+        {
+          return gp;
+        }
+      }
+    }
+    // return singleton set;
+    BitSet bs = new BitSet();
+    bs.set(column);
+    return bs;
+  }
+
+  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);
+  }
+
+  @Override
+  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;
+  }
+
+  public static GroupSet makeGroups(ContactMatrixI matrix, float thresh,
+          boolean abs)
+  {
+    AverageDistanceEngine clusterer = new AverageDistanceEngine(null, null,
+            matrix);
+    double height = clusterer.findHeight(clusterer.getTopNode());
+    String newick = new jalview.io.NewickFile(clusterer.getTopNode(), false,
+            true).print();
+    String 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());
+    }
+    List<BitSet> 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);
+    }
+    GroupSet grps = new GroupSet(abs, thresh, groups, treeType, newick);
+    return grps;
+  }
+
+  @Override
+  public List<BitSet> getGroups()
+  {
+    return groups;
+  }
+}
diff --git a/src/jalview/datamodel/GroupSetI.java b/src/jalview/datamodel/GroupSetI.java
new file mode 100644 (file)
index 0000000..7c086a5
--- /dev/null
@@ -0,0 +1,34 @@
+package jalview.datamodel;
+
+import java.awt.Color;
+import java.util.BitSet;
+import java.util.List;
+
+public interface GroupSetI
+{
+  boolean hasGroups();
+
+  String getNewick();
+
+  boolean hasTree();
+
+  void updateGroups(List<BitSet> colGroups);
+
+  BitSet getGroupsFor(int column);
+
+  Color getColourForGroup(BitSet bs);
+
+  void setColorForGroup(BitSet bs, Color color);
+
+  void restoreGroups(List<BitSet> newgroups, String treeMethod, String tree,
+          double thresh2);
+
+  boolean hasCutHeight();
+
+  double getCutHeight();
+
+  String getTreeMethod();
+
+  List<BitSet> getGroups();
+
+}
index a915bb0..f8fd750 100644 (file)
@@ -5,16 +5,19 @@ import java.util.BitSet;
 import java.util.HashMap;
 import java.util.List;
 
+import jalview.util.MapList;
+import jalview.ws.datamodel.alphafold.MappableContactMatrix;
 /**
  * Dummy contact matrix based on sequence distance
  * 
  * @author jprocter
  *
  */
-public class SeqDistanceContactMatrix implements ContactMatrixI
+public class SeqDistanceContactMatrix
+        extends MappableContactMatrix<SeqDistanceContactMatrix>
+        implements ContactMatrixI
 {
   private static final String SEQUENCE_DISTANCE = "SEQUENCE_DISTANCE";
-
   private int width = 0;
 
   public SeqDistanceContactMatrix(int width)
@@ -82,20 +85,6 @@ public class SeqDistanceContactMatrix implements ContactMatrixI
   }
 
   @Override
-  public boolean hasReferenceSeq()
-  {
-    // TODO Auto-generated method stub
-    return false;
-  }
-
-  @Override
-  public SequenceI getReferenceSeq()
-  {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
   public String getAnnotDescr()
   {
     return "Sequence distance matrix";
@@ -124,47 +113,16 @@ 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()
+  protected double getElementAt(int _column, int i)
   {
-    return groups != null;
+    return Math.abs(_column - i);
   }
-
-  @Override
-  public List<BitSet> getGroups()
-  {
-    return groups;
-  }
-
-  HashMap<BitSet, Color> colorMap = new HashMap<>();
-
   @Override
-  public Color getColourForGroup(BitSet bs)
+  protected SeqDistanceContactMatrix newMappableContactMatrix(
+          SequenceI newRefSeq, MapList newFromMapList)
   {
-    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);
+    return new SeqDistanceContactMatrix(width);
   }
 }
index 5ae7195..33c8ac5 100755 (executable)
@@ -39,6 +39,7 @@ import jalview.util.Comparison;
 import jalview.util.DBRefUtils;
 import jalview.util.MapList;
 import jalview.util.StringUtils;
+import jalview.ws.datamodel.alphafold.MappableContactMatrix;
 
 /**
  * 
@@ -2144,13 +2145,18 @@ public class Sequence extends ASequence implements SequenceI
     AlignmentAnnotation aa = cmholder.addContactList(cm);
 
     Annotation _aa[] = new Annotation[getLength()];
-    Annotation dummy = new Annotation(0.0f);
-    for (int i = 0; i < _aa.length; _aa[i++] = dummy)
+
+    for (int i = 0; i < _aa.length; _aa[i++] = new Annotation(0.0f))
     {
       ;
     }
     aa.annotations = _aa;
     aa.setSequenceRef(this);
+    if (cm instanceof MappableContactMatrix
+            && !((MappableContactMatrix) cm).hasReferenceSeq())
+    {
+      ((MappableContactMatrix) cm).setRefSeq(this);
+    }
     aa.createSequenceMapping(this, getStart(), false);
     addAlignmentAnnotation(aa);
     return aa;
index 010d4aa..9d00fa5 100755 (executable)
@@ -26,7 +26,7 @@ package jalview.datamodel;
  * @author $author$
  * @version $Revision$
  */
-public class SequenceNode extends BinaryNode
+public class SequenceNode extends BinaryNode<SequenceI>
 {
   private boolean placeholder = false;
 
@@ -38,20 +38,20 @@ public class SequenceNode extends BinaryNode
     super();
   }
 
-  public SequenceNode(SequenceI val, BinaryNode parent, String name,
-          double dist, int bootstrap, boolean dummy)
+  public SequenceNode(SequenceI val, BinaryNode<SequenceI> parent,
+          String name, double dist, int bootstrap, boolean dummy)
   {
     super(val, parent, name, dist, bootstrap, dummy);
   }
 
-  public SequenceNode(SequenceI element, BinaryNode parent, String name,
-          double dist, int bootstrap)
+  public SequenceNode(SequenceI element, BinaryNode<SequenceI> parent,
+          String name, double dist, int bootstrap)
   {
     super(element, parent, name, dist, bootstrap);
   }
 
-  public SequenceNode(SequenceI element, BinaryNode parent, String name,
-          double dist)
+  public SequenceNode(SequenceI element, BinaryNode<SequenceI> parent,
+          String name, double dist)
   {
     super(element, parent, name, dist);
   }
index b7c83c6..c64dac1 100644 (file)
@@ -92,7 +92,6 @@ public class JmolParser extends StructureFile implements JmolStatusListener
   {
     super(fp, doXferSettings);
   }
-
   public JmolParser(FileParse fp) throws IOException
   {
     super(fp);
@@ -315,16 +314,26 @@ public class JmolParser extends StructureFile implements JmolStatusListener
       // add a PAEMatrix if set (either by above or otherwise)
       if (hasPAEMatrix())
       {
-        Alignment al = new Alignment(prot.toArray(new SequenceI[0]));
-        EBIAlfaFold.addAlphaFoldPAE(al, new File(this.getPAEMatrix()), 0,
-                null, false, false, null);
-
-        if (al.getAlignmentAnnotation() != null)
+        try
         {
-          for (AlignmentAnnotation alann : al.getAlignmentAnnotation())
+          Alignment al = new Alignment(prot.toArray(new SequenceI[0]));
+          EBIAlfaFold.addAlphaFoldPAE(al, new File(this.getPAEMatrix()), 0,
+                  null, false, false, null);
+
+          if (al.getAlignmentAnnotation() != null)
           {
-            annotations.add(alann);
+            for (AlignmentAnnotation alann : al.getAlignmentAnnotation())
+            {
+              annotations.add(alann);
+            }
           }
+        } catch (Throwable ff)
+        {
+          Console.error("Couldn't import PAE Matrix from " + getPAEMatrix(),
+                  ff);
+          warningMessage += "Couldn't import PAE Matrix"
+                  + getNewlineString() + ff.getLocalizedMessage()
+                  + getNewlineString();
         }
       }
     } catch (OutOfMemoryError er)
index 7462bc8..0a9d35f 100755 (executable)
@@ -428,8 +428,7 @@ public class AnnotationLabels extends JPanel
       {
         final PAEContactMatrix cm = (PAEContactMatrix) av
                 .getContactMatrix(aa[selectedRow]);
-        if (cm != null && cm.getNewick() != null
-                && cm.getNewick().length() > 0)
+        if (cm != null && cm.hasTree())
         {
           item = new JMenuItem("Show Tree for Matrix");
           item.addActionListener(new ActionListener()
index f1a8af7..9970702 100755 (executable)
@@ -656,7 +656,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       fr = Math.min(cXci.cStart, cXci.cEnd);
       to = Math.max(cXci.cStart, cXci.cEnd);
 
-      if (evt.isControlDown())
+      // double click selects the whole group
+      if (evt.getClickCount() == 2)
       {
         ContactMatrixI matrix = av.getContactMatrix(clicked);
 
@@ -667,6 +668,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
           {
             SequenceI rseq = clicked.sequenceRef;
             BitSet grp = matrix.getGroupsFor(currentX);
+            // TODO: cXci needs to be mapped to real groups
             for (int c = fr; c <= to; c++)
             {
               BitSet additionalGrp = matrix.getGroupsFor(c);
@@ -697,16 +699,18 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       {
         // select corresponding range in segment under mouse
         {
-          for (int c = fr; c <= to; c++)
+          int[] rng = forCurrentX.getMappedPositionsFor(fr, to);
+          if (rng != null)
           {
-            av.getColumnSelection().addElement(c);
+            av.getColumnSelection().addRangeOfElements(rng, true);
           }
           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()))
+        if (evt.isControlDown()
+                && PAEContactMatrix.PAEMATRIX.equals(clicked.getCalcId()))
         {
           int c = fr - 1;
           ContactRange cr = forCurrentX.getRangeFor(fr, to);
@@ -724,12 +728,17 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
             if (// cr.getMin() <= cval &&
             cval <= thresh)
             {
-              av.getColumnSelection().addElement(c--);
-            }
-            else
-            {
-              break;
+              int[] cols = forCurrentX.getMappedPositionsFor(c, c);
+              if (cols != null)
+              {
+                av.getColumnSelection().addRangeOfElements(cols, true);
+              }
+              else
+              {
+                break;
+              }
             }
+            c--;
           }
           c = to;
           while (c < forCurrentX.getContactHeight())
@@ -738,12 +747,18 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
             if (// cr.getMin() <= cval &&
             cval <= thresh)
             {
-              av.getColumnSelection().addElement(c++);
+              int[] cols = forCurrentX.getMappedPositionsFor(c, c);
+              if (cols != null)
+              {
+                av.getColumnSelection().addRangeOfElements(cols, true);
+              }
             }
             else
             {
               break;
             }
+            c++;
+
           }
         }
       }
@@ -1052,32 +1067,51 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       int fr, to;
       fr = Math.min(lastXci.cStart, lastXci.cEnd);
       to = Math.max(lastXci.cStart, lastXci.cEnd);
-      jalview.bin.Console.trace("Marking " + fr + " to " + to);
-      for (int c = fr; c <= to; c++)
+      int[] mappedPos = forFromX.getMappedPositionsFor(fr, to);
+      if (mappedPos != null)
       {
-        if (cma.sequenceRef != null)
+        jalview.bin.Console.trace("Marking " + fr + " to " + to
+                + " mapping to sequence positions " + mappedPos[0] + " to "
+                + mappedPos[1]);
+        for (int pair = 0; pair < mappedPos.length; pair += 2)
         {
-          int col = cma.sequenceRef.findIndex(c);
-          av.getColumnSelection().addElement(col);
-        }
-        else
-        {
-          av.getColumnSelection().addElement(c);
+          for (int c = mappedPos[pair]; c <= mappedPos[pair + 1]; c++)
+          // {
+          // if (cma.sequenceRef != null)
+          // {
+          // int col = cma.sequenceRef.findIndex(cma.sequenceRef.getStart()+c);
+          // av.getColumnSelection().addElement(col);
+          // }
+          // else
+          {
+            av.getColumnSelection().addElement(c);
+          }
         }
       }
+      // and again for most recent corner of drag
       fr = Math.min(cXci.cStart, cXci.cEnd);
       to = Math.max(cXci.cStart, cXci.cEnd);
-      jalview.bin.Console.trace("Marking " + fr + " to " + to);
-      for (int c = fr; c <= to; c++)
+      mappedPos = forFromX.getMappedPositionsFor(fr, to);
+      if (mappedPos != null)
       {
-        if (cma.sequenceRef != null)
+        for (int pair = 0; pair < mappedPos.length; pair += 2)
         {
-          int col = cma.sequenceRef.findIndex(c);
-          av.getColumnSelection().addElement(col);
-        }
-        else
-        {
-          av.getColumnSelection().addElement(c);
+          jalview.bin.Console.trace("Marking " + fr + " to " + to
+                  + " mapping to sequence positions " + mappedPos[pair]
+                  + " to " + mappedPos[pair + 1]);
+          for (int c = mappedPos[pair]; c <= mappedPos[pair + 1]; c++)
+          {
+            // if (cma.sequenceRef != null)
+            // {
+            // int col =
+            // cma.sequenceRef.findIndex(cma.sequenceRef.getStart()+c);
+            // av.getColumnSelection().addElement(col);
+            // }
+            // else
+            {
+              av.getColumnSelection().addElement(c);
+            }
+          }
         }
       }
       fr = Math.min(lastX, currentX);
@@ -1250,12 +1284,28 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         ContactRange cr = clist.getRangeFor(ci.cStart, ci.cEnd);
         tooltip = "Contact from " + clist.getPosition() + ", [" + ci.cStart
                 + " - " + ci.cEnd + "]" + "<br/>Mean:" + cr.getMean();
+
         int col = ann.sequenceRef.findPosition(column);
+        int[][] highlightPos;
+        int[] mappedPos = clist.getMappedPositionsFor(ci.cStart, ci.cEnd);
+        if (mappedPos != null)
+        {
+          highlightPos = new int[1 + mappedPos.length][2];
+          highlightPos[0] = new int[] { col, col };
+          for (int p = 0, h = 0; p < mappedPos.length; h++, p += 2)
+          {
+            highlightPos[h][0] = ann.sequenceRef
+                    .findPosition(mappedPos[p] - 1);
+            highlightPos[h][1] = ann.sequenceRef
+                    .findPosition(mappedPos[p + 1] - 1);
+          }
+        }
+        else
+        {
+          highlightPos = new int[][] { new int[] { col, col } };
+        }
         ap.getStructureSelectionManager()
-                .highlightPositionsOn(ann.sequenceRef, new int[][]
-                { new int[] { col, col },
-                    new int[]
-                    { ci.cStart, ci.cEnd } }, null);
+                .highlightPositionsOn(ann.sequenceRef, highlightPos, null);
       }
     }
     return tooltip;
index 35972b0..6c68ee6 100644 (file)
@@ -72,6 +72,7 @@ import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
 import jalview.gui.structurechooser.StructureChooserQuerySource;
 import jalview.gui.structurechooser.ThreeDBStructureChooserQuerySource;
 import jalview.io.DataSourceType;
+import jalview.io.FileFormatException;
 import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
 import jalview.jbgui.FilterOption;
@@ -84,6 +85,8 @@ import jalview.util.Platform;
 import jalview.util.StringUtils;
 import jalview.ws.DBRefFetcher;
 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
+import jalview.ws.datamodel.alphafold.PAEContactMatrix;
+import jalview.ws.dbsources.EBIAlfaFold;
 import jalview.ws.seqfetcher.DbSourceProxy;
 import jalview.ws.sifts.SiftsSettings;
 
@@ -707,7 +710,7 @@ public class StructureChooser extends GStructureChooser
   }
 
   /**
-   * Handles action event for btn_pdbFromFile
+   * Handles action event for btn_paeMatrixFile
    */
   @Override
   protected void paeMatrixFile_actionPerformed()
@@ -736,10 +739,26 @@ public class StructureChooser extends GStructureChooser
             "label.load_pae_matrix_file_associate_with_structure",
             pdbFile.getName()));
 
+    // TODO convert to Callable/Promise
     int value = chooser.showOpenDialog(null);
     if (value == JalviewFileChooser.APPROVE_OPTION)
     {
-      localPdbPaeMatrixFileName = chooser.getSelectedFile().getPath();
+      String fileName = chooser.getSelectedFile().getPath();
+      try
+      {
+        PAEContactMatrix.validateContactMatrixFile(fileName);
+      } catch (Exception thr)
+      {
+        JvOptionPane.showInternalMessageDialog(this, MessageManager
+                .formatMessage("label.couldnt_load_file", new Object[]
+                { fileName }) + "<br>" + thr.getLocalizedMessage(),
+                MessageManager.getString("label.error_loading_file"),
+                JvOptionPane.WARNING_MESSAGE);
+        Console.error("Couldn't import " + fileName + " as a PAE matrix",
+                thr);
+        return;
+      }
+      localPdbPaeMatrixFileName = fileName;
       Cache.setProperty("LAST_DIRECTORY", localPdbPaeMatrixFileName);
     }
     validateAssociationFromFile();
@@ -1061,11 +1080,13 @@ public class StructureChooser extends GStructureChooser
       {
         pdbFileString = MessageManager.getString("label.none");
         pdbFileTooltip = MessageManager.getString("label.nothing_selected");
+        setPdbOptionsEnabled(false);
       }
     }
     else
     {
       btn_pdbFromFile.setEnabled(false);
+      setPdbOptionsEnabled(false);
       // lbl_fromFileStatus.setIcon(errorImage);
       pdbFileString = MessageManager.getString("label.none");
       pdbFileTooltip = MessageManager.getString("label.nothing_selected");
@@ -1190,7 +1211,14 @@ public class StructureChooser extends GStructureChooser
     final StructureSelectionManager ssm = ap.getStructureSelectionManager();
 
     final int preferredHeight = pnl_filter.getHeight();
+    btn_add.setEnabled(false);
+    btn_newView.setEnabled(false);
+    btn_cancel.setEnabled(false);
+    actionsPanel.setEnabled(false);
 
+    final String progress = MessageManager
+            .getString("label.working_ellipsis");
+    setProgressBar(progress, progress.hashCode());
     Runnable viewStruc = new Runnable()
     {
       @Override
@@ -1281,7 +1309,9 @@ public class StructureChooser extends GStructureChooser
                   .getCmb_assSeq().getSelectedItem();
           SequenceI userSelectedSeq = assSeqOpt.getSequence();
           if (userSelectedSeq != null)
+          {
             selectedSequence = userSelectedSeq;
+          }
           String pdbFilename = selectedPdbFileName;
 
           StructureChooser.openStructureFileForSequence(ssm, sc, ap,
@@ -1293,6 +1323,7 @@ public class StructureChooser extends GStructureChooser
           @Override
           public void run()
           {
+            setProgressBar("Complete.", progress.hashCode());
             closeAction(preferredHeight);
             mainFrame.dispose();
           }
index 3a055ae..f6b842d 100755 (executable)
@@ -54,6 +54,7 @@ import jalview.analysis.Conservation;
 import jalview.analysis.TreeModel;
 import jalview.api.AlignViewportI;
 import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Annotation;
 import jalview.datamodel.BinaryNode;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.ContactMatrixI;
@@ -67,6 +68,7 @@ import jalview.schemes.ColourSchemeI;
 import jalview.structure.SelectionSource;
 import jalview.util.Format;
 import jalview.util.MessageManager;
+import jalview.ws.datamodel.MappableContactMatrixI;
 
 /**
  * DOCUMENT ME!
@@ -1035,6 +1037,41 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
             cm.setColorForGroup(gp, colors.get(gp));
           }
         }
+        // stash colors in linked annotation row.
+        // doesn't work yet. TESTS!
+        int sstart = aa.sequenceRef != null ? aa.sequenceRef.getStart() - 1
+                : 0;
+        Annotation ae;
+        Color gpcol = null;
+        int[] seqpos = null;
+        for (BitSet gp : colors.keySet())
+        {
+          gpcol = colors.get(gp);
+          for (int p = gp.nextSetBit(0); p >= 0
+                  && p < Integer.MAX_VALUE; p = gp.nextSetBit(p + 1))
+          {
+            if (cm instanceof MappableContactMatrixI)
+            {
+              MappableContactMatrixI mcm = (MappableContactMatrixI) cm;
+              seqpos = mcm.getMappedPositionsFor(aa.sequenceRef, p);
+              if (seqpos == null)
+              {
+                // no mapping for this column.
+                continue;
+              }
+              // TODO: handle ranges...
+              ae = aa.getAnnotationForPosition(seqpos[0]);
+            }
+            else
+            {
+              ae = aa.getAnnotationForPosition(p + sstart);
+            }
+            if (ae != null)
+            {
+              ae.colour = gpcol.brighter().darker();
+            }
+          }
+        }
       }
     }
 
@@ -1071,7 +1108,6 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
       return false;
     }
     ColumnSelection cs = av.getColumnSelection();
-
     HiddenColumns hc = av.getAlignment().getHiddenColumns();
     int offp = (rseq != null) ? rseq.findIndex(rseq.getStart() + colm)
             : colm;
@@ -1087,7 +1123,6 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     }
     return false;
   }
-
   private BitSet createColumnGroupFor(Vector<BinaryNode> l, Color col)
   {
     BitSet gp = new BitSet();
@@ -1136,22 +1171,39 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
       {
         continue;
       }
+      // TODO - sort indices for faster lookup
       ColumnSelection cs = av.getColumnSelection();
       HiddenColumns hc = av.getAlignment().getHiddenColumns();
+      ContactMatrixI cm = av.getContactMatrix(tp.assocAnnotation);
+      MappableContactMatrixI mcm = null;
+      int offp;
+      if (cm instanceof MappableContactMatrixI)
+      {
+        mcm = (MappableContactMatrixI) cm;
+        int[] seqpos = mcm.getMappedPositionsFor(
+                tp.assocAnnotation.sequenceRef, colm);
+        if (seqpos == null)
+        {
+          // no mapping for this column.
+          continue;
+        }
+        // TODO: handle ranges...
+        offp = seqpos[0];
+      }
+      else
       {
-        int offp = (rseq != null) ? rseq.findIndex(rseq.getStart() + colm)
+        offp = (rseq != null) ? rseq.findIndex(rseq.getStart() + colm)
                 : colm;
-
-        if (!av.hasHiddenColumns() || hc.isVisible(offp - 1))
+      }
+      if (!av.hasHiddenColumns() || hc.isVisible(offp - 1))
+      {
+        if (cs.contains(offp - 1))
         {
-          if (cs.contains(offp - 1))
-          {
-            cs.removeElement(offp - 1);
-          }
-          else
-          {
-            cs.addElement(offp - 1);
-          }
+          cs.removeElement(offp - 1);
+        }
+        else
+        {
+          cs.addElement(offp - 1);
         }
       }
     }
index 1ac7bab..f6d17d4 100644 (file)
@@ -358,7 +358,7 @@ public class Tree extends DatastoreItem
         }
         if (jvseq instanceof SequenceI)
         {
-          leaf.setElement(jvseq);
+          leaf.setElement((SequenceI) jvseq);
           leaf.setPlaceholder(false);
         }
         else
index d317e97..8cb5b3c 100644 (file)
@@ -106,6 +106,8 @@ public abstract class GStructureChooser extends JPanel
    */
   protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
 
+  protected JPanel actionsPanel;
+
   protected JPanel statusPanel = new JPanel();
 
   public JLabel statusBar = new JLabel();
@@ -121,6 +123,8 @@ public abstract class GStructureChooser extends JPanel
 
   protected StringBuilder errorWarning = new StringBuilder();
 
+  protected JButton btn_cancel;
+
   protected JButton btn_add;
 
   protected JButton btn_newView;
@@ -414,8 +418,7 @@ public abstract class GStructureChooser extends JPanel
       }
     });
 
-    JButton btn_cancel = new JButton(
-            MessageManager.getString("action.cancel"));
+    btn_cancel = new JButton(MessageManager.getString("action.cancel"));
     btn_cancel.setFont(VERDANA_12);
     btn_cancel.addActionListener(new ActionListener()
     {
@@ -569,10 +572,8 @@ public abstract class GStructureChooser extends JPanel
     lbl_pdbFile.setFont(VERDANA_10);
 
     lbl_chooseTempFacType.setFont(VERDANA_12);
-    lbl_chooseTempFacType.setText(new StringBuilder()
-            .append(MessageManager.getString("label.choose_tempfac_type"))
-            .append(" ").append(MessageManager.getString("label.optional"))
-            .toString());
+    lbl_chooseTempFacType.setText(
+            MessageManager.getString("label.interpret_tempfac_as"));
 
     combo_tempFacAs.setFont(VERDANA_12);
     for (TFType t : TFType.values())
@@ -590,10 +591,8 @@ public abstract class GStructureChooser extends JPanel
     });
 
     btn_paeMatrixFile.setFont(VERDANA_12);
-    btn_paeMatrixFile.setText(new StringBuilder()
-            .append(MessageManager.getString("label.add_pae_matrix_file"))
-            .append(" ").append(MessageManager.getString("label.optional"))
-            .toString());
+    btn_paeMatrixFile
+            .setText(MessageManager.getString("label.add_pae_matrix_file"));
     btn_paeMatrixFile.addActionListener(new ActionListener()
     {
       @Override
@@ -685,7 +684,7 @@ public abstract class GStructureChooser extends JPanel
 
     targetView.setVisible(false);
 
-    JPanel actionsPanel = new JPanel(new MigLayout());
+    actionsPanel = new JPanel(new MigLayout());
     actionsPanel.add(targetView, "left");
     actionsPanel.add(btn_add, "wrap");
     actionsPanel.add(chk_superpose, "left");
@@ -727,15 +726,23 @@ public abstract class GStructureChooser extends JPanel
     gbc.insets = new Insets(0, 0, 18, 0);
     pnl_fileOptions.add(lbl_pdbFile, gbc);
     gbc.gridy++;
+
     gbc.insets = new Insets(0, 0, 2, 0);
+    pnl_fileOptions.add(new JLabel(
+            MessageManager.getString("label.structure_import_options")),
+            gbc);
+    gbc.gridy++;
+
+    gbc.insets = new Insets(0, 0, 6, 0);
     pnl_fileOptions.add(lbl_chooseTempFacType, gbc);
     gbc.gridy++;
     gbc.insets = new Insets(0, 0, 18, 0);
     pnl_fileOptions.add(combo_tempFacAs, gbc);
     gbc.gridy++;
-    gbc.insets = new Insets(0, 0, 2, 0);
+    gbc.insets = new Insets(0, 0, 6, 0);
     pnl_fileOptions.add(btn_paeMatrixFile, gbc);
     gbc.gridy++;
+    gbc.insets = new Insets(0, 0, 2, 0);
     gbc.weighty = 1.0;
     pnl_fileOptions.add(lbl_paeFile, gbc);
 
@@ -1070,5 +1077,6 @@ public abstract class GStructureChooser extends JPanel
     lbl_chooseTempFacType.setEnabled(b);
     combo_tempFacAs.setEnabled(b);
     btn_paeMatrixFile.setEnabled(b);
+    lbl_paeFile.setEnabled(b);
   }
 }
index 913dffe..6f26036 100644 (file)
@@ -96,6 +96,7 @@ import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.GeneLocus;
 import jalview.datamodel.GraphLine;
+import jalview.datamodel.GroupSet;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Point;
 import jalview.datamodel.RnaViewerModel;
@@ -152,6 +153,7 @@ import jalview.viewmodel.ViewportRanges;
 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
+import jalview.ws.datamodel.MappableContactMatrixI;
 import jalview.ws.datamodel.alphafold.PAEContactMatrix;
 import jalview.ws.jws2.Jws2Discoverer;
 import jalview.ws.jws2.dm.AAConSettings;
@@ -194,6 +196,7 @@ import jalview.xml.binding.jalview.JalviewModel.Viewport.HiddenColumns;
 import jalview.xml.binding.jalview.JalviewModel.Viewport.Overview;
 import jalview.xml.binding.jalview.JalviewUserColours;
 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
+import jalview.xml.binding.jalview.MapListType;
 import jalview.xml.binding.jalview.MapListType.MapListFrom;
 import jalview.xml.binding.jalview.MapListType.MapListTo;
 import jalview.xml.binding.jalview.Mapping;
@@ -2323,8 +2326,7 @@ public class Jalview2XML
               {
                 for (BitSet gp : cm.getGroups())
                 {
-                  BigInteger val = new BigInteger(gp.toByteArray());
-                  xmlmat.getGroups().add(val.toString());
+                  xmlmat.getGroups().add(stringifyBitset(gp));
                 }
               }
               if (cm.hasTree())
@@ -2337,8 +2339,39 @@ public class Jalview2XML
               {
                 xmlmat.setCutHeight(cm.getCutHeight());
               }
-
               // set/get properties
+              if (cm instanceof MappableContactMatrixI)
+              {
+                jalview.util.MapList mlst = ((MappableContactMatrixI) cm)
+                        .getMapFor(annotation.sequenceRef);
+                if (mlst != null)
+                {
+                  MapListType mp = new MapListType();
+                  List<int[]> r = mlst.getFromRanges();
+                  for (int[] range : r)
+                  {
+                    MapListFrom mfrom = new MapListFrom();
+                    mfrom.setStart(range[0]);
+                    mfrom.setEnd(range[1]);
+                    // mp.addMapListFrom(mfrom);
+                    mp.getMapListFrom().add(mfrom);
+                  }
+                  r = mlst.getToRanges();
+                  for (int[] range : r)
+                  {
+                    MapListTo mto = new MapListTo();
+                    mto.setStart(range[0]);
+                    mto.setEnd(range[1]);
+                    // mp.addMapListTo(mto);
+                    mp.getMapListTo().add(mto);
+                  }
+                  mp.setMapFromUnit(
+                          BigInteger.valueOf(mlst.getFromRatio()));
+                  mp.setMapToUnit(BigInteger.valueOf(mlst.getToRatio()));
+                  xmlmat.setMapping(mp);
+                }
+              }
+              // and add to model
               an.getContactmatrix().add(xmlmat);
             }
           }
@@ -2446,6 +2479,43 @@ public class Jalview2XML
 
   }
 
+  private String stringifyBitset(BitSet gp)
+  {
+    StringBuilder sb = new StringBuilder();
+    for (long val : gp.toLongArray())
+    {
+      if (sb.length() > 0)
+      {
+        sb.append(",");
+      }
+      sb.append(val);
+    }
+    return sb.toString();
+  }
+
+  private BitSet deStringifyBitset(String stringified)
+  {
+    if ("".equals(stringified) || stringified == null)
+    {
+      return new BitSet();
+    }
+    String[] longvals = stringified.split(",");
+    long[] newlongvals = new long[longvals.length];
+    for (int lv = 0; lv < longvals.length; lv++)
+    {
+      try
+      {
+        newlongvals[lv] = Long.valueOf(longvals[lv]);
+      } catch (Exception x)
+      {
+        errorMessage += "Couldn't destringify bitset from: '" + stringified
+                + "'";
+        newlongvals[lv] = 0;
+      }
+    }
+    return BitSet.valueOf(newlongvals);
+
+  }
   private CalcIdParam createCalcIdParam(String calcId, AlignViewport av)
   {
     AutoCalcSetting settings = av.getCalcIdSettingsFor(calcId);
@@ -3975,25 +4045,39 @@ public class Jalview2XML
                           .fromFloatStringToContacts(xmlmat.getElements(),
                                   xmlmat.getCols().intValue(),
                                   xmlmat.getRows().intValue());
+                  jalview.util.MapList mapping = null;
+                  if (xmlmat.getMapping() != null)
+                  {
+                    MapListType m = xmlmat.getMapping();
+                    // Mapping m = dr.getMapping();
+                    int fr[] = new int[m.getMapListFrom().size() * 2];
+                    Iterator<MapListFrom> from = m.getMapListFrom()
+                            .iterator();// enumerateMapListFrom();
+                    for (int _i = 0; from.hasNext(); _i += 2)
+                    {
+                      MapListFrom mf = from.next();
+                      fr[_i] = mf.getStart();
+                      fr[_i + 1] = mf.getEnd();
+                    }
+                    int fto[] = new int[m.getMapListTo().size() * 2];
+                    Iterator<MapListTo> to = m.getMapListTo().iterator();// enumerateMapListTo();
+                    for (int _i = 0; to.hasNext(); _i += 2)
+                    {
+                      MapListTo mf = to.next();
+                      fto[_i] = mf.getStart();
+                      fto[_i + 1] = mf.getEnd();
+                    }
 
-                  PAEContactMatrix newpae = new PAEContactMatrix(
-                          jaa.sequenceRef, elements);
+                    mapping = new jalview.util.MapList(fr, fto,
+                            m.getMapFromUnit().intValue(),
+                            m.getMapToUnit().intValue());
+                  }
                   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);
-                      }
+                      newgroups.add(deStringifyBitset(sgroup));
                     }
                   }
                   String nwk = xmlmat.getNewick().size() > 0
@@ -4004,12 +4088,14 @@ public class Jalview2XML
                     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);
+                  GroupSet grpset = new GroupSet();
+                  grpset.restoreGroups(newgroups, treeMethod, nwk, thresh);
+                  PAEContactMatrix newpae = new PAEContactMatrix(
+                          jaa.sequenceRef, mapping, elements, grpset);
                   jaa.sequenceRef.addContactListFor(jaa, newpae);
                 }
               }
index 4aef1d8..9fd4de6 100644 (file)
@@ -2,10 +2,23 @@ package jalview.renderer;
 
 import java.util.Iterator;
 
+import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.ContactListI;
-
+import jalview.datamodel.HiddenColumns;
+import jalview.renderer.ContactGeometry.contactInterval;
+
+/**
+ * encapsulate logic for mapping between positions in a ContactList and their
+ * rendered representation in a given number of pixels.
+ * 
+ * @author jprocter
+ *
+ */
 public class ContactGeometry
 {
+
+  final ContactListI contacts;
+
   final int pixels_step;
 
   final double contacts_per_pixel;
@@ -14,8 +27,9 @@ public class ContactGeometry
 
   final int graphHeight;
 
-  public ContactGeometry(ContactListI contacts, int graphHeight)
+  public ContactGeometry(final ContactListI contacts, int graphHeight)
   {
+    this.contacts = contacts;
     this.graphHeight = graphHeight;
     contact_height = contacts.getContactHeight();
     // fractional number of contacts covering each pixel
@@ -54,6 +68,56 @@ public class ContactGeometry
     public final int pStart;
 
     public final int pEnd;
+
+  }
+
+  /**
+   * 
+   * @param columnSelection
+   * @param ci
+   * @param visibleOnly
+   *          - when true, only test intersection of visible columns given
+   *          matrix range
+   * @return true if the range on the matrix specified by ci intersects with
+   *         selected columns in the ContactListI's reference frame.
+   */
+
+  boolean intersects(contactInterval ci, ColumnSelection columnSelection,
+          HiddenColumns hiddenColumns, boolean visibleOnly)
+  {
+    boolean rowsel = false;
+    final int[] mappedRange = contacts.getMappedPositionsFor(ci.cStart,
+            ci.cEnd);
+    if (mappedRange == null)
+    {
+      return false;
+    }
+    for (int p = 0; p < mappedRange.length && !rowsel; p += 2)
+    {
+      boolean containsHidden = false;
+      if (visibleOnly && hiddenColumns != null
+              && hiddenColumns.hasHiddenColumns())
+      {
+        // TODO: turn into function on hiddenColumns and create test !!
+        Iterator<int[]> viscont = hiddenColumns.getVisContigsIterator(
+                mappedRange[p], mappedRange[p + 1], false);
+        containsHidden = !viscont.hasNext();
+        if (!containsHidden)
+        {
+          for (int[] interval = viscont.next(); viscont
+                  .hasNext(); rowsel |= columnSelection
+                          .intersects(interval[p], interval[p + 1]))
+            ;
+        }
+      }
+      else
+      {
+        rowsel = columnSelection.intersects(mappedRange[p],
+                mappedRange[p + 1]);
+      }
+    }
+    return rowsel;
+
   }
 
   /**
index cbc4af9..a8f6c1b 100644 (file)
@@ -35,12 +35,10 @@ public abstract class ContactMapRenderer implements AnnotationRowRendererI
      * shown when no data available from map
      */
     Color no_data;
-
     /**
      * shown for region not currently visible - should normally not see this
      */
     Color hidden;
-
     /**
      * linear shading scheme min/max
      */
@@ -150,14 +148,20 @@ public abstract class ContactMapRenderer implements AnnotationRowRendererI
         x++;
         continue;
       }
+      // ContactListI from viewport can map column -> group
       Color gpcol = (cm == null) ? Color.white
-              : cm.getColourForGroup(cm.getGroupsFor(column));
+              : contacts.getColourForGroup(); // 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;
-      // TODO: pass visible column mask to the ContactGeometry object so it maps
+      // TODO: optionally pass visible column mask to the ContactGeometry object
+      // so it maps
       // only visible contacts to geometry
       // Bean holding mapping from contact list to pixels
+      // TODO: allow bracketing/limiting of range on contacts to render (like
+      // visible column mask but more flexible?)
+
+      // COntactListI provides mapping for column -> cm-groupmapping
       final ContactGeometry cgeom = new ContactGeometry(contacts,
               _aa.graphHeight);
 
@@ -174,29 +178,8 @@ public abstract class ContactMapRenderer implements AnnotationRowRendererI
         boolean rowsel = false, containsHidden = false;
         if (columnSelection != null)
         {
-          if (_aa.sequenceRef == null)
-          {
-            rowsel = columnSelection.intersects(ci.cStart, ci.cEnd);
-          }
-          else
-          {
-            // TODO check we have correctly mapped cstart to local sequence
-            // numbering
-            int s = _aa.sequenceRef.findIndex(ci.cStart);
-            int e = _aa.sequenceRef.findIndex(ci.cEnd);
-            if (maskHiddenCols && hasHiddenColumns)
-            {
-              // TODO: turn into function and create test !!
-              Iterator<int[]> viscont = hiddenColumns
-                      .getVisContigsIterator(s, e, false);
-              containsHidden = !viscont.hasNext();
-            }
-            if (s > 0 && s < _aa.sequenceRef.getLength())
-            {
-              rowsel = columnSelection.intersects(s, e);
-            }
-
-          }
+          rowsel = cgeom.intersects(ci, columnSelection, hiddenColumns,
+                  maskHiddenCols);
         }
         // TODO: show selected region
         if (colsel || rowsel)
@@ -231,7 +214,6 @@ public abstract class ContactMapRenderer implements AnnotationRowRendererI
                   (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 8436b48..7d9674e 100644 (file)
@@ -973,7 +973,10 @@ public abstract class AAStructureBindingModel
       }
       List<StructureCommandI> finalView = commandGenerator
               .centerViewOn(models);
-      executeCommands(finalView, false, "Centered on Superposition");
+      if (finalView != null && finalView.size() > 0)
+      {
+        executeCommands(finalView, false, "Centered on Superposition");
+      }
     }
     return error;
   }
diff --git a/src/jalview/ws/datamodel/MappableContactMatrixI.java b/src/jalview/ws/datamodel/MappableContactMatrixI.java
new file mode 100644 (file)
index 0000000..b8a9779
--- /dev/null
@@ -0,0 +1,64 @@
+package jalview.ws.datamodel;
+
+import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactMatrixI;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.SequenceI;
+import jalview.util.MapList;
+
+public interface MappableContactMatrixI extends ContactMatrixI
+{
+
+  boolean hasReferenceSeq();
+
+  SequenceI getReferenceSeq();
+
+  /**
+   * remaps the matrix to a new reference sequence
+   * 
+   * @param dsq
+   * @param sqmpping
+   *          - mapping from current reference to new reference - 1:1 only
+   * @return new ContactMatrixI instance with updated mapping
+   */
+  MappableContactMatrixI liftOver(SequenceI dsq, Mapping sqmpping);
+
+  /**
+   * like ContactMatrixI.getContactList(int column) but
+   * 
+   * @param localFrame
+   *          - sequence or other object that this contact matrix is associated
+   *          with
+   * @param column
+   *          - position in localFrame
+   * @return ContactListI that returns contacts w.r.t. localFrame
+   */
+
+  ContactListI getMappableContactList(SequenceI localFrame, int column);
+
+  /**
+   * 
+   * Similar to AlignedCodonFrame.getMappingBetween
+   * 
+   * @param sequenceRef
+   *          - a reference sequence mappable to this contactMatrix - may be
+   *          null
+   * @return null or the MapList mapping to the coordinates of the reference
+   *         sequence (or if hasReferenceSeq() is false, and sequenceRef is
+   *         null, any mapping present)
+   * 
+   */
+  MapList getMapFor(SequenceI sequenceRef);
+
+  /**
+   * Locate a position in the mapped sequence for a column in the matrix - use
+   * this to resolve positions corresponding to column clusters
+   * 
+   * @param localFrame
+   *          - sequence derivced from reference sequence
+   * @param column
+   *          - matrix row/column
+   * @return sequence position(s) corresponding to column in contact matrix
+   */
+  int[] getMappedPositionsFor(SequenceI localFrame, int column);
+}
diff --git a/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java b/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java
new file mode 100644 (file)
index 0000000..9a01738
--- /dev/null
@@ -0,0 +1,444 @@
+package jalview.ws.datamodel.alphafold;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.BitSet;
+
+import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactListImpl;
+import jalview.datamodel.ContactListProviderI;
+import jalview.datamodel.GroupSet;
+import jalview.datamodel.GroupSetI;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.SequenceI;
+import jalview.util.MapList;
+import jalview.ws.datamodel.MappableContactMatrixI;
+
+public abstract class MappableContactMatrix<T extends MappableContactMatrix<T>>
+        implements MappableContactMatrixI
+{
+  SequenceI refSeq = null;
+
+  MapList toSeq = null;
+
+  /**
+   * the length that refSeq is expected to be (excluding gaps, of course)
+   */
+  int length;
+
+  @Override
+  public boolean hasReferenceSeq()
+  {
+    return (refSeq != null);
+  }
+
+  @Override
+  public SequenceI getReferenceSeq()
+  {
+    return refSeq;
+  }
+
+  /**
+   * container for groups - defined on matrix columns
+   */
+  GroupSet grps = new GroupSet();
+
+  @Override
+  public GroupSetI getGroupSet()
+  {
+    return grps;
+  };
+
+  @Override
+  public void setGroupSet(GroupSet makeGroups)
+  {
+    grps = makeGroups;
+  }
+
+  @Override
+  public MapList getMapFor(SequenceI mapSeq)
+  {
+    if (refSeq != null)
+    {
+      while (mapSeq != refSeq && mapSeq.getDatasetSequence() != null)
+      {
+        mapSeq = mapSeq.getDatasetSequence();
+      }
+      if (mapSeq != refSeq)
+      {
+        return null;
+      }
+    }
+    else
+    {
+      if (mapSeq != null)
+      {
+        // our MapList does not concern this seq
+        return null;
+      }
+    }
+
+    return toSeq;
+  }
+
+  /**
+   * set the reference sequence and construct the mapping between the start-end
+   * positions of given sequence and row/columns of contact matrix
+   * 
+   * @param _refSeq
+   */
+  public void setRefSeq(SequenceI _refSeq)
+  {
+    refSeq = _refSeq;
+    while (refSeq.getDatasetSequence() != null)
+    {
+      refSeq = refSeq.getDatasetSequence();
+    }
+    length = _refSeq.getEnd() - _refSeq.getStart() + 1;
+    // if (length!=refSeq.getLength() || _refSeq.getStart()!=1)
+    {
+      toSeq = new MapList(
+              new int[]
+              { _refSeq.getStart(), _refSeq.getEnd() },
+              new int[]
+              { 0, length - 1 }, 1, 1);
+    }
+  }
+
+  public T liftOver(SequenceI newRefSeq, Mapping sp2sq)
+  {
+    if (sp2sq.getMappedWidth() != sp2sq.getWidth())
+    {
+      // TODO: employ getWord/MappedWord to transfer annotation between cDNA and
+      // Protein reference frames
+      throw new Error(
+              "liftOver currently not implemented for transfer of annotation between different types of seqeunce");
+    }
+    boolean mapIsTo = (sp2sq != null) ? (sp2sq.getTo() == refSeq) : false;
+
+    /**
+     * map from matrix to toSeq's coordinate frame
+     */
+    int[] refMap = toSeq.locateInFrom(0, length - 1);
+    ArrayList<Integer> newFromMap = new ArrayList<Integer>();
+    int last = -1;
+    for (int i = 0; i < refMap.length; i += 2)
+    {
+      /*
+       * for each contiguous range in toSeq, locate corresponding range in sequence mapped to toSeq by sp2sq
+       */
+      int[] sp2map = mapIsTo
+              ? sp2sq.getMap().locateInFrom(refMap[i], refMap[i + 1])
+              : sp2sq.getMap().locateInTo(refMap[i], refMap[i + 1]);
+      if (sp2map == null)
+      {
+        continue;
+      }
+
+      for (int spm = 0; spm < sp2map.length; spm += 2)
+      {
+
+        if (last > -1)
+        {
+          if (sp2map[spm] != last + 1)
+          {
+            newFromMap.add(sp2map[spm]);
+          }
+          else
+          {
+            newFromMap.remove(newFromMap.size() - 1);
+          }
+        }
+        else
+        {
+          newFromMap.add(sp2map[spm]);
+        }
+        last = sp2map[spm + 1];
+        newFromMap.add(last);
+      }
+    }
+    if ((newFromMap.size() % 2) != 0)
+    {
+      // should have had an even number of int ranges!
+      throw new Error("PAEMatrix liftover failed.");
+    }
+    int fromIntMap[] = new int[newFromMap.size()];
+    int ipos = 0;
+    for (Integer i : newFromMap)
+    {
+      fromIntMap[ipos++] = i;
+    }
+    MapList newFromMapList = new MapList(fromIntMap,
+            new int[]
+            { 0, length - 1 }, 1, 1);
+
+    T newCM = newMappableContactMatrix(newRefSeq, newFromMapList);
+    return newCM;
+  }
+
+  protected abstract T newMappableContactMatrix(SequenceI newRefSeq,
+          MapList newFromMapList);
+
+  @Override
+  public int[] getMappedPositionsFor(final SequenceI localFrame,
+          final int column)
+  {
+    return getMappedPositionsFor(localFrame, column, column);
+  }
+
+  public int[] getMappedPositionsFor(final SequenceI localFrame, int from,
+          int to)
+  {
+    if (localFrame == null)
+    {
+      throw new Error("Unimplemented when no local sequence given.");
+    }
+    // return a ContactListI for column
+    // column is index into localFrame
+    // 1. map column to corresponding column in matrix
+
+    final int _lcolumn = localFrame.findPosition(from);
+    final int _rcolumn = (from == to) ? _lcolumn
+            : localFrame.findPosition(to);
+    if (toSeq == null)
+    {
+      // no mapping
+      return new int[] { _lcolumn, _rcolumn };
+    }
+
+    SequenceI lf = localFrame, uf = refSeq;
+
+    // just look for dataset sequences and check they are the same.
+    // in future we could use DBRefMappings/whatever.
+    while (lf.getDatasetSequence() != null
+            || uf.getDatasetSequence() != null)
+    {
+      if (lf.getDatasetSequence() != null)
+      {
+        lf = lf.getDatasetSequence();
+      }
+      if (uf.getDatasetSequence() != null)
+      {
+        uf = uf.getDatasetSequence();
+      }
+    }
+    if (lf != uf)
+    {
+      // could try harder to find a mapping
+      throw new Error("This Matrix associated with '" + refSeq.getName()
+              + "' is not mappable for the given localFrame sequence. ("
+              + localFrame.getName() + ")");
+    }
+
+    int[] mappedPositions = toSeq.locateInFrom(_lcolumn, _rcolumn);
+    // TODO - trim to localFrame ?
+    // if (mappedPositions!=null) {
+    // int s=-1,e=-1;
+    // for (int p=0;p<mappedPositions.length;p++)
+    // {
+    // if (s==-1 && mappedPositions[p]>=localFrame.getStart())
+    // {
+    // s=p; // remember first position within local frame
+    // }
+    // if (e==-1 || mappedPositions[p]<=localFrame.getEnd())
+    // {
+    // // update end pointer
+    // e=p;
+    // // compute local map
+    // mappedPositions[p] = localFrame.findIndex(mappedPositions[p]);
+    // }
+    // }
+    // }
+    return mappedPositions;
+  }
+
+  @Override
+  public ContactListI getMappableContactList(final SequenceI localFrame,
+          final int column)
+  {
+    final int _column;
+    final int _lcolumn;
+    if (localFrame == null)
+    {
+      throw new Error("Unimplemented when no local sequence given.");
+    }
+    // return a ContactListI for column
+    // column is index into localFrame
+    // 1. map column to corresponding column in matrix
+    final MappableContactMatrix us = this;
+    _lcolumn = localFrame.findPosition(column);
+
+    if (toSeq != null)
+    {
+      SequenceI lf = localFrame, uf = refSeq;
+
+      // just look for dataset sequences and check they are the same.
+      // in future we could use DBRefMappings/whatever.
+      while (lf.getDatasetSequence() != null
+              || uf.getDatasetSequence() != null)
+      {
+        if (lf.getDatasetSequence() != null)
+        {
+          lf = lf.getDatasetSequence();
+        }
+        if (uf.getDatasetSequence() != null)
+        {
+          uf = uf.getDatasetSequence();
+        }
+      }
+      if (lf != uf)
+      {
+        // could try harder to find a mapping
+        throw new Error("This Matrix associated with '" + refSeq.getName()
+                + "' is not mappable for the given localFrame sequence. ("
+                + localFrame.getName() + ")");
+      }
+      // check the mapping to see if localFrame _lcolumn exists
+      int[] word = toSeq.locateInTo(_lcolumn, _lcolumn);
+      if (word == null)
+      {
+        return null;
+      }
+      _column = word[0];
+    }
+    else
+    {
+      // no mapping
+      _column = _lcolumn;
+    }
+
+    // TODO - remove ? this may be a redundant check
+    if (_column < 0 || ((toSeq != null && _column > toSeq.getToHighest())
+            || (toSeq == null && getHeight() <= _column)))
+    {
+      return null;
+    }
+
+    // 2. resolve ranges in matrix corresponding to range in localFrame
+    final int[] matrixRange = toSeq == null
+            ? new int[]
+            { localFrame.getStart(), localFrame.getEnd() }
+            : toSeq.locateInTo(localFrame.getStart(), localFrame.getEnd());
+
+    int h = 0;
+    for (int p = 0; p < matrixRange.length; p += 2)
+    {
+      h += 1 + Math.abs(matrixRange[p + 1] - matrixRange[p]);
+    }
+    final int rangeHeight = h;
+    // 3. Construct ContactListImpl instance for just those segments.
+
+    return new ContactListImpl(new ContactListProviderI()
+    {
+
+      public int getColumn()
+      {
+        return column;
+      }
+
+      @Override
+      public int getPosition()
+      {
+        return _column;
+      }
+
+      @Override
+      public int getContactHeight()
+      {
+        return rangeHeight;
+      }
+
+      @Override
+      public double getContactAt(int mcolumn)
+      {
+        if (mcolumn < 0 || mcolumn >= rangeHeight)
+        {
+          return -1;
+        }
+        return getElementAt(_column, locateInRange(mcolumn));
+
+        // this code maps from mcolumn to localFrame - but that isn't what's
+        // needed
+        // int loccolumn = localFrame.findPosition(mcolumn);
+        // int[] lcolumn=(toSeq==null) ? new int[] {mcolumn} :
+        // toSeq.locateInTo(loccolumn,loccolumn);
+        // if (lcolumn==null || lcolumn[0] < 0 || lcolumn[0] >= rangeHeight)
+        // {
+        // return -1;
+        // }
+        // return getElementAt(_column,lcolumn[0]);
+      }
+
+      @Override
+      public int[] getMappedPositionsFor(int cStart, int cEnd)
+      {
+        if (!hasReferenceSeq())
+        {
+          return ContactListProviderI.super.getMappedPositionsFor(cStart,
+                  cEnd);
+        }
+        // map into segment of matrix being shown
+        int realCstart = locateInRange(cStart);
+        int realCend = locateInRange(cEnd);
+
+        // TODO account for discontinuities in the mapping
+
+        int[] mappedPositions = toSeq.locateInFrom(realCstart, realCend);
+        if (mappedPositions != null)
+        {
+          int s = -1, e = -1;
+          for (int p = 0; p < mappedPositions.length; p++)
+          {
+            if (s == -1 && mappedPositions[p] >= localFrame.getStart())
+            {
+              s = p; // remember first position within local frame
+            }
+            if (e == -1 || mappedPositions[p] <= localFrame.getEnd())
+            {
+              // update end pointer
+              e = p;
+              // compute local map
+              mappedPositions[p] = localFrame.findIndex(mappedPositions[p]);
+            }
+          }
+        }
+        return mappedPositions;
+      }
+
+      /**
+       * @return the mcolumn'th position in the matrixRange window on the matrix
+       */
+      private int locateInRange(int mcolumn)
+      {
+
+        int h = 0, p = 0;
+        while (h < mcolumn && p + 2 < matrixRange.length)
+        {
+          h += 1 + Math.abs(matrixRange[p + 1] - matrixRange[p]);
+          p += 2;
+        }
+        return matrixRange[p] + mcolumn - h;
+      }
+
+      @Override
+      public Color getColourForGroup()
+      {
+        BitSet gp = us.getGroupsFor(_column);
+        Color col = us.getColourForGroup(gp);
+        return col;
+      }
+    });
+  }
+
+  /**
+   * get a specific element of the contact matrix in its data-local coordinates
+   * rather than the mapped frame. Implementations are allowed to throw
+   * RunTimeExceptions if _column/i are out of bounds
+   * 
+   * @param _column
+   * @param i
+   * @return
+   */
+  protected abstract double getElementAt(int _column, int i);
+
+}
index 1ec856b..ce072e0 100644 (file)
@@ -1,53 +1,56 @@
 package jalview.ws.datamodel.alphafold;
 
 import java.awt.Color;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
 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 java.util.Map.Entry;
+
+import org.json.simple.JSONObject;
 
 import jalview.analysis.AverageDistanceEngine;
 import jalview.bin.Console;
+import jalview.datamodel.Annotation;
 import jalview.datamodel.BinaryNode;
 import jalview.datamodel.ContactListI;
 import jalview.datamodel.ContactListImpl;
 import jalview.datamodel.ContactListProviderI;
 import jalview.datamodel.ContactMatrixI;
+import jalview.datamodel.GroupSet;
+import jalview.datamodel.GroupSetI;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.SequenceDummy;
 import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
+import jalview.io.FileFormatException;
+import jalview.io.FileParse;
+import jalview.util.MapList;
 import jalview.util.MapUtils;
+import jalview.ws.dbsources.EBIAlfaFold;
 
-public class PAEContactMatrix implements ContactMatrixI
+public class PAEContactMatrix extends
+        MappableContactMatrix<PAEContactMatrix> implements ContactMatrixI
 {
 
-  SequenceI refSeq = null;
-
-  /**
-   * the length that refSeq is expected to be (excluding gaps, of course)
-   */
-  int length;
 
   int maxrow = 0, maxcol = 0;
 
-  int[] indices1, indices2;
 
   float[][] elements;
 
   float maxscore;
 
-  private void setRefSeq(SequenceI _refSeq)
-  {
-    refSeq = _refSeq;
-    while (refSeq.getDatasetSequence() != null)
-    {
-      refSeq = refSeq.getDatasetSequence();
-    }
-    length = _refSeq.getEnd() - _refSeq.getStart() + 1;
-  }
 
   @SuppressWarnings("unchecked")
   public PAEContactMatrix(SequenceI _refSeq, Map<String, Object> pae_obj)
+          throws FileFormatException
   {
     setRefSeq(_refSeq);
     // convert the lists to primitive arrays and store
@@ -94,6 +97,22 @@ public class PAEContactMatrix implements ContactMatrixI
   }
 
   /**
+   * new matrix with specific mapping to a reference sequence
+   * 
+   * @param newRefSeq
+   * @param newFromMapList
+   * @param elements2
+   * @param grps2
+   */
+  public PAEContactMatrix(SequenceI newRefSeq, MapList newFromMapList,
+          float[][] elements2, GroupSet grps2)
+  {
+    this(newRefSeq, elements2);
+    toSeq = newFromMapList;
+    grps = grps2;
+  }
+
+  /**
    * parse a sane JSON representation of the pAE
    * 
    * @param pae_obj
@@ -101,9 +120,17 @@ public class PAEContactMatrix implements ContactMatrixI
   @SuppressWarnings("unchecked")
   private void parse_version_2_pAE(Map<String, Object> pae_obj)
   {
-    // this is never going to be reached by the integer rounding.. or is it ?
-    maxscore = ((Double) MapUtils.getFirst(pae_obj,
-            "max_predicted_aligned_error", "max_pae")).floatValue();
+    maxscore = -1;
+    // look for a maxscore element - if there is one...
+    try
+    {
+      // this is never going to be reached by the integer rounding.. or is it ?
+      maxscore = ((Double) MapUtils.getFirst(pae_obj,
+              "max_predicted_aligned_error", "max_pae")).floatValue();
+    } catch (Throwable t)
+    {
+      // ignore if a key is not found.
+    }
     List<List<Long>> scoreRows = ((List<List<Long>>) MapUtils
             .getFirst(pae_obj, "predicted_aligned_error", "pae"));
     elements = new float[scoreRows.size()][scoreRows.size()];
@@ -115,9 +142,18 @@ public class PAEContactMatrix implements ContactMatrixI
       {
         Object d = scores.next();
         if (d instanceof Double)
+        {
           elements[row][col++] = ((Double) d).longValue();
+        }
         else
+        {
           elements[row][col++] = (float) ((Long) d).longValue();
+        }
+
+        if (maxscore < elements[row][col - 1])
+        {
+          maxscore = elements[row][col - 1];
+        }
       }
       row++;
       col = 0;
@@ -139,10 +175,26 @@ public class PAEContactMatrix implements ContactMatrixI
     // dataset refSeq
     Iterator<Long> rows = ((List<Long>) pae_obj.get("residue1")).iterator();
     Iterator<Long> cols = ((List<Long>) pae_obj.get("residue2")).iterator();
+    // two pass - to allocate the elements array
+    while (rows.hasNext())
+    {
+      int row = rows.next().intValue();
+      int col = cols.next().intValue();
+      if (maxrow < row)
+      {
+        maxrow = row;
+      }
+      if (maxcol < col)
+      {
+        maxcol = col;
+      }
+
+    }
+    rows = ((List<Long>) pae_obj.get("residue1")).iterator();
+    cols = ((List<Long>) pae_obj.get("residue2")).iterator();
     Iterator<Double> scores = ((List<Double>) pae_obj.get("distance"))
             .iterator();
-    // assume square matrix
-    elements = new float[length][length];
+    elements = new float[maxrow][maxcol];
     while (scores.hasNext())
     {
       float escore = scores.next().floatValue();
@@ -164,9 +216,9 @@ public class PAEContactMatrix implements ContactMatrixI
   }
 
   @Override
-  public ContactListI getContactList(final int _column)
+  public ContactListI getContactList(final int column)
   {
-    if (_column < 0 || _column >= elements.length)
+    if (column < 0 || column >= elements.length)
     {
       return null;
     }
@@ -176,7 +228,7 @@ public class PAEContactMatrix implements ContactMatrixI
       @Override
       public int getPosition()
       {
-        return _column;
+        return column;
       }
 
       @Override
@@ -186,39 +238,33 @@ public class PAEContactMatrix implements ContactMatrixI
       }
 
       @Override
-      public double getContactAt(int column)
+      public double getContactAt(int mcolumn)
       {
-        if (column < 0 || column >= elements[_column].length)
+        if (mcolumn < 0 || mcolumn >= elements[column].length)
         {
           return -1;
         }
-        return elements[_column][column];
+        return elements[column][mcolumn];
       }
     });
   }
 
   @Override
-  public float getMin()
+  protected double getElementAt(int _column, int i)
   {
-    return 0;
+    return elements[_column][i];
   }
 
   @Override
-  public float getMax()
-  {
-    return maxscore;
-  }
-
-  @Override
-  public boolean hasReferenceSeq()
+  public float getMin()
   {
-    return (refSeq != null);
+    return 0;
   }
 
   @Override
-  public SequenceI getReferenceSeq()
+  public float getMax()
   {
-    return refSeq;
+    return maxscore;
   }
 
   @Override
@@ -258,142 +304,41 @@ 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)
+  public static void validateContactMatrixFile(String fileName)
+          throws FileFormatException, IOException
   {
-    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)
+    FileInputStream infile = null;
+    try
     {
-      float cut = abs ? (float) (thresh / height) : thresh;
-      Console.debug("Threshold " + cut + " for height=" + height);
-
-      nodegroups = clusterer.groupNodes(cut);
-    }
-    else
+      infile = new FileInputStream(new File(fileName));
+    } catch (Throwable t)
     {
-      nodegroups = new ArrayList<BinaryNode>();
-      nodegroups.add(clusterer.getTopNode());
+      new IOException("Couldn't open " + fileName, t);
     }
-    this.abs = abs;
-    this.thresh = thresh;
-    groups = new ArrayList<>();
-    for (BinaryNode root : nodegroups)
+    JSONObject paeDict = null;
+    try
     {
-      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)
+      paeDict = EBIAlfaFold.parseJSONtoPAEContactMatrix(infile);
+    } catch (Throwable t)
     {
-      groups = colGroups;
+      new FileFormatException("Couldn't parse " + fileName
+              + " as a JSON dict or array containing a dict");
     }
-  }
 
-  @Override
-  public BitSet getGroupsFor(int column)
-  {
-    for (BitSet gp : groups)
+    PAEContactMatrix matrix = new PAEContactMatrix(
+            new SequenceDummy("Predicted"), (Map<String, Object>) paeDict);
+    if (matrix.getWidth() <= 0)
     {
-      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;
+      throw new FileFormatException(
+              "No data in PAE matrix read from '" + fileName + "'");
     }
-    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()
+  protected PAEContactMatrix newMappableContactMatrix(SequenceI newRefSeq,
+          MapList newFromMapList)
   {
-    return treeType;
+    PAEContactMatrix pae = new PAEContactMatrix(newRefSeq, newFromMapList,
+            elements, new GroupSet(grps));
+    return pae;
   }
 }
index a734f52..fd10c79 100644 (file)
@@ -44,6 +44,7 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.GroupSet;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
@@ -447,7 +448,7 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
     }
     ContactMatrixI matrix = new PAEContactMatrix(sequence,
             (Map<String, Object>) paeDict);
-    ((PAEContactMatrix) matrix).makeGroups(5f, true);
+    matrix.setGroupSet(GroupSet.makeGroups(matrix, 5f, true));
 
     AlignmentAnnotation cmannot = sequence.addContactList(matrix);
     if (label != null)
@@ -505,8 +506,8 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
     SequenceI seq = sm.getSequence();
     ContactMatrixI matrix = new PAEContactMatrix(seq,
             (Map<String, Object>) pae_obj);
-    ((PAEContactMatrix) matrix).makeGroups(5f, true);
-    AlignmentAnnotation cmannot = seq.addContactList(matrix);
+    matrix.setGroupSet(GroupSet.makeGroups(matrix, 5f, true));
+    AlignmentAnnotation cmannot = sm.getSequence().addContactList(matrix);
     /* this already happens in Sequence.addContactList()
      seq.addAlignmentAnnotation(cmannot);
      */
index 43689d3..0ec8f0b 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.03.17 at 05:31:45 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.embl;
index bc3e556..d90651c 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.03.17 at 05:31:45 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.embl;
index 2fef24a..0bb5c59 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.03.17 at 05:31:45 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.embl;
index f35812e..b3fad01 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.03.17 at 05:31:45 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.embl;
index d70f92c..03bbba4 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.03.17 at 05:31:45 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.embl;
index 5dcc0bd..6b98b6a 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 985736e..2feda64 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index c7bc579..c820076 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index e461296..087667a 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index b1a738b..b42a170 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 12f39c0..3b449fe 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 9ac7b58..afedb4c 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 1b1abff..fa80569 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index a071af8..45077af 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index d71051e..76fc6cd 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index b77d98d..94f9373 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 8a9f681..e4b160f 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 6d7f5f2..1f16680 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 0d5acfb..69bf01d 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 23aa9ac..c405597 100644 (file)
@@ -2,9 +2,10 @@
 // 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 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
+
 package jalview.xml.binding.jalview;
 
 import java.math.BigInteger;
@@ -16,6 +17,7 @@ import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlType;
 
+
 /**
  * <p>
  * Java class for MatrixType complex type.
@@ -33,6 +35,7 @@ import javax.xml.bind.annotation.XmlType;
  *         &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;element name="mapping" type="{www.vamsas.ac.uk/jalview/version2}mapListType" 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" />
@@ -51,7 +54,7 @@ import javax.xml.bind.annotation.XmlType;
 @XmlType(
   name = "MatrixType",
   propOrder =
-  { "elements", "groups", "newick", "property" })
+  { "elements", "groups", "newick", "property", "mapping" })
 public class MatrixType
 {
 
@@ -64,6 +67,8 @@ public class MatrixType
 
   protected List<Property> property;
 
+  protected MapListType mapping;
+
   @XmlAttribute(name = "type", required = true)
   protected String type;
 
@@ -199,6 +204,29 @@ public class MatrixType
   }
 
   /**
+   * Gets the value of the mapping property.
+   * 
+   * @return possible object is {@link MapListType }
+   * 
+   */
+  public MapListType getMapping()
+  {
+    return mapping;
+  }
+
+  /**
+   * Sets the value of the mapping property.
+   * 
+   * @param value
+   *          allowed object is {@link MapListType }
+   * 
+   */
+  public void setMapping(MapListType value)
+  {
+    this.mapping = value;
+  }
+
+  /**
    * Gets the value of the type property.
    * 
    * @return possible object is {@link String }
index 77074d1..eeeed22 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 448b35f..993adae 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 8719689..2ff7a55 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index c0bedff..f0fd2f3 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index ed57889..b70e665 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 15893d8..a5923e1 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 6676f7b..f08b225 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 3de52d2..44e606d 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 6c9cbce..ad0ea1e 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 10635e5..099af84 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index 88f5a22..4374c83 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 package jalview.xml.binding.jalview;
index e5bd209..65d49d5 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.03.17 at 05:31:44 PM GMT 
+// Generated on: 2023.05.13 at 06:58:41 PM BST 
 //
 
 @javax.xml.bind.annotation.XmlSchema(
index 2622784..c5980b3 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 28e7220..d7f0cdb 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index f26c12b..0477736 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 5230b13..719344b 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 076a37c..184f424 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 3cc0c73..72de883 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 49ab079..ec9fdcd 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 1e6f734..d40163d 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 0de4239..4b4c3a2 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index e4bdc31..791aa0e 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 7ab7959..f3d2973 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index bd21a83..b8cec80 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index cbd47bf..3b2300b 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index e003273..f22b4c8 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 0ab941a..8902f68 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 20fbbb5..c3f1d0a 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index a4e2b7c..0c10761 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index ae3f321..1aa1925 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 67e43d1..3b6d294 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 17918fb..89496ec 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index bf570f3..07967eb 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index f2964dc..de03ff2 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 033e498..b053df8 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 66a5161..0887b7b 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 9e805f0..e8cea36 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 8eebd3d..3383f53 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index a701b99..e651a3b 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 5b914d0..f3d61ee 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index d35b45f..13fe5aa 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 2260842..9fbb9da 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 2f7daa3..d1562a1 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 42d8c58..f9b4daa 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 5fa8cd6..4c92560 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 4500112..2e92ca6 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 551c67a..220c009 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index c9dbdf8..f8adfde 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index a2f8c6b..283ba1f 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 package jalview.xml.binding.uniprot;
index 0b60eaa..eb7f47a 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.03.17 at 05:31:46 PM GMT 
+// Generated on: 2023.05.13 at 06:58:42 PM BST 
 //
 
 @javax.xml.bind.annotation.XmlSchema(
index 5b209d0..2970ccf 100755 (executable)
@@ -39,6 +39,7 @@ import jalview.schemes.ResidueProperties;
 import jalview.structure.StructureImportSettings;
 import jalview.structure.StructureMapping;
 import jalview.util.Comparison;
+import jalview.ws.datamodel.MappableContactMatrixI;
 
 public class PDBChain
 {
@@ -700,9 +701,10 @@ public class PDBChain
               ana = new AlignmentAnnotation(ana);
               ana.liftOver(dsq, sqmpping);
               dsq.addAlignmentAnnotation(ana);
-              if (cm != null)
+              if (cm != null && cm instanceof MappableContactMatrixI)
               {
-                dsq.addContactListFor(ana, cm);
+                dsq.addContactListFor(ana, ((MappableContactMatrixI) cm)
+                        .liftOver(dsq, sqmpping));
               }
             }
             else
index c526fa1..f017662 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.analysis;
 
+import static org.testng.Assert.assertNotEquals;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertNotNull;
@@ -54,6 +55,7 @@ import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SeqDistanceContactMatrix;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.gui.JvOptionPane;
 import jalview.io.AppletFormatAdapter;
@@ -62,6 +64,7 @@ import jalview.io.FileFormat;
 import jalview.io.FileFormatI;
 import jalview.io.FormatAdapter;
 import jalview.io.gff.SequenceOntologyI;
+import jalview.util.Comparison;
 import jalview.util.MapList;
 import jalview.util.MappingUtils;
 
@@ -2603,6 +2606,98 @@ public class AlignmentUtilsTests
   }
 
   @Test(groups = "Functional")
+  public void testAddReferenceAnnotations()
+  {
+    SequenceI longseq = new Sequence("longA", "ASDASDASDASDAASDASDASDASDA");
+    Annotation[] aa = new Annotation[longseq.getLength()];
+
+    for (int p = 0; p < aa.length; p++)
+    {
+      aa[p] = new Annotation("P", "pos " + (p + 1), (char) 0,
+              (float) p + 1);
+    }
+    AlignmentAnnotation refAnnot = new AlignmentAnnotation("LongSeqAnnot",
+            "Annotations", aa);
+    refAnnot.setCalcId("Test");
+    longseq.addAlignmentAnnotation(refAnnot);
+    verifyExpectedSequenceAnnotation(refAnnot);
+
+    Alignment ourAl = new Alignment(
+            new SequenceI[]
+            { longseq.getSubSequence(5, 10),
+                longseq.getSubSequence(7, 12) });
+    ourAl.createDatasetAlignment();
+
+    // transfer annotation
+    SortedMap<String, String> tipEntries = new TreeMap<>();
+    Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
+
+    AlignmentUtils.findAddableReferenceAnnotations(ourAl.getSequences(),
+            tipEntries, candidates, ourAl);
+    AlignmentUtils.addReferenceAnnotations(candidates, ourAl, null);
+
+    assertNotNull(ourAl.getAlignmentAnnotation());
+    assertEquals(ourAl.getAlignmentAnnotation().length, 2);
+
+    for (AlignmentAnnotation alan : ourAl.getAlignmentAnnotation())
+    {
+      verifyExpectedSequenceAnnotation(alan);
+    }
+    // Everything above works for 2.11.3 and 2.11.2.x.
+    // now simulate copy/paste to new alignment
+    SequenceI[] newSeqAl = new SequenceI[2];
+    // copy sequences but no annotation
+    newSeqAl[0] = new Sequence(ourAl.getSequenceAt(0),
+            ourAl.getSequenceAt(0).getAnnotation());
+    newSeqAl[1] = new Sequence(ourAl.getSequenceAt(1),
+            ourAl.getSequenceAt(1).getAnnotation());
+
+    Alignment newAl = new Alignment(newSeqAl);
+    // delete annotation
+    for (SequenceI sq : newAl.getSequences())
+    {
+      sq.setAlignmentAnnotation(new AlignmentAnnotation[0]);
+    }
+    // JAL-4182 scenario test
+    SequenceGroup sg = new SequenceGroup(Arrays.asList(newSeqAl));
+    sg.setStartRes(0);
+    sg.setEndRes(newAl.getWidth());
+    AlignmentUtils.addReferenceAnnotationTo(newAl, newSeqAl[0],
+            newSeqAl[0].getDatasetSequence().getAnnotation()[0], sg);
+    AlignmentUtils.addReferenceAnnotationTo(newAl, newSeqAl[1],
+            newSeqAl[1].getDatasetSequence().getAnnotation()[0], sg);
+    for (AlignmentAnnotation alan : newAl.getAlignmentAnnotation())
+    {
+      verifyExpectedSequenceAnnotation(alan);
+    }
+  }
+
+  /**
+   * helper - tests annotation is mapped to position it was originally created
+   * for
+   * 
+   * @param alan
+   */
+  private void verifyExpectedSequenceAnnotation(AlignmentAnnotation alan)
+  {
+    for (int c = 0; c < alan.annotations.length; c++)
+    {
+      Annotation a = alan.annotations[c];
+      if (a != null)
+      {
+        assertEquals("Misaligned annotation at " + c,
+                (float) alan.sequenceRef.findPosition(c), a.value);
+      }
+      else
+      {
+        assertTrue("Unexpected Null at position " + c,
+                c >= alan.sequenceRef.getLength()
+                        || Comparison.isGap(alan.sequenceRef.getCharAt(c)));
+      }
+    }
+  }
+
+  @Test(groups = "Functional")
   public void testAddReferenceContactMap()
   {
     SequenceI sq = new Sequence("a", "SSSQ");
@@ -2626,6 +2721,12 @@ public class AlignmentUtilsTests
                     && al.getAlignmentAnnotation().length == 1);
     AlignmentAnnotation alan = al.findAnnotations(sq, null, cm_aan.label)
             .iterator().next();
+    ContactMatrixI t_cm = al.getContactMatrixFor(alan);
+    assertNotNull("No contact map for the transferred annotation row.",
+            t_cm);
+    assertTrue(t_cm instanceof SeqDistanceContactMatrix);
+    assertTrue(((SeqDistanceContactMatrix) t_cm).hasReferenceSeq());
+
     ContactListI cl = al.getContactListFor(alan, 1);
     assertNotNull(
             "No contact matrix recovered after reference annotation transfer",
index f7688b5..5a8361d 100644 (file)
@@ -45,7 +45,7 @@ public class AverageDistanceEngineTest
     Cache.loadProperties("test/jalview/bin/TestProps.jvprops");
   }
 
-  @Test
+  @Test(groups = { "Functional" })
   public void testUPGMAEngine() throws Exception
   {
     AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded(
@@ -103,7 +103,6 @@ public class AverageDistanceEngineTest
       }
       System.out.println("\\");
     }
-
   }
 
 }
diff --git a/test/jalview/datamodel/PAEContactMatrixTest.java b/test/jalview/datamodel/PAEContactMatrixTest.java
new file mode 100644 (file)
index 0000000..8cc2ec4
--- /dev/null
@@ -0,0 +1,209 @@
+package jalview.datamodel;
+
+import static org.testng.Assert.*;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import jalview.analysis.AlignmentUtils;
+import jalview.analysis.SeqsetUtils;
+import jalview.gui.JvOptionPane;
+import jalview.util.MapList;
+import jalview.ws.datamodel.MappableContactMatrixI;
+import jalview.ws.datamodel.alphafold.PAEContactMatrix;
+
+public class PAEContactMatrixTest
+{
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+  }
+
+  static float[][] PAEdata = { { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f },
+      { 2.0f, 1.0f, 2.0f, 3.0f, 4.0f },
+      { 3.0f, 2.0f, 1.0f, 2.0f, 3.0f },
+      { 4.0f, 3.0f, 2.0f, 1.0f, 2.0f },
+      { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f } };
+
+  /**
+   * test associations for a PAE matrix
+   */
+  @Test(groups = { "Functional" })
+  public void testSeqAssociatedPAEMatrix()
+  {
+    Sequence seq = new Sequence("Seq", "ASDQE");
+    AlignmentAnnotation aa = seq
+            .addContactList(new PAEContactMatrix(seq, PAEdata));
+    assertNotNull(seq.getContactListFor(aa, 0));
+    assertEquals(seq.getContactListFor(aa, 0).getContactAt(0), 1.0);
+    assertNotNull(seq.getContactListFor(aa, 1));
+    assertEquals(seq.getContactListFor(aa, 1).getContactAt(1), 1.0);
+    assertNotNull(seq.getContactListFor(aa, 2));
+    assertEquals(seq.getContactListFor(aa, 2).getContactAt(2), 1.0);
+    assertNotNull(seq.getContactListFor(aa, 3));
+    assertEquals(seq.getContactListFor(aa, 3).getContactAt(3), 1.0);
+    assertNotNull(seq.getContactListFor(aa, 4));
+    assertEquals(seq.getContactListFor(aa, 4).getContactAt(4), 1.0);
+
+    assertNotNull(seq.getContactListFor(aa, seq.getEnd() - 1));
+    assertNull(seq.getContactListFor(aa, seq.getEnd()));
+
+    ContactListI cm = seq.getContactListFor(aa, seq.getStart());
+    assertEquals(cm.getContactAt(seq.getStart()), 1d);
+    verifyPAEmatrix(seq, aa, 0, 0, 4);
+
+    // Now associated with sequence not starting at 1
+    seq = new Sequence("Seq/5-9", "ASDQE");
+    ContactMatrixI paematrix = new PAEContactMatrix(seq, PAEdata);
+    aa = seq.addContactList(paematrix);
+    assertNotNull(aa);
+    // individual annotation elements need to be distinct for Matrix associated
+    // rows
+    Annotation ae5 = aa.getAnnotationForPosition(5);
+    Annotation ae6 = aa.getAnnotationForPosition(6);
+    assertNotNull(ae5);
+    assertNotNull(ae6);
+    assertTrue(ae5 != ae6);
+
+    cm = seq.getContactListFor(aa, 0);
+    assertEquals(cm.getContactAt(0), 1d);
+    verifyPAEmatrix(seq, aa, 0, 0, 4);
+
+    // test clustering
+    paematrix.setGroupSet(GroupSet.makeGroups(paematrix, 0.1f, false));
+
+    // remap - test the MappableContactMatrix.liftOver method
+    SequenceI newseq = new Sequence("Seq", "ASDQEASDQEASDQE");
+    Mapping sqmap = new Mapping(seq,
+            new MapList(new int[]
+            { 5, 8, 10, 10 }, new int[] { 5, 9 }, 1, 1));
+    assertTrue(paematrix instanceof MappableContactMatrixI);
+
+    MappableContactMatrixI remapped = ((MappableContactMatrixI) paematrix)
+            .liftOver(newseq, sqmap);
+    assertTrue(remapped instanceof PAEContactMatrix);
+
+    AlignmentAnnotation newaa = newseq.addContactList(remapped);
+    assertNull(newseq.getContactListFor(newaa, -1 + newseq.findIndex(1)));
+    assertNull(newseq.getContactListFor(newaa, -1 + newseq.findIndex(4)));
+    assertNotNull(
+            newseq.getContactListFor(newaa, -1 + newseq.findIndex(5)));
+    assertNotNull(
+            newseq.getContactListFor(newaa, -1 + newseq.findIndex(6)));
+    assertNotNull(
+            newseq.getContactListFor(newaa, -1 + newseq.findIndex(7)));
+    assertNotNull(
+            newseq.getContactListFor(newaa, -1 + newseq.findIndex(8)));
+    // no mapping for position 9
+    assertNull(newseq.getContactListFor(newaa, -1 + newseq.findIndex(9)));
+    // last column
+    assertNotNull(
+            newseq.getContactListFor(newaa, -1 + newseq.findIndex(10)));
+
+    // verify MappedPositions includes discontinuity
+    int[] mappedCl = newseq.getContactListFor(newaa, 5)
+            .getMappedPositionsFor(0, 4);
+    assertEquals(4, mappedCl.length,
+            "getMappedPositionsFor doesn't support discontinuous mappings to contactList");
+
+    // make it harder.
+
+    SequenceI alseq = newseq.getSubSequence(6, 10);
+    alseq.insertCharAt(2, 2, '-');
+    AlignmentI alForSeq = new Alignment(new SequenceI[] { alseq });
+    newaa = AlignmentUtils.addReferenceAnnotationTo(alForSeq, alseq, newaa,
+            null);
+    ContactListI alcl = alForSeq.getContactListFor(newaa, 1);
+    assertNotNull(alcl);
+    mappedCl = alcl.getMappedPositionsFor(0, 4);
+    assertNotNull(mappedCl);
+    assertEquals(4, mappedCl.length,
+            "getMappedPositionsFor doesn't support discontinuous mappings to contactList");
+
+    // remap2 - test with original matrix map from 1-5 remapped to 5-9
+
+    seq = new Sequence("Seq/1-5", "ASDQE");
+    paematrix = new PAEContactMatrix(seq, PAEdata);
+    assertTrue(paematrix instanceof MappableContactMatrixI);
+    aa = seq.addContactList(paematrix);
+
+    newseq = new Sequence("Seq", "ASDQEASDQEASDQE");
+    sqmap = new Mapping(seq,
+            new MapList(new int[]
+            { 5, 9 }, new int[] { 1, 5 }, 1, 1));
+
+    remapped = ((MappableContactMatrixI) paematrix).liftOver(newseq, sqmap);
+    assertTrue(remapped instanceof PAEContactMatrix);
+
+    newaa = newseq.addContactList(remapped);
+    verify_mapping(newseq, newaa);
+
+    // remap3 - remap2 but mapping sense in liftover is reversed
+
+    seq = new Sequence("Seq/1-5", "ASDQE");
+    paematrix = new PAEContactMatrix(seq, PAEdata);
+    assertTrue(paematrix instanceof MappableContactMatrixI);
+    aa = seq.addContactList(paematrix);
+
+    newseq = new Sequence("Seq", "ASDQEASDQEASDQE");
+    sqmap = new Mapping(newseq,
+            new MapList(new int[]
+            { 1, 5 }, new int[] { 5, 9 }, 1, 1));
+
+    remapped = ((MappableContactMatrixI) paematrix).liftOver(newseq, sqmap);
+    assertTrue(remapped instanceof PAEContactMatrix);
+
+    newaa = newseq.addContactList(remapped);
+    verify_mapping(newseq, newaa);
+  }
+
+  /**
+   * checks that the PAE matrix is located at positions 1-9 in newseq, and
+   * columns are not truncated.
+   * 
+   * @param newseq
+   * @param newaa
+   */
+  private void verify_mapping(SequenceI newseq, AlignmentAnnotation newaa)
+  {
+    assertNull(newseq.getContactListFor(newaa, -1 + newseq.findIndex(1)));
+    assertNull(newseq.getContactListFor(newaa, -1 + newseq.findIndex(4)));
+    assertNotNull(
+            newseq.getContactListFor(newaa, -1 + newseq.findIndex(5)));
+    assertNotNull(
+            newseq.getContactListFor(newaa, -1 + newseq.findIndex(6)));
+    assertNotNull(
+            newseq.getContactListFor(newaa, -1 + newseq.findIndex(7)));
+    assertNotNull(
+            newseq.getContactListFor(newaa, -1 + newseq.findIndex(8)));
+    assertNotNull(
+            newseq.getContactListFor(newaa, -1 + newseq.findIndex(9)));
+    // last column should be null this time
+    assertNull(newseq.getContactListFor(newaa, -1 + newseq.findIndex(10)));
+
+    verifyPAEmatrix(newseq, newaa, 4, 4, 8);
+  }
+
+  private void verifyPAEmatrix(SequenceI seq, AlignmentAnnotation aa,
+          int topl, int rowl, int rowr)
+  {
+    int[] mappedCl;
+    for (int f = rowl; f <= rowr; f++)
+    {
+      ContactListI clist = seq.getContactListFor(aa, f);
+      assertNotNull(clist, "No ContactListI for position " + (f));
+      assertEquals(clist.getContactAt(0), (double) f - topl + 1,
+              "for column " + f + " relative to " + topl);
+      mappedCl = clist.getMappedPositionsFor(0, 0);
+      assertNotNull(mappedCl);
+      assertEquals(mappedCl[0], mappedCl[1]);
+      assertEquals(mappedCl[0], seq.findIndex(seq.getStart() + topl));
+      assertEquals(clist.getContactAt(f - topl), 1d,
+              "for column and row " + f + " relative to " + topl);
+    }
+  }
+
+}
index d74cd31..37f946b 100644 (file)
@@ -32,7 +32,9 @@ import java.awt.Color;
 import java.awt.Rectangle;
 import java.io.File;
 import java.io.IOException;
+import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.BitSet;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
@@ -59,6 +61,7 @@ import jalview.datamodel.ContactMatrix;
 import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.GeneLocus;
+import jalview.datamodel.GroupSet;
 import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.Mapping;
 import jalview.datamodel.PDBEntry;
@@ -100,6 +103,7 @@ import jalview.util.MapList;
 import jalview.util.matcher.Condition;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
+import jalview.ws.datamodel.MappableContactMatrixI;
 import jalview.ws.datamodel.alphafold.PAEContactMatrix;
 
 @Test(singleThreaded = true)
@@ -1569,10 +1573,37 @@ 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);
+    dummyMat.setGroupSet(GroupSet.makeGroups(dummyMat, 0.5f, false));
     Assert.assertNotSame(dummyMat.getNewick(), "");
     AlignmentAnnotation paeCm = sq.addContactList(dummyMat);
     al.addAnnotation(paeCm);
+    // verify store/restore of group bitsets
+    for (BitSet gp : dummyMat.getGroups())
+    {
+      StringBuilder sb = new StringBuilder();
+      for (long val : gp.toLongArray())
+      {
+        if (sb.length() > 0)
+        {
+          sb.append(",");
+        }
+        sb.append(val);
+      }
+      String[] longvals = sb.toString().split(",");
+      long[] newlongvals = new long[longvals.length];
+      for (int lv = 0; lv < longvals.length; lv++)
+      {
+        try
+        {
+          newlongvals[lv] = Long.valueOf(longvals[lv]);
+        } catch (Exception x)
+        {
+          Assert.fail("failed to deserialise bitset element ");
+        }
+      }
+      BitSet newGp = BitSet.valueOf(newlongvals);
+      assertTrue(gp.equals(newGp));
+    }
     File tfile = File.createTempFile("testStoreAndRecoverPAEmatrix",
             ".jvp");
     new Jalview2XML(false).saveState(tfile);
@@ -1592,20 +1623,28 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     ContactMatrixI restoredMat = newSeq
             .getContactMatrixFor(newSeq.getAnnotation()[0]);
     Assert.assertNotNull(restoredMat);
+    MapList oldMap = ((MappableContactMatrixI) dummyMat).getMapFor(sq);
+    MapList newMap = ((MappableContactMatrixI) restoredMat)
+            .getMapFor(newSeq);
+    Assert.assertEquals(oldMap.getFromRanges(), newMap.getFromRanges());
+    Assert.assertEquals(oldMap.getToRanges(), newMap.getToRanges());
+    Assert.assertEquals(oldMap.getFromRatio(), newMap.getFromRatio());
+    Assert.assertEquals(oldMap.getToRatio(), newMap.getToRatio());
     for (i = sq.getLength() - 1; i >= 0; i--)
     {
       ContactListI oldCM = dummyMat.getContactList(i),
               newCM = restoredMat.getContactList(i);
       for (int j = oldCM.getContactHeight(); j >= 0; j--)
       {
-        Assert.assertEquals(oldCM.getContactAt(j), newCM.getContactAt(j));
+        double old_j = oldCM.getContactAt(j);
+        double new_j = newCM.getContactAt(j);
+        Assert.assertEquals(old_j, new_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());
-
   }
 
 }