JAL-3725 restrict mapped virtual feature location to mapped region
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 27 Aug 2020 15:02:06 +0000 (16:02 +0100)
committerBen Soares <b.soares@dundee.ac.uk>
Fri, 1 Oct 2021 17:18:40 +0000 (18:18 +0100)
src/jalview/datamodel/MappedFeatures.java
src/jalview/datamodel/SequenceFeature.java
src/jalview/gui/PopupMenu.java
src/jalview/io/SequenceAnnotationReport.java
test/jalview/datamodel/SequenceFeatureTest.java

index f145d93..ca6db1b 100644 (file)
@@ -296,8 +296,8 @@ public class MappedFeatures
   public int[] getMappedPositions(int begin, int end)
   {
     MapList map = mapping.getMap();
-    return mapping.to == featureSequence ? map.locateInFrom(begin, end)
-            : map.locateInTo(begin, end);
+    return mapping.to == featureSequence ? map.getOverlapsInFrom(begin, end)
+            : map.getOverlapsInTo(begin, end);
   }
 
   /**
index 6eeba2f..bbf1b45 100755 (executable)
@@ -612,10 +612,9 @@ public class SequenceFeature implements FeatureLocationI
     String consequence = "";
     if (mf != null)
     {
-      int[] beginRange = mf.getMappedPositions(begin, begin);
-      int[] endRange = mf.getMappedPositions(end, end);
-      int from = beginRange[0];
-      int to = endRange[endRange.length - 1];
+      int[] localRange = mf.getMappedPositions(begin, end);
+      int from = localRange[0];
+      int to = localRange[localRange.length - 1];
       String s = mf.isFromCds() ? "Peptide Location" : "Coding location";
       sb.append(String.format(ROW_DATA, s, seqName, from == to ? from
               : from + (isContactFeature() ? ":" : "-") + to));
index 6b32efa..d1e8e32 100644 (file)
@@ -839,10 +839,13 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       /*
        * show local rather than linked feature coordinates
        */
-      int[] beginRange = mf.getMappedPositions(start, start);
-      start = beginRange[0];
-      int[] endRange = mf.getMappedPositions(end, end);
-      end = endRange[endRange.length - 1];
+      int[] localRange = mf.getMappedPositions(start, end);
+      if (localRange == null)
+      {
+        return;
+      }
+      start = localRange[0];
+      end = localRange[localRange.length - 1];
     }
     StringBuilder desc = new StringBuilder();
     desc.append(sf.getType()).append(" ").append(String.valueOf(start));
index 62b723d..9ffdf21 100644 (file)
@@ -209,12 +209,27 @@ public class SequenceAnnotationReport
      * if this is a virtual features, convert begin/end to the
      * coordinates of the sequence it is mapped to
      */
-    int[] beginRange = null;
-    int[] endRange = null;
+    int[] beginRange = null; // feature start in local coordinates
+    int[] endRange = null; // feature end in local coordinates
     if (mf != null)
     {
-      beginRange = mf.getMappedPositions(begin, begin);
-      endRange = mf.getMappedPositions(end, end);
+      if (feature.isContactFeature())
+      {
+        /*
+         * map start and end points individually
+         */
+        beginRange = mf.getMappedPositions(begin, begin);
+        endRange = begin == end ? beginRange
+                : mf.getMappedPositions(end, end);
+      }
+      else
+      {
+        /*
+         * map the feature extent
+         */
+        beginRange = mf.getMappedPositions(begin, end);
+        endRange = beginRange;
+      }
       if (beginRange == null || endRange == null)
       {
         // something went wrong
index f8479a3..bd5e9ac 100644 (file)
@@ -48,8 +48,8 @@ public class SequenceFeatureTest
   @Test(groups = { "Functional" })
   public void testCopyConstructors()
   {
-    SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33,
-            12.5f, "group");
+    SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+            "group");
     sf1.setValue("STRAND", "+");
     sf1.setValue("Note", "Testing");
     Integer count = Integer.valueOf(7);
@@ -83,8 +83,8 @@ public class SequenceFeatureTest
     /*
      * copy constructor modifying type/begin/end/group/score
      */
-    SequenceFeature sf4 = new SequenceFeature(sf1, "Disulfide bond", 12,
-            15, "group3", -9.1f);
+    SequenceFeature sf4 = new SequenceFeature(sf1, "Disulfide bond", 12, 15,
+            "group3", -9.1f);
     assertEquals("Disulfide bond", sf4.getType());
     assertTrue(sf4.isContactFeature());
     assertEquals("desc", sf4.getDescription());
@@ -104,8 +104,8 @@ public class SequenceFeatureTest
   @Test(groups = { "Functional" })
   public void testGetValue()
   {
-    SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33,
-            12.5f, "group");
+    SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+            "group");
     sf1.setValue("STRAND", "+");
     assertEquals("+", sf1.getValue("STRAND"));
     assertNull(sf1.getValue("strand")); // case-sensitive
@@ -137,15 +137,15 @@ public class SequenceFeatureTest
   @Test(groups = { "Functional" })
   public void testEqualsAndHashCode()
   {
-    SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33,
-            12.5f, "group");
+    SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+            "group");
     sf1.setValue("ID", "id");
     sf1.setValue("Name", "name");
     sf1.setValue("Parent", "parent");
     sf1.setStrand("+");
     sf1.setPhase("1");
