JAL-2349 JAL-3855 Integrate pAE retrieval in StructureFile so it can be transferred...
authorJim Procter <j.procter@dundee.ac.uk>
Mon, 17 Oct 2022 11:18:22 +0000 (12:18 +0100)
committerJim Procter <j.procter@dundee.ac.uk>
Mon, 17 Oct 2022 11:18:22 +0000 (12:18 +0100)
12 files changed:
src/jalview/analysis/AlignmentUtils.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/ContactMapHolder.java
src/jalview/datamodel/ContactMapHolderI.java
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceGroup.java
src/jalview/datamodel/SequenceI.java
src/jalview/ext/jmol/JmolParser.java
src/jalview/ws/dbsources/EBIAlfaFold.java
src/mc_view/PDBChain.java
test/jalview/analysis/AlignmentUtilsTests.java
test/jalview/ws/seqfetcher/DbRefFetcherTest.java

index fdc74e2..a1a7fef 100644 (file)
@@ -20,8 +20,6 @@
  */
 package jalview.analysis;
 
-import java.util.Locale;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -31,6 +29,7 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.NoSuchElementException;
@@ -46,6 +45,7 @@ import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.GeneLociI;
 import jalview.datamodel.IncompleteCodonException;
@@ -1471,7 +1471,8 @@ public class AlignmentUtils
          */
         final Iterable<AlignmentAnnotation> matchedAlignmentAnnotations = al
                 .findAnnotations(seq, dsann.getCalcId(), dsann.label);
-        if (!matchedAlignmentAnnotations.iterator().hasNext())
+        if (matchedAlignmentAnnotations == null
+                || !matchedAlignmentAnnotations.iterator().hasNext())
         {
           result.add(dsann);
           if (labelForCalcId != null)
@@ -1517,7 +1518,7 @@ public class AlignmentUtils
           startRes = selectionGroup.getStartRes();
           endRes = selectionGroup.getEndRes();
         }
-        copyAnn.restrict(startRes, endRes);
+        copyAnn.restrict(startRes, endRes + 0);
 
         /*
          * Add to the sequence (sets copyAnn.datasetSequence), unless the
@@ -1525,6 +1526,12 @@ public class AlignmentUtils
          */
         if (!seq.hasAnnotation(ann))
         {
+          ContactMatrixI cm = seq.getDatasetSequence()
+                  .getContactMatrixFor(ann);
+          if (cm != null)
+          {
+            seq.addContactListFor(copyAnn, cm);
+          }
           seq.addAlignmentAnnotation(copyAnn);
         }
         // adjust for gaps
@@ -1534,6 +1541,7 @@ public class AlignmentUtils
         copyAnn.visible = true;
       }
     }
