JAL-2381 copy and paste sequence also copies contact matrix annotation
authorJames Procter <j.procter@dundee.ac.uk>
Thu, 25 May 2023 15:28:36 +0000 (16:28 +0100)
committerJames Procter <j.procter@dundee.ac.uk>
Thu, 25 May 2023 15:28:36 +0000 (16:28 +0100)
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceGroup.java
src/jalview/datamodel/SequenceI.java
src/jalview/gui/AlignFrame.java
test/jalview/datamodel/SequenceTest.java
test/jalview/gui/AlignViewportTest.java

index 33c8ac5..32d295a 100755 (executable)
@@ -33,6 +33,8 @@ import java.util.Vector;
 
 import fr.orsay.lri.varna.models.rna.RNA;
 import jalview.analysis.AlignSeq;
+import jalview.analysis.AlignmentUtils;
+import jalview.analysis.SeqsetUtils;
 import jalview.datamodel.features.SequenceFeatures;
 import jalview.datamodel.features.SequenceFeaturesI;
 import jalview.util.Comparison;
@@ -350,6 +352,11 @@ public class Sequence extends ASequence implements SequenceI
         {
           // only copy the given annotation
           AlignmentAnnotation newann = new AlignmentAnnotation(sqann[i]);
+          ContactMatrixI cm = seq.getContactMatrixFor(sqann[i]);
+          if (cm!=null)
+          {
+            addContactListFor(newann, cm);
+          }
           addAlignmentAnnotation(newann);
         }
       }
@@ -1627,14 +1634,19 @@ public class Sequence extends ASequence implements SequenceI
                                     // sequence-column mapping
           datasetSequence.addAlignmentAnnotation(_aa);
 
-          // transfer contact matrices
-          ContactMatrixI cm = getContactMatrixFor(aa);
-          if (cm != null)
-          {
-            datasetSequence.addContactListFor(_aa, cm);
+          if (_cmholder != null)
+          { // transfer contact matrices
+            ContactMatrixI cm = _cmholder.getContactMatrixFor(aa);
+            if (cm != null)
+            {
+              datasetSequence.addContactListFor(_aa, cm);
+              datasetSequence.addContactListFor(aa, cm);
+            }
           }
         }
       }
+      // all matrices should have been transferred. so we clear the local holder
+      _cmholder=null;
     }
     return datasetSequence;
   }
@@ -2119,30 +2131,56 @@ public class Sequence extends ASequence implements SequenceI
   ////
   //// Contact Matrix Holder Boilerplate
   ////
-  ContactMapHolderI cmholder = new ContactMapHolder();
+  ContactMapHolderI _cmholder = null;
 
+  private ContactMapHolderI getContactMapHolder()
+  {
+    if (datasetSequence!=null) {
+      return ((Sequence)datasetSequence).getContactMapHolder();
+    }
+    if (_cmholder==null)
+    {
+      _cmholder=new ContactMapHolder();
+    }
+    return _cmholder;
+  }
   @Override
   public Collection<ContactMatrixI> getContactMaps()
   {
-    return cmholder.getContactMaps();
+    return getContactMapHolder().getContactMaps();
   }
 
   @Override
   public ContactMatrixI getContactMatrixFor(AlignmentAnnotation ann)
   {
-    return cmholder.getContactMatrixFor(ann);
+    return getContactMapHolder().getContactMatrixFor(ann);
   }
 
   @Override
   public ContactListI getContactListFor(AlignmentAnnotation _aa, int column)
   {
-    return cmholder.getContactListFor(_aa, column);
+    return getContactMapHolder().getContactListFor(_aa, column);
   }
 
   @Override
   public AlignmentAnnotation addContactList(ContactMatrixI cm)
   {
-    AlignmentAnnotation aa = cmholder.addContactList(cm);
+    AlignmentAnnotation aa;
+    
+    if (datasetSequence != null)
+    {
+      aa = datasetSequence.addContactList(cm);
+      // clone the annotation for the local sequence
+      aa = new AlignmentAnnotation(aa);
+      aa.restrict(start, end);
+      aa.adjustForAlignment();
+      getContactMapHolder().addContactListFor(aa,cm);
+      addAlignmentAnnotation(aa);
+      return aa;
+    }
+    
+    // construct new annotation for matrix on dataset sequence
+    aa = getContactMapHolder().addContactList(cm);
 
     Annotation _aa[] = new Annotation[getLength()];
 
@@ -2166,6 +2204,6 @@ public class Sequence extends ASequence implements SequenceI
   public void addContactListFor(AlignmentAnnotation annotation,
           ContactMatrixI cm)
   {
-    cmholder.addContactListFor(annotation, cm);
+    getContactMapHolder().addContactListFor(annotation, cm);
   }
 }
index b356894..81f8664 100755 (executable)
@@ -311,6 +311,11 @@ public class SequenceGroup implements AnnotatedCollectionI
             newannot.restrict(startRes, endRes);
             newannot.setSequenceRef(seqs[ipos]);
             newannot.adjustForAlignment();
+            ContactMatrixI cm = seq.getContactMatrixFor(seq.getAnnotation()[a]);
+            if (cm!=null)
+            {
+              seqs[ipos].addContactListFor(newannot, cm);
+            }
             seqipos.addAlignmentAnnotation(newannot);
           }
         }
