From 480d7b96f089281a3caf77d2a4e5adec09dc5bfa Mon Sep 17 00:00:00 2001 From: gmungoc Date: Mon, 29 May 2017 11:54:47 +0100 Subject: [PATCH] JAL-2526 Sequence.findPositions to get residue positions for column range --- src/jalview/datamodel/Sequence.java | 66 +++++++++++++++++++- src/jalview/datamodel/SequenceI.java | 26 +++++++- .../renderer/seqfeatures/FeatureRenderer.java | 30 ++++++--- test/jalview/datamodel/SequenceTest.java | 28 +++++++-- 4 files changed, 133 insertions(+), 17 deletions(-) diff --git a/src/jalview/datamodel/Sequence.java b/src/jalview/datamodel/Sequence.java index d7ac7a7..dd7c24a 100755 --- a/src/jalview/datamodel/Sequence.java +++ b/src/jalview/datamodel/Sequence.java @@ -662,7 +662,7 @@ public class Sequence extends ASequence implements SequenceI // Rely on end being at least as long as the length of the sequence. while ((i < sequence.length) && (j <= end) && (j <= pos)) { - if (!jalview.util.Comparison.isGap(sequence[i])) + if (!Comparison.isGap(sequence[i])) { j++; } @@ -688,7 +688,7 @@ public class Sequence extends ASequence implements SequenceI int seqlen = sequence.length; while ((j < i) && (j < seqlen)) { - if (!jalview.util.Comparison.isGap(sequence[j])) + if (!Comparison.isGap(sequence[j])) { pos++; } @@ -700,6 +700,68 @@ public class Sequence extends ASequence implements SequenceI } /** + * {@inheritDoc} + */ + @Override + public Range findPositions(int fromCol, int toCol) + { + /* + * count residues before fromCol + */ + int j = 0; + int count = 0; + int seqlen = sequence.length; + while (j < fromCol && j < seqlen) + { + if (!Comparison.isGap(sequence[j])) + { + count++; + } + j++; + } + + /* + * find first and last residues between fromCol and toCol + */ + int firstPos = 0; + int lastPos = 0; + int firstPosCol = 0; + boolean foundFirst = false; + + while (j <= toCol && j < seqlen) + { + if (!Comparison.isGap(sequence[j])) + { + count++; + if (!foundFirst) + { + firstPos = count; + firstPosCol = j; + foundFirst = true; + } + lastPos = count; + } + j++; + } + + if (firstPos == 0) + { + /* + * no residues in this range + */ + return null; + } + + /* + * adjust for sequence start coordinate + */ + firstPos += start - 1; + lastPos += start - 1; + + return new Range(firstPos, lastPos); + } + + /** * Returns an int array where indices correspond to each residue in the * sequence and the element value gives its position in the alignment * diff --git a/src/jalview/datamodel/SequenceI.java b/src/jalview/datamodel/SequenceI.java index e4be5ee..163a4a0 100755 --- a/src/jalview/datamodel/SequenceI.java +++ b/src/jalview/datamodel/SequenceI.java @@ -176,7 +176,7 @@ public interface SequenceI extends ASequenceI public String getDescription(); /** - * Return the alignment column for a sequence position + * Return the alignment column (from 1..) for a sequence position * * @param pos * lying from start to end @@ -201,6 +201,30 @@ public interface SequenceI extends ASequenceI public int findPosition(int i); /** + * Returns the range of sequence positions included in the given alignment + * position range. If no positions are included (the range is entirely gaps), + * then returns null. + * + *
+   * Example: 
+   * >Seq/8-13
+   * ABC--DE-F
+   * findPositions(1, 4) returns Range(9, 9) // B only
+   * findPositions(3, 4) returns null // all gaps
+   * findPositions(2, 6) returns Range(10, 12) // CDE
+   * findPositions(3, 7) returns Range(11,12) // DE
+   * 
+ * + * @param fromCol + * first aligned column position (base 0, inclusive) + * @param toCol + * last aligned column position (base 0, inclusive) + * + * @return + */ + public Range findPositions(int fromCol, int toCol); + + /** * Returns an int array where indices correspond to each residue in the * sequence and the element value gives its position in the alignment * diff --git a/src/jalview/renderer/seqfeatures/FeatureRenderer.java b/src/jalview/renderer/seqfeatures/FeatureRenderer.java index d6be4c2..5dce2b8 100644 --- a/src/jalview/renderer/seqfeatures/FeatureRenderer.java +++ b/src/jalview/renderer/seqfeatures/FeatureRenderer.java @@ -21,6 +21,7 @@ package jalview.renderer.seqfeatures; import jalview.api.AlignViewportI; +import jalview.datamodel.Range; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.util.Comparison; @@ -277,8 +278,14 @@ public class FeatureRenderer extends FeatureRendererModel transparency)); } - int startPos = seq.findPosition(start); - int endPos = seq.findPosition(end);// todo a performant overload of this! + /* + * get range of sequence positions within column range + */ + Range seqRange = seq.findPositions(start, end); + if (seqRange == null) + { + return null; + } Color drawnColour = null; @@ -293,8 +300,8 @@ public class FeatureRenderer extends FeatureRendererModel continue; } - List overlaps = seq.findFeatures(startPos, endPos, - type); + List overlaps = seq.findFeatures(seqRange.start, + seqRange.end, type); for (SequenceFeature sequenceFeature : overlaps) { /* @@ -309,15 +316,18 @@ public class FeatureRenderer extends FeatureRendererModel Color featureColour = getColour(sequenceFeature); boolean isContactFeature = sequenceFeature.isContactFeature(); + // todo overload findIndex using Location data + int featureStartCol = seq.findIndex(sequenceFeature.begin); + int featureEndCol = seq.findIndex(sequenceFeature.end); if (isContactFeature) { boolean drawn = renderFeature(g, seq, - seq.findIndex(sequenceFeature.begin) - 1, - seq.findIndex(sequenceFeature.begin) - 1, featureColour, + featureStartCol - 1, + featureStartCol - 1, featureColour, start, end, y1, colourOnly); drawn |= renderFeature(g, seq, - seq.findIndex(sequenceFeature.end) - 1, - seq.findIndex(sequenceFeature.end) - 1, featureColour, + featureEndCol - 1, + featureEndCol - 1, featureColour, start, end, y1, colourOnly); if (drawn) { @@ -347,8 +357,8 @@ public class FeatureRenderer extends FeatureRendererModel { */ boolean drawn = renderFeature(g, seq, - seq.findIndex(sequenceFeature.begin) - 1, - seq.findIndex(sequenceFeature.end) - 1, featureColour, + featureStartCol - 1, + featureEndCol - 1, featureColour, start, end, y1, colourOnly); if (drawn) { diff --git a/test/jalview/datamodel/SequenceTest.java b/test/jalview/datamodel/SequenceTest.java index 7eeac12..4da11eb 100644 --- a/test/jalview/datamodel/SequenceTest.java +++ b/test/jalview/datamodel/SequenceTest.java @@ -231,10 +231,10 @@ public class SequenceTest assertEquals(6, sq.findIndex(6)); assertEquals(6, sq.findIndex(9)); - sq = new Sequence("test", "-A--B-C-D-E-F--"); - assertEquals(2, sq.findIndex(1)); - assertEquals(5, sq.findIndex(2)); - assertEquals(7, sq.findIndex(3)); + sq = new Sequence("test/8-13", "-A--B-C-D-E-F--"); + assertEquals(2, sq.findIndex(8)); + assertEquals(5, sq.findIndex(9)); + assertEquals(7, sq.findIndex(10)); // before start returns 0 assertEquals(0, sq.findIndex(0)); @@ -1161,4 +1161,24 @@ public class SequenceTest seq2.createDatasetSequence(); seq.setDatasetSequence(seq2); } + + @Test + public void testFindPositions() + { + SequenceI sq = new Sequence("Seq", "ABC--DE-F", 8, 13); + + Range range = sq.findPositions(1, 4); // BC + assertEquals(new Range(9, 10), range); + + range = sq.findPositions(2, 4); // C + assertEquals(new Range(10, 10), range); + + assertNull(sq.findPositions(3, 4)); // all gaps + + range = sq.findPositions(2, 6); // CDE + assertEquals(new Range(10, 12), range); + + range = sq.findPositions(3, 7); // DE + assertEquals(new Range(11, 12), range); + } } -- 1.7.10.2