+
   }
 
   /**
index e1c87a9..3ae6831 100755 (executable)
@@ -1653,8 +1653,10 @@ public class Alignment implements AlignmentI, AutoCloseable
   public Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq,
           String calcId, String label)
   {
-    return AlignmentAnnotation.findAnnotations(
-            Arrays.asList(getAlignmentAnnotation()), seq, calcId, label);
+    return annotations == null ? null
+            : AlignmentAnnotation.findAnnotations(
+                    Arrays.asList(getAlignmentAnnotation()), seq, calcId,
+                    label);
   }
 
   @Override
@@ -2045,9 +2047,28 @@ public class Alignment implements AlignmentI, AutoCloseable
   }
 
   @Override
+  public ContactMatrixI getContactMatrixFor(AlignmentAnnotation ann)
+  {
+    return cmholder.getContactMatrixFor(ann);
+  }
+
+  @Override
   public ContactListI getContactListFor(AlignmentAnnotation _aa, int column)
   {
-    return cmholder.getContactListFor(_aa, column);
+    ContactListI cl = cmholder.getContactListFor(_aa, column);
+    if (cl == null && _aa.groupRef != null)
+    {
+      cl = _aa.groupRef.getContactListFor(_aa, column);
+    }
+    if (cl == null && _aa.sequenceRef != null)
+    {
+      cl = _aa.sequenceRef.getContactListFor(_aa, column);
+      if (cl == null && _aa.sequenceRef.getDatasetSequence() != null)
+      {
+        _aa.sequenceRef.getDatasetSequence().getContactListFor(_aa, column);
+      }
+    }
+    return cl;
   }
 
   @Override
@@ -2065,4 +2086,12 @@ public class Alignment implements AlignmentI, AutoCloseable
     addAnnotation(aa);
     return aa;
   }
+
+  @Override
+  public void addContactListFor(AlignmentAnnotation annotation,
+          ContactMatrixI cm)
+  {
+    cmholder.addContactListFor(annotation, cm);
+
+  }
 }
index 5ef2b2a..ac1b267 100644 (file)
@@ -50,4 +50,17 @@ public class ContactMapHolder implements ContactMapHolderI
     }
     return aa;
   }
+
+  @Override
+  public ContactMatrixI getContactMatrixFor(AlignmentAnnotation ann)
+  {
+    return contactmaps == null ? null : contactmaps.get(ann.annotationId);
+  }
+
+  @Override
+  public void addContactListFor(AlignmentAnnotation annotation,
+          ContactMatrixI cm)
+  {
+    contactmaps.put(annotation.annotationId, cm);
+  }
 }
index 624a03e..ba23e67 100644 (file)
@@ -18,4 +18,8 @@ public interface ContactMapHolderI
 
   Collection<ContactMatrixI> getContactMaps();
 
+  public ContactMatrixI getContactMatrixFor(AlignmentAnnotation ann);
+
+  void addContactListFor(AlignmentAnnotation annotation, ContactMatrixI cm);
+
 }
index d62be17..5ae7195 100755 (executable)
@@ -1625,6 +1625,13 @@ public class Sequence extends ASequence implements SequenceI
           _aa.adjustForAlignment(); // uses annotation's own record of
                                     // sequence-column mapping
           datasetSequence.addAlignmentAnnotation(_aa);
+
+          // transfer contact matrices
+          ContactMatrixI cm = getContactMatrixFor(aa);
+          if (cm != null)
+          {
+            datasetSequence.addContactListFor(_aa, cm);
+          }
         }
       }
     }
@@ -2111,7 +2118,7 @@ public class Sequence extends ASequence implements SequenceI
   ////
   //// Contact Matrix Holder Boilerplate
   ////
-  ContactMapHolder cmholder = new ContactMapHolder();
+  ContactMapHolderI cmholder = new ContactMapHolder();
 
   @Override
   public Collection<ContactMatrixI> getContactMaps()
@@ -2120,6 +2127,12 @@ public class Sequence extends ASequence implements SequenceI
   }
 
   @Override
+  public ContactMatrixI getContactMatrixFor(AlignmentAnnotation ann)
+  {
+    return cmholder.getContactMatrixFor(ann);
+  }
+
+  @Override
   public ContactListI getContactListFor(AlignmentAnnotation _aa, int column)
   {
     return cmholder.getContactListFor(_aa, column);
@@ -2137,8 +2150,16 @@ public class Sequence extends ASequence implements SequenceI
       ;
     }
     aa.annotations = _aa;
+    aa.setSequenceRef(this);
+    aa.createSequenceMapping(this, getStart(), false);
     addAlignmentAnnotation(aa);
     return aa;
   }
 
+  @Override
+  public void addContactListFor(AlignmentAnnotation annotation,
+          ContactMatrixI cm)
+  {
+    cmholder.addContactListFor(annotation, cm);
+  }
 }
index 6a0e64c..b356894 100755 (executable)
@@ -1499,6 +1499,12 @@ public class SequenceGroup implements AnnotatedCollectionI
   }
 
   @Override
+  public ContactMatrixI getContactMatrixFor(AlignmentAnnotation ann)
+  {
+    return cmholder.getContactMatrixFor(ann);
+  }
+
+  @Override
   public ContactListI getContactListFor(AlignmentAnnotation _aa, int column)
   {
     return cmholder.getContactListFor(_aa, column);
@@ -1519,4 +1525,12 @@ public class SequenceGroup implements AnnotatedCollectionI
     // TODO passing annotations back to context to be added
     return aa;
   }
+
+  @Override
+  public void addContactListFor(AlignmentAnnotation annotation,
+          ContactMatrixI cm)
+  {
+    cmholder.addContactListFor(annotation, cm);
+  }
+
 }
index 34dbab7..c789857 100755 (executable)
@@ -596,4 +596,7 @@ public interface SequenceI extends ASequenceI, ContactMapHolderI
    */
   public int firstResidueOutsideIterator(Iterator<int[]> it);
 
+  public void addContactListFor(AlignmentAnnotation annotation,
+          ContactMatrixI cm);
+
 }
index ec123f4..269fc31 100644 (file)
@@ -290,6 +290,13 @@ public class JmolParser extends StructureFile implements JmolStatusListener
           Console.info("retrieving pAE for " + pdbId);
           Alignment al = new Alignment(prot.toArray(new SequenceI[0]));
           EBIAlfaFold.retrieve_AlphaFold_pAE(pdbId, al, null);
+          if (al.getAlignmentAnnotation() != null)
+          {
+            for (AlignmentAnnotation alann : al.getAlignmentAnnotation())
+            {
+              annotations.add(alann);
+            }
+          }
           ;
         } catch (Throwable t)
         {
index 0e148ff..9e488c9 100644 (file)
@@ -197,7 +197,8 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
                 "exception.no_pdb_records_for_chain", new String[]
                 { id, ((chain == null) ? "' '" : chain) }));
       }
-      retrieve_AlphaFold_pAE(id, pdbAlignment, retrievalUrl);
+      // done during structure retrieval
+      // retrieve_AlphaFold_pAE(id, pdbAlignment, retrievalUrl);
 
     } catch (Exception ex) // Problem parsing PDB file
     {
@@ -274,11 +275,9 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
             pdbAlignment.getSequenceAt(0),
             (Map<String, Object>) pae_obj.get(0));
 
