*/
package jalview.util;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
import jalview.analysis.AlignmentSorter;
import jalview.api.AlignViewportI;
+import jalview.bin.Cache;
import jalview.commands.CommandI;
import jalview.commands.EditCommand;
import jalview.commands.EditCommand.Action;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
/**
* Helper methods for manipulations involving sequence mappings.
*
action = action.getUndoAction();
}
// TODO write this
- System.err.println("MappingUtils.mapCutOrPaste not yet implemented");
+ Cache.log.error("MappingUtils.mapCutOrPaste not yet implemented");
}
/**
while (regions.hasNext())
{
mapHiddenColumns(regions.next(), codonFrames, newHidden,
- fromSequences,
- toSequences, fromGapChar);
+ fromSequences, toSequences, fromGapChar);
}
return; // mappedColumns;
}
{
if (range.length % 2 != 0)
{
- System.err.println(
+ Cache.log.error(
"Error unbalance start/end ranges: " + ranges.toString());
return 0;
}
int min = Math.min(range[0], range[1]);
int max = Math.max(range[0], range[1]);
-
+
return (min <= queryRange[0] && max >= queryRange[0]
&& min <= queryRange[1] && max >= queryRange[1]);
}
* a list of (single) [start, end] ranges
* @return
*/
- public static void removeEndPositions(int positions,
- List<int[]> ranges)
+ public static void removeEndPositions(int positions, List<int[]> ranges)
{
int toRemove = positions;
Iterator<int[]> it = new ReverseListIterator<>(ranges);
/*
* not coded for [start1, end1, start2, end2, ...]
*/
- System.err
- .println("MappingUtils.removeEndPositions doesn't handle multiple ranges");
+ Cache.log.error(
+ "MappingUtils.removeEndPositions doesn't handle multiple ranges");
return;
}
/*
* not coded for a reverse strand range (end < start)
*/
- System.err
- .println("MappingUtils.removeEndPositions doesn't handle reverse strand");
+ Cache.log.error(
+ "MappingUtils.removeEndPositions doesn't handle reverse strand");
return;
}
if (length > toRemove)
}
}
}
+
+ /**
+ * Returns the maximal start-end positions in the given (ordered) list of
+ * ranges which is overlapped by the given begin-end range, or null if there
+ * is no overlap.
+ *
+ * <pre>
+ * Examples:
+ * if ranges is {[4, 8], [10, 12], [16, 19]}
+ * then
+ * findOverlap(ranges, 1, 20) == [4, 19]
+ * findOverlap(ranges, 6, 11) == [6, 11]
+ * findOverlap(ranges, 9, 15) == [10, 12]
+ * findOverlap(ranges, 13, 15) == null
+ * </pre>
+ *
+ * @param ranges
+ * @param begin
+ * @param end
+ * @return
+ */
+ protected static int[] findOverlap(List<int[]> ranges, final int begin,
+ final int end)
+ {
+ boolean foundStart = false;
+ int from = 0;
+ int to = 0;
+
+ /*
+ * traverse the ranges to find the first position (if any) >= begin,
+ * and the last position (if any) <= end
+ */
+ for (int[] range : ranges)
+ {
+ if (!foundStart)
+ {
+ if (range[0] >= begin)
+ {
+ /*
+ * first range that starts with, or follows, begin
+ */
+ foundStart = true;
+ from = Math.max(range[0], begin);
+ }
+ else if (range[1] >= begin)
+ {
+ /*
+ * first range that contains begin
+ */
+ foundStart = true;
+ from = begin;
+ }
+ }
+
+ if (range[0] <= end)
+ {
+ to = Math.min(end, range[1]);
+ }
+ }
+
+ return foundStart && to >= from ? new int[] { from, to } : null;
+ }
}
import static org.testng.AssertJUnit.assertTrue;
import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
-import jalview.gui.JvOptionPane;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
+import jalview.bin.Cache;
+import jalview.gui.JvOptionPane;
+
public class MapListTest
{
@BeforeClass(alwaysRun = true)
+ public void setUp()
+ {
+ Cache.initLogger();
+ }
+
+ @BeforeClass(alwaysRun = true)
public void setUpJvOptionPane()
{
JvOptionPane.setInteractiveMode(false);
@Test(groups = { "Functional" })
public void testSomething()
{
- MapList ml = new MapList(new int[] { 1, 5, 10, 15, 25, 20 }, new int[] {
- 51, 1 }, 1, 3);
+ MapList ml = new MapList(new int[] { 1, 5, 10, 15, 25, 20 },
+ new int[]
+ { 51, 1 }, 1, 3);
MapList ml1 = new MapList(new int[] { 1, 3, 17, 4 },
- new int[] { 51, 1 }, 1, 3);
+ new int[]
+ { 51, 1 }, 1, 3);
MapList ml2 = new MapList(new int[] { 1, 60 }, new int[] { 1, 20 }, 3,
1);
// test internal consistency
int to[] = new int[51];
testMap(ml, 1, 60);
- MapList mldna = new MapList(new int[] { 2, 2, 6, 8, 12, 16 }, new int[]
- { 1, 3 }, 3, 1);
+ MapList mldna = new MapList(new int[] { 2, 2, 6, 8, 12, 16 },
+ new int[]
+ { 1, 3 }, 3, 1);
int[] frm = mldna.locateInFrom(1, 1);
testLocateFrom(mldna, 1, 1, new int[] { 2, 2, 6, 7 });
testMap(mldna, 1, 3);
}
/**
+ * Tests for method that locates the overlap of the ranges in the 'from' map
+ * for given range in the 'to' map
+ */
+ @Test(groups = { "Functional" })
+ public void testGetOverlapsInFrom_withIntrons()
+ {
+ /*
+ * Exons at positions [2, 3, 5] [6, 7, 9] [10, 12, 14] [16, 17, 18] i.e.
+ * 2-3, 5-7, 9-10, 12-12, 14-14, 16-18
+ */
+ int[] codons = { 2, 3, 5, 7, 9, 10, 12, 12, 14, 14, 16, 18 };
+ int[] protein = { 11, 14 };
+ MapList ml = new MapList(codons, protein, 3, 1);
+
+ assertEquals("[2, 3, 5, 5]",
+ Arrays.toString(ml.getOverlapsInFrom(11, 11)));
+ assertEquals("[2, 3, 5, 7, 9, 9]",
+ Arrays.toString(ml.getOverlapsInFrom(11, 12)));
+ // out of range 5' :
+ assertEquals("[2, 3, 5, 7, 9, 9]",
+ Arrays.toString(ml.getOverlapsInFrom(8, 12)));
+ // out of range 3' :
+ assertEquals("[10, 10, 12, 12, 14, 14, 16, 18]",
+ Arrays.toString(ml.getOverlapsInFrom(13, 16)));
+ // out of range both :
+ assertEquals("[2, 3, 5, 7, 9, 10, 12, 12, 14, 14, 16, 18]",
+ Arrays.toString(ml.getOverlapsInFrom(1, 16)));
+ // no overlap:
+ assertNull(ml.getOverlapsInFrom(20, 25));
+ }
+
+ /**
+ * Tests for method that locates the overlap of the ranges in the 'to' map
+ * for given range in the 'from' map
+ */
+ @Test(groups = { "Functional" })
+ public void testGetOverlapsInTo_withIntrons()
+ {
+ /*
+ * Exons at positions [2, 3, 5] [6, 7, 9] [10, 12, 14] [17, 18, 19] i.e.
+ * 2-3, 5-7, 9-10, 12-12, 14-14, 17-19
+ */
+ int[] codons = { 2, 3, 5, 7, 9, 10, 12, 12, 14, 14, 17, 19 };
+ /*
+ * Mapped proteins at positions 1, 3, 4, 6 in the sequence
+ */
+ int[] protein = { 1, 1, 3, 4, 6, 6 };
+ MapList ml = new MapList(codons, protein, 3, 1);
+
+ /*
+ * Can't map from an unmapped position
+ */
+ assertNull(ml.getOverlapsInTo(1, 1));
+ assertNull(ml.getOverlapsInTo(4, 4));
+ assertNull(ml.getOverlapsInTo(15, 16));
+
+ /*
+ * nor from a range that includes no mapped position (exon)
+ */
+ assertNull(ml.getOverlapsInTo(15, 16));
+
+ // end of codon 1 maps to first peptide
+ assertEquals("[1, 1]", Arrays.toString(ml.getOverlapsInTo(2, 2)));
+ // end of codon 1 and start of codon 2 maps to first 2 peptides
+ assertEquals("[1, 1, 3, 3]", Arrays.toString(ml.getOverlapsInTo(3, 7)));
+
+ // range overlaps 5' end of dna:
+ assertEquals("[1, 1, 3, 3]", Arrays.toString(ml.getOverlapsInTo(1, 6)));
+ assertEquals("[1, 1, 3, 3]", Arrays.toString(ml.getOverlapsInTo(1, 8)));
+
+ // range overlaps 3' end of dna:
+ assertEquals("[6, 6]", Arrays.toString(ml.getOverlapsInTo(17, 24)));
+ assertEquals("[6, 6]", Arrays.toString(ml.getOverlapsInTo(16, 24)));
+
+ // dna positions 8, 11 are intron but include end of exon 2 and start of exon 3
+ assertEquals("[3, 4]", Arrays.toString(ml.getOverlapsInTo(8, 11)));
+ }
+
+ /**
* Tests for method that locates ranges in the 'to' map for given range in the
* 'from' map.
*/
List<int[]> ranges = new ArrayList<>();
ranges.add(new int[] { 2, 3 });
ranges.add(new int[] { 5, 6 });
- assertEquals("[2, 3, 5, 6]", Arrays.toString(MapList.getRanges(ranges)));
+ assertEquals("[2, 3, 5, 6]",
+ Arrays.toString(MapList.getRanges(ranges)));
}
/**
assertEquals(6, ml2.getToHighest());
assertEquals("{[2, 3], [5, 7], [9, 10], [12, 12], [14, 14], [16, 18]}",
prettyPrint(ml2.getFromRanges()));
- assertEquals("{[1, 1], [3, 4], [6, 6]}", prettyPrint(ml2.getToRanges()));
+ assertEquals("{[1, 1], [3, 4], [6, 6]}",
+ prettyPrint(ml2.getToRanges()));
/*
* reverse direction
@Test(groups = { "Functional" })
public void testToString()
{
- MapList ml = new MapList(new int[] { 1, 5, 10, 15, 25, 20 }, new int[] {
- 51, 1 }, 1, 3);
+ MapList ml = new MapList(new int[] { 1, 5, 10, 15, 25, 20 },
+ new int[]
+ { 51, 1 }, 1, 3);
String s = ml.toString();
assertEquals("[ [1, 5] [10, 15] [25, 20] ] 1:3 to [ [51, 1] ]", s);
}
public void testAddMapList()
{
MapList ml = new MapList(new int[] { 11, 15, 20, 25, 35, 30 },
- new int[] { 72, 22 }, 1, 3);
+ new int[]
+ { 72, 22 }, 1, 3);
assertEquals(11, ml.getFromLowest());
assertEquals(35, ml.getFromHighest());
assertEquals(22, ml.getToLowest());
assertEquals(72, ml.getToHighest());
- MapList ml2 = new MapList(new int[] { 2, 4, 37, 40 }, new int[] { 12,
- 17, 78, 83, 88, 96 }, 1, 3);
+ MapList ml2 = new MapList(new int[] { 2, 4, 37, 40 },
+ new int[]
+ { 12, 17, 78, 83, 88, 96 }, 1, 3);
ml.addMapList(ml2);
assertEquals(2, ml.getFromLowest());
assertEquals(40, ml.getFromHighest());
public void testAddMapList_sameMap()
{
MapList ml = new MapList(new int[] { 11, 15, 20, 25, 35, 30 },
- new int[] { 72, 22 }, 1, 3);
+ new int[]
+ { 72, 22 }, 1, 3);
String before = ml.toString();
ml.addMapList(ml);
assertEquals(before, ml.toString());
MapList ml = new MapList(new int[] { 11, 15 }, new int[] { 72, 58 }, 1,
3);
- MapList ml2 = new MapList(new int[] { 15, 16 }, new int[] { 58, 53 },
- 1, 3);
+ MapList ml2 = new MapList(new int[] { 15, 16 }, new int[] { 58, 53 }, 1,
+ 3);
ml.addMapList(ml2);
assertEquals("[ [11, 16] ] 1:3 to [ [72, 53] ]", ml.toString());
}
public void testIsFromForwardStrand()
{
// [3-9] declares forward strand
- MapList ml = new MapList(new int[] { 2, 2, 3, 9, 12, 11 }, new int[] {
- 20, 11 }, 1, 1);
+ MapList ml = new MapList(new int[] { 2, 2, 3, 9, 12, 11 },
+ new int[]
+ { 20, 11 }, 1, 1);
assertTrue(ml.isFromForwardStrand());
// [11-5] declares reverse strand ([13-14] is ignored)
ml = new MapList(new int[] { 2, 2, 11, 5, 13, 14 },
- new int[] { 20, 11 }, 1, 1);
+ new int[]
+ { 20, 11 }, 1, 1);
assertFalse(ml.isFromForwardStrand());
// all single position ranges - defaults to forward strand
/*
* simple 1:1 plus 1:1 forwards
*/
- MapList ml1 = new MapList(new int[] { 3, 4, 8, 12 }, new int[] { 5, 8,
- 11, 13 }, 1, 1);
+ MapList ml1 = new MapList(new int[] { 3, 4, 8, 12 },
+ new int[]
+ { 5, 8, 11, 13 }, 1, 1);
assertEquals("{[3, 4], [8, 12]}", prettyPrint(ml1.getFromRanges()));
assertEquals("{[5, 8], [11, 13]}", prettyPrint(ml1.getToRanges()));
- MapList ml2 = new MapList(new int[] { 1, 50 }, new int[] { 40, 45, 70,
- 75, 90, 127 }, 1, 1);
+ MapList ml2 = new MapList(new int[] { 1, 50 },
+ new int[]
+ { 40, 45, 70, 75, 90, 127 }, 1, 1);
assertEquals("{[1, 50]}", prettyPrint(ml2.getFromRanges()));
assertEquals("{[40, 45], [70, 75], [90, 127]}",
prettyPrint(ml2.getToRanges()));
*/
ml1 = new MapList(new int[] { 1, 50 }, new int[] { 70, 119 }, 1, 1);
ml2 = new MapList(new int[] { 1, 500 },
- new int[] { 1000, 901, 600, 201 }, 1, 1);
+ new int[]
+ { 1000, 901, 600, 201 }, 1, 1);
compound = ml1.traverse(ml2);
assertEquals(1, compound.getFromRatio());
* 1:1 plus 1:3 should result in 1:3
*/
ml1 = new MapList(new int[] { 1, 30 }, new int[] { 11, 40 }, 1, 1);
- ml2 = new MapList(new int[] { 1, 100 }, new int[] { 1, 50, 91, 340 },
- 1, 3);
+ ml2 = new MapList(new int[] { 1, 100 }, new int[] { 1, 50, 91, 340 }, 1,
+ 3);
compound = ml1.traverse(ml2);
assertEquals(1, compound.getFromRatio());
* 3:1 plus 1:1 should result in 3:1
*/
ml1 = new MapList(new int[] { 1, 30 }, new int[] { 11, 20 }, 3, 1);
- ml2 = new MapList(new int[] { 1, 100 }, new int[] { 1, 15, 91, 175 },
- 1, 1);
+ ml2 = new MapList(new int[] { 1, 100 }, new int[] { 1, 15, 91, 175 }, 1,
+ 1);
compound = ml1.traverse(ml2);
assertEquals(3, compound.getFromRatio());
}
/**
- * Test that method that inspects for the (first) forward or reverse 'to' range.
- * Single position ranges are ignored.
+ * Test that method that inspects for the (first) forward or reverse 'to'
+ * range. Single position ranges are ignored.
*/
@Test(groups = { "Functional" })
public void testIsToForwardsStrand()