-    SequenceFeature sf2 = new SequenceFeature("type", "desc", 22, 33,
-            12.5f, "group");
+    SequenceFeature sf2 = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+            "group");
     sf2.setValue("ID", "id");
     sf2.setValue("Name", "name");
     sf2.setValue("Parent", "parent");
@@ -158,10 +158,10 @@ public class SequenceFeatureTest
     assertEquals(sf1.hashCode(), sf2.hashCode());
 
     // changing type breaks equals:
-    SequenceFeature sf3 = new SequenceFeature("type", "desc", 22, 33,
-            12.5f, "group");
-    SequenceFeature sf4 = new SequenceFeature("Type", "desc", 22, 33,
-            12.5f, "group");
+    SequenceFeature sf3 = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+            "group");
+    SequenceFeature sf4 = new SequenceFeature("Type", "desc", 22, 33, 12.5f,
+            "group");
     assertFalse(sf3.equals(sf4));
 
     // changing description breaks equals:
@@ -195,7 +195,8 @@ public class SequenceFeatureTest
 
     // changing start position breaks equals:
     int restorei = sf2.getBegin();
-    sf2 = new SequenceFeature(sf2, 21, sf2.getEnd(), sf2.getFeatureGroup(), sf2.getScore());
+    sf2 = new SequenceFeature(sf2, 21, sf2.getEnd(), sf2.getFeatureGroup(),
+            sf2.getScore());
     assertFalse(sf1.equals(sf2));
     sf2 = new SequenceFeature(sf2, restorei, sf2.getEnd(),
             sf2.getFeatureGroup(), sf2.getScore());
@@ -210,9 +211,11 @@ public class SequenceFeatureTest
 
     // changing feature group breaks equals:
     restores = sf2.getFeatureGroup();
-    sf2 = new SequenceFeature(sf2, sf2.getBegin(), sf2.getEnd(), "Group", sf2.getScore());
+    sf2 = new SequenceFeature(sf2, sf2.getBegin(), sf2.getEnd(), "Group",
+            sf2.getScore());
     assertFalse(sf1.equals(sf2));
-    sf2 = new SequenceFeature(sf2, sf2.getBegin(), sf2.getEnd(), restores, sf2.getScore());
+    sf2 = new SequenceFeature(sf2, sf2.getBegin(), sf2.getEnd(), restores,
+            sf2.getScore());
 
     // changing ID breaks equals:
     restores = (String) sf2.getValue("ID");
@@ -285,7 +288,8 @@ public class SequenceFeatureTest
     String seqName = seq.getName();
 
     // single locus, no group, no score
-    SequenceFeature sf = new SequenceFeature("variant", "G,C", 22, 22, null);
+    SequenceFeature sf = new SequenceFeature("variant", "G,C", 22, 22,
+            null);
     String expected = "<br><table><tr><td>Location</td><td>TestSeq</td><td>22</td></tr>"
             + "<tr><td>Type</td><td>variant</td><td></td></tr>"
             + "<tr><td>Description</td><td>G,C</td><td></td></tr></table>";
@@ -299,8 +303,7 @@ public class SequenceFeatureTest
             + "<tr><td>Description</td><td>a description</td><td></td></tr></table>";
     assertEquals(expected, sf.getDetailsReport(seqName, null));
 
-    sf = new SequenceFeature("variant", "G,C", 22, 33,
-            12.5f, "group");
+    sf = new SequenceFeature("variant", "G,C", 22, 33, 12.5f, "group");
     sf.setValue("Parent", "ENSG001");
     sf.setValue("Child", "ENSP002");
     expected = "<br><table><tr><td>Location</td><td>TestSeq</td><td>22-33</td></tr>"
@@ -351,9 +354,23 @@ public class SequenceFeatureTest
             + "<tr><td>Type</td><td>variant</td><td></td></tr>"
             + "<tr><td>Description</td><td>G,C</td><td></td></tr>"
             + "<tr><td>Consequence</td><td><i>Translated by Jalview</i></td><td>p.Leu9Phe</td></tr>"
-            + "<tr><td>alleles</td><td></td><td>G,C</td></tr>"
+            + "<tr><td>alleles</td><td></td><td>G,C</td></tr>" 
             + "</table>";
 
     assertEquals(expected, sf.getDetailsReport(seq.getName(), mf));
+    
+
+    /*
+     * exon feature extending beyond mapped range; mapped location should be
+     * restricted to peptide mapped range limit i.e. 10-13
+     */
+    SequenceFeature sf2 = new SequenceFeature("exon", "exon 1", 109, 230, null);
+    features.add(sf2);
+    expected = "<br><table><tr><td>Location</td><td>Cds</td><td>109-230</td></tr>"
+            + "<tr><td>Peptide Location</td><td>TestSeq</td><td>10-13</td></tr>"
+            + "<tr><td>Type</td><td>exon</td><td></td></tr>"
+            + "<tr><td>Description</td><td>exon 1</td><td></td></tr>"
+            + "</table>";
+    assertEquals(expected, sf2.getDetailsReport(seq.getName(), mf));
   }
 }