-    // THIS IS NOT GOING TO WORK !!!
-    // ?? StructureFile assumes sequenceI holds all data, so AlignmentAnnotation
-    // needs to hold the contact matrix data.
-    pdbAlignment.getSequenceAt(0)
-            .addAlignmentAnnotation(pdbAlignment.addContactList(matrix));
+    AlignmentAnnotation cmannot = pdbAlignment.getSequenceAt(0)
+            .addContactList(matrix);
+    pdbAlignment.addAnnotation(cmannot);
     return true;
   }
 
index dc25368..035e608 100755 (executable)
@@ -28,6 +28,7 @@ import java.util.Vector;
 import jalview.analysis.AlignSeq;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.Mapping;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
@@ -664,10 +665,16 @@ public class PDBChain
                   ana.getCalcId(), ana.label, ana.description);
           if (transfer == null || transfer.size() == 0)
           {
+            ContactMatrixI cm = shadow.getContactMatrixFor(ana);
             ana = new AlignmentAnnotation(ana);
+            // TODO map contact matrix under mapping
             ana.liftOver(sequence, shadowMap);
             ana.liftOver(dsq, sqmpping);
             dsq.addAlignmentAnnotation(ana);
+            if (cm != null)
+            {
+              dsq.addContactListFor(ana, cm);
+            }
           }
           else
           {
@@ -688,10 +695,14 @@ public class PDBChain
                             ana.description);
             if (transfer == null || transfer.size() == 0)
             {
+              ContactMatrixI cm = sequence.getContactMatrixFor(ana);
               ana = new AlignmentAnnotation(ana);
               ana.liftOver(dsq, sqmpping);
               dsq.addAlignmentAnnotation(ana);
-              // mapping.transfer(ana);
+              if (cm != null)
+              {
+                dsq.addContactListFor(ana, cm);
+              }
             }
             else
             {
index e231e7f..c1eb9fd 100644 (file)
@@ -2600,4 +2600,35 @@ public class AlignmentUtilsTests
             dnaToPeptide);
     assertSame(seq, cds1.getDatasetSequence());
   }
+
+  @Test(groups = "Functional")
+  public void testAddReferenceContactMap()
+  {
+    SequenceI sq = new Sequence("a", "SSSQ");
+    ContactMatrixI cm = new SeqDistanceContactMatrix(4);
+    AlignmentAnnotation cm_aan = sq.addContactList(cm);
+    SequenceI dssq = sq.createDatasetSequence();
+    Alignment ds = new Alignment(new SequenceI[] { dssq });
+
+    // remove annotation on our non-dataset sequence
+    sq.removeAlignmentAnnotation(sq.getAnnotation()[0]);
+    // test transfer
+    Alignment al = new Alignment(new SequenceI[] { sq });
+    SortedMap<String, String> tipEntries = new TreeMap<>();
+    final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
+
+    AlignmentUtils.findAddableReferenceAnnotations(al.getSequences(),
+            tipEntries, candidates, al);
+    AlignmentUtils.addReferenceAnnotations(candidates, al, null);
+    assertTrue("No contact map annotation transferred",
+            al.getAlignmentAnnotation() != null
+                    && al.getAlignmentAnnotation().length == 1);
+    AlignmentAnnotation alan = al.findAnnotations(sq, null, cm_aan.label)
+            .iterator().next();
+    ContactListI cl = al.getContactListFor(alan, 1);
+    assertNotNull(
+            "No contact matrix recovered after reference annotation transfer",
+            cl);
+
+  }
 }
index 6769d39..d2b5aec 100644 (file)
  */
 package jalview.ws.seqfetcher;
 
-import static org.testng.Assert.assertNotEquals;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
 import jalview.analysis.CrossRef;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
@@ -43,15 +51,6 @@ import jalview.ws.dbsources.EBIAlfaFold;
 import jalview.ws.dbsources.Pdb;
 import jalview.ws.dbsources.Uniprot;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.Assert;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
 /**
  * @author jimp
  * 
@@ -240,18 +239,21 @@ public class DbRefFetcherTest
   public void testAlphaFoldClien() throws Exception
   {
     DbSourceProxy alphafold = new EBIAlfaFold();
-    AlignmentI resp = alphafold.getSequenceRecords(alphafold.getTestQuery());
+    AlignmentI resp = alphafold
+            .getSequenceRecords(alphafold.getTestQuery());
     assertNotNull(resp);
-    assertEquals("One sequence only",resp.getHeight(), 1);
-    for (AlignmentAnnotation aa:resp.getAlignmentAnnotation()) {
+    assertEquals("One sequence only", resp.getHeight(), 1);
+    for (AlignmentAnnotation aa : resp.getAlignmentAnnotation())
+    {
       if (aa.graph == AlignmentAnnotation.CUSTOMRENDERER)
       {
-        assertTrue("Contact map didn't provide valid contact",resp.getContactListFor(aa, 1).getContactAt(1)!=-1d);
+        assertTrue("Contact map didn't provide valid contact",
+                resp.getContactListFor(aa, 1).getContactAt(1) != -1d);
         // test passes
         return;
       }
     }
-    Assert.fail();
+    Assert.fail("No pAE matrix found for alphafold structure.");
   }
 
 }