index c789857..2e1daa3 100755 (executable)
@@ -415,7 +415,7 @@ public interface SequenceI extends ASequenceI, ContactMapHolderI
   /**
    * Derive a sequence (using this one's dataset or as the dataset)
    * 
-   * @return duplicate sequence with valid dataset sequence
+   * @return duplicate sequence and any annotation present with valid dataset sequence
    */
   public SequenceI deriveSequence();
 
index ae945fe..48927bb 100644 (file)
@@ -2304,10 +2304,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                         .intValue();
               }
             }
-            alignment.addAnnotation(sequences[i].getAnnotation()[a]); // annotation
-            // was
-            // duplicated
-            // earlier
+            // annotation was duplicated earlier
+            alignment.addAnnotation(sequences[i].getAnnotation()[a]);
+            // take care of contact matrix too
+            ContactMatrixI cm=sequences[i].getContactMatrixFor(sequences[i].getAnnotation()[a]);
+            if (cm!=null)
+            {
+              alignment.addContactListFor(sequences[i].getAnnotation()[a], cm);
+            }
+            
             alignment.setAnnotationIndex(sequences[i].getAnnotation()[a],
                     a);
           }
index 0151a12..344d74d 100644 (file)
@@ -1052,6 +1052,38 @@ public class SequenceTest
     assertEquals("ABCDEF",
             derived.getDatasetSequence().getSequenceAsString());
   }
+  
+  /**
+   * test that creating a copy of an existing sequence with dataset sequence and
+   * associated contact matrix yields annotation associated with the same
+   * contact matrix in the copy
+   */
+  @Test(groups= {"Functional"})
+  public void testCopyPasteStyleDerivesequence_withcontactMatrixAnn()
+  {
+    SequenceI seq1=new Sequence("seq1","ACDACDACD");
+    seq1.createDatasetSequence();
+    ContactMatrixI cm = new SeqDistanceContactMatrix(seq1.getLength());
+    // addContactList needs to return annotation addable to the sequence reference it was called from
+    AlignmentAnnotation aann = seq1.addContactList(cm);
+    assertTrue(aann.sequenceRef==seq1);
+    assertEquals(1,seq1.getAnnotation().length);
+    assertNotNull(seq1.getContactListFor(seq1.getAnnotation()[0], 1));
+    
+    SequenceI seq_derived=seq1.deriveSequence();
+    assertEquals(1,seq_derived.getAnnotation().length);
+    assertTrue(cm==seq_derived.getContactMatrixFor(seq_derived.getAnnotation()[0]));
+    assertNotNull(seq_derived.getContactListFor(seq_derived.getAnnotation()[0], 1));
+    
+    // copy paste actually uses the copy constructor .. so
+    
+    SequenceI seq_copied=new Sequence((Sequence)seq_derived);
+    assertEquals(1,seq_copied.getAnnotation().length);
+    assertTrue(cm==seq_copied.getContactMatrixFor(seq_copied.getAnnotation()[0]));
+    assertNotNull(seq_copied.getContactListFor(seq_copied.getAnnotation()[0], 1));
+    
+    
+  }
 
   @Test(groups = { "Functional" })
   public void testCopyConstructor_noDataset()
index b3c6b2a..4537dcc 100644 (file)
@@ -42,8 +42,10 @@ import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
+import jalview.datamodel.SeqDistanceContactMatrix;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -537,4 +539,29 @@ public class AlignViewportTest
     assertEquals(0, ranges.getStartSeq());
     assertEquals(2, ranges.getEndSeq());
   }
+  @Test(groups = {"Functional"})
+  public void testGetSelectionAsNewSequences_withContactMatrices()
+  {
+    SequenceI seq = new Sequence("seq","ACADA");
+    ContactMatrixI cmat = new SeqDistanceContactMatrix(5);
+    seq.addContactList(cmat);
+    Alignment al = new Alignment(new SequenceI[] {seq.deriveSequence() });
+    al.addAnnotation(al.getSequenceAt(0).getAnnotation()[0]);
+    AlignFrame af = new AlignFrame(al,500,500);
+    
+    SequenceI selseqs[] = af.getViewport().getSelectionAsNewSequence();
+    assertNotNull(selseqs[0].getAnnotation());
+    assertNotNull(selseqs[0].getAnnotation()[0]);
+    assertEquals(cmat,selseqs[0].getContactMatrixFor(selseqs[0].getAnnotation()[0]));
+    
+    assertNotNull(selseqs[0].getContactListFor(selseqs[0].getAnnotation()[0], 2));
+    
+    // now select everything and test again
+    af.selectAllSequenceMenuItem_actionPerformed(null);
+    selseqs = af.getViewport().getSelectionAsNewSequence();
+    assertNotNull(selseqs[0].getAnnotation());
+    assertNotNull(selseqs[0].getAnnotation()[0]);
+    assertEquals(cmat,selseqs[0].getContactMatrixFor(selseqs[0].getAnnotation()[0]));
+    assertNotNull(selseqs[0].getContactListFor(selseqs[0].getAnnotation()[0], 2));
+  }
 }