JAL-2617 omit stop codon from synthesized CDS sequence
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 1 Sep 2017 16:04:31 +0000 (17:04 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 1 Sep 2017 16:04:31 +0000 (17:04 +0100)
src/jalview/analysis/AlignmentUtils.java
src/jalview/util/MappingUtils.java
test/jalview/util/MappingUtilsTest.java

index 2b9b9f9..311a9a3 100644 (file)
@@ -2200,7 +2200,10 @@ public class AlignmentUtils
     {
       // assuming extra codon is for STOP and not in peptide
       codesForResidues--;
+      mappedDnaLength -= CODON_LENGTH;
+      MappingUtils.removeEndPositions(CODON_LENGTH, ranges);
     }
+
     if (codesForResidues == proteinLength)
     {
       proteinRange.add(new int[] { proteinStart, proteinEnd });
@@ -2211,7 +2214,7 @@ public class AlignmentUtils
 
   /**
    * Returns a list of CDS ranges found (as sequence positions base 1), i.e. of
-   * start/end positions of sequence features of type "CDS" (or a sub-type of
+   * [start, end] positions of sequence features of type "CDS" (or a sub-type of
    * CDS in the Sequence Ontology). The ranges are sorted into ascending start
    * position order, so this method is only valid for linear CDS in the same
    * sense as the protein product.
index 3682239..9c5c109 100644 (file)
@@ -939,4 +939,55 @@ public final class MappingUtils
     }
     return copy;
   }
+
+  /**
+   * Removes the specified number of positions from the given ranges. Provided
+   * to allow a stop codon to be stripped from a CDS sequence so that it matches
+   * the peptide translation length.
+   * 
+   * @param positions
+   * @param ranges
+   *          a list of (single) [start, end] ranges
+   * @return
+   */
+  public static void removeEndPositions(int positions,
+          List<int[]> ranges)
+  {
+    int toRemove = positions;
+    Iterator<int[]> it = new ReverseListIterator<>(ranges);
+    while (toRemove > 0)
+    {
+      int[] endRange = it.next();
+      if (endRange.length != 2)
+      {
+        /*
+         * not coded for [start1, end1, start2, end2, ...]
+         */
+        System.err
+                .println("MappingUtils.removeEndPositions doesn't handle multiple  ranges");
+        return;
+      }
+
+      int length = endRange[1] - endRange[0] + 1;
+      if (length <= 0)
+      {
+        /*
+         * not coded for a reverse strand range (end < start)
+         */
+        System.err
+                .println("MappingUtils.removeEndPositions doesn't handle reverse strand");
+        return;
+      }
+      if (length > toRemove)
+      {
+        endRange[1] -= toRemove;
+        toRemove = 0;
+      }
+      else
+      {
+        toRemove -= length;
+        it.remove();
+      }
+    }
+  }
 }
index d0ec3e8..5226819 100644 (file)
@@ -1149,4 +1149,49 @@ public class MappingUtilsTest
     assertEquals("[12, 11, 8, 4]", Arrays.toString(ranges));
   }
 
+  @Test(groups = "Functional")
+  public void testRemoveEndPositions()
+  {
+    List<int[]> ranges = new ArrayList<>();
+
+    /*
+     * case 1: truncate last range
+     */
+    ranges.add(new int[] { 1, 10 });
+    ranges.add(new int[] { 20, 30 });
+    MappingUtils.removeEndPositions(5, ranges);
+    assertEquals(2, ranges.size());
+    assertEquals(25, ranges.get(1)[1]);
+
+    /*
+     * case 2: remove last range
+     */
+    ranges.clear();
+    ranges.add(new int[] { 1, 10 });
+    ranges.add(new int[] { 20, 22 });
+    MappingUtils.removeEndPositions(3, ranges);
+    assertEquals(1, ranges.size());
+    assertEquals(10, ranges.get(0)[1]);
+
+    /*
+     * case 3: truncate penultimate range
+     */
+    ranges.clear();
+    ranges.add(new int[] { 1, 10 });
+    ranges.add(new int[] { 20, 21 });
+    MappingUtils.removeEndPositions(3, ranges);
+    assertEquals(1, ranges.size());
+    assertEquals(9, ranges.get(0)[1]);
+
+    /*
+     * case 4: remove last two ranges
+     */
+    ranges.clear();
+    ranges.add(new int[] { 1, 10 });
+    ranges.add(new int[] { 20, 20 });
+    ranges.add(new int[] { 30, 30 });
+    MappingUtils.removeEndPositions(3, ranges);
+    assertEquals(1, ranges.size());
+    assertEquals(9, ranges.get(0)[1]);
+  }
 }