From: gmungoc Date: Sun, 23 Jul 2017 07:59:37 +0000 (+0100) Subject: Merge branch 'develop' into features/JAL-2446NCList X-Git-Tag: Release_2_10_3b1~174 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=fb2d7072a283815141262d70d5f11a5e966d500b;p=jalview.git Merge branch 'develop' into features/JAL-2446NCList Conflicts: src/jalview/renderer/seqfeatures/FeatureRenderer.java src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java --- fb2d7072a283815141262d70d5f11a5e966d500b diff --cc src/jalview/api/FeatureColourI.java index 01eb7fa,01eb7fa..0ded079 --- a/src/jalview/api/FeatureColourI.java +++ b/src/jalview/api/FeatureColourI.java @@@ -146,7 -146,7 +146,9 @@@ public interface FeatureColour boolean hasThreshold(); /** -- * Returns the computed colour for the given sequence feature ++ * Returns the computed colour for the given sequence feature. Answers null if ++ * the score of this feature instance is outside the range to render (if any), ++ * i.e. lies below or above a configured threshold. * * @param feature * @return @@@ -154,17 -154,17 +156,6 @@@ Color getColor(SequenceFeature feature); /** -- * Answers true if the feature has a simple colour, or is coloured by label, -- * or has a graduated colour and the score of this feature instance is within -- * the range to render (if any), i.e. does not lie below or above any -- * threshold set. -- * -- * @param feature -- * @return -- */ -- boolean isColored(SequenceFeature feature); -- -- /** * Update the min-max range for a graduated colour scheme * * @param min diff --cc src/jalview/renderer/seqfeatures/FeatureRenderer.java index 3f44bcc,759101d..d661915 --- a/src/jalview/renderer/seqfeatures/FeatureRenderer.java +++ b/src/jalview/renderer/seqfeatures/FeatureRenderer.java @@@ -300,57 -305,61 +300,66 @@@ public class FeatureRenderer extends Fe continue; } - // loop through all features in sequence to find - // current feature to render - for (int sfindex = 0; sfindex < sfSize; sfindex++) + FeatureColourI fc = getFeatureStyle(type); + List overlaps = seq.getFeatures().findFeatures( + visiblePositions.getBegin(), visiblePositions.getEnd(), type); + + filterFeaturesForDisplay(overlaps, fc); + + for (SequenceFeature sf : overlaps) { - final SequenceFeature sequenceFeature = sequenceFeatures[sfindex]; - if (!sequenceFeature.type.equals(type)) + Color featureColour = fc.getColor(sf); ++ if (featureColour == null) + { ++ // score feature outwith threshold for colouring + continue; + } /* - * a feature type may be flagged as shown but the group - * an instance of it belongs to may be hidden + * if feature starts/ends outside the visible range, + * restrict to visible positions (or if a contact feature, + * to a single position) */ - if (featureGroupNotShown(sequenceFeature)) + int visibleStart = sf.getBegin(); + if (visibleStart < visiblePositions.getBegin()) { - continue; + visibleStart = sf.isContactFeature() ? sf.getEnd() + : visiblePositions.getBegin(); } - - /* - * check feature overlaps the target range - * TODO: efficient retrieval of features overlapping a range - */ - if (sequenceFeature.getBegin() > endPos - || sequenceFeature.getEnd() < startPos) + int visibleEnd = sf.getEnd(); + if (visibleEnd > visiblePositions.getEnd()) { - continue; + visibleEnd = sf.isContactFeature() ? sf.getBegin() + : visiblePositions.getEnd(); } - Color featureColour = getColour(sequenceFeature); - if (featureColour == null) - { - // score feature outwith threshold for colouring - continue; - } + int featureStartCol = seq.findIndex(visibleStart); + int featureEndCol = sf.begin == sf.end ? featureStartCol : seq + .findIndex(visibleEnd); + - if (sf.isContactFeature()) ++ // Color featureColour = getColour(sequenceFeature); + - boolean isContactFeature = sequenceFeature.isContactFeature(); ++ boolean isContactFeature = sf.isContactFeature(); + + if (isContactFeature) { - boolean drawn = renderFeature(g, seq, - seq.findIndex(sequenceFeature.begin) - 1, - seq.findIndex(sequenceFeature.begin) - 1, featureColour, - start, end, y1, colourOnly); - drawn |= renderFeature(g, seq, - seq.findIndex(sequenceFeature.end) - 1, - seq.findIndex(sequenceFeature.end) - 1, featureColour, - start, end, y1, colourOnly); + boolean drawn = renderFeature(g, seq, featureStartCol - 1, + featureStartCol - 1, featureColour, start, end, y1, + colourOnly); + drawn |= renderFeature(g, seq, featureEndCol - 1, + featureEndCol - 1, featureColour, start, end, y1, + colourOnly); if (drawn) { drawnColour = featureColour; } } - else if (showFeature(sf)) + else { + /* + * showing feature score by height of colour + * is not implemented as a selectable option + * if (av.isShowSequenceFeaturesHeight() && !Float.isNaN(sequenceFeature.score)) { @@@ -437,13 -464,33 +446,17 @@@ continue; } - for (int sfindex = 0; sfindex < sequenceFeatures.length; sfindex++) + List overlaps = seq.findFeatures(column, column, + type); + for (SequenceFeature sequenceFeature : overlaps) { - SequenceFeature sequenceFeature = sequenceFeatures[sfindex]; - if (!sequenceFeature.type.equals(type)) + if (!featureGroupNotShown(sequenceFeature)) { - return getColour(sequenceFeature); - continue; - } - - if (featureGroupNotShown(sequenceFeature)) - { - continue; - } - - /* - * check the column position is within the feature range - * (or is one of the two contact positions for a contact feature) - */ - boolean featureIsAtPosition = sequenceFeature.begin <= pos - && sequenceFeature.end >= pos; - if (sequenceFeature.isContactFeature()) - { - featureIsAtPosition = sequenceFeature.begin == pos - || sequenceFeature.end == pos; - } - if (featureIsAtPosition) - { - return getColour(sequenceFeature); ++ Color col = getColour(sequenceFeature); ++ if (col != null) ++ { ++ return col; ++ } } } } diff --cc src/jalview/schemes/FeatureColour.java index dbe4901,dbe4901..ed3e02d --- a/src/jalview/schemes/FeatureColour.java +++ b/src/jalview/schemes/FeatureColour.java @@@ -551,12 -551,12 +551,23 @@@ public class FeatureColour implements F return getColour(); } -- // todo should we check for above/below threshold here? ++ /* ++ * graduated colour case, optionally with threshold ++ * (treating Float.NaN as within visible range here) ++ */ ++ float scr = feature.getScore(); ++ if (isAboveThreshold() && scr <= threshold) ++ { ++ return null; ++ } ++ if (isBelowThreshold() && scr >= threshold) ++ { ++ return null; ++ } if (range == 0.0) { return getMaxColour(); } -- float scr = feature.getScore(); if (Float.isNaN(scr)) { return getMinColour(); @@@ -602,44 -602,44 +613,6 @@@ return (isHighToLow) ? (base + range) : base; } -- /** -- * Answers true if the feature has a simple colour, or is coloured by label, -- * or has a graduated colour and the score of this feature instance is within -- * the range to render (if any), i.e. does not lie below or above any -- * threshold set. -- * -- * @param feature -- * @return -- */ -- @Override -- public boolean isColored(SequenceFeature feature) -- { -- if (isColourByLabel() || !isGraduatedColour()) -- { -- return true; -- } -- -- float val = feature.getScore(); -- if (Float.isNaN(val)) -- { -- return true; -- } -- if (Float.isNaN(this.threshold)) -- { -- return true; -- } -- -- if (isAboveThreshold() && val <= threshold) -- { -- return false; -- } -- if (isBelowThreshold() && val >= threshold) -- { -- return false; -- } -- return true; -- } -- @Override public boolean isSimpleColour() { diff --cc src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java index de1ee5e,40f38b6..1d09dca --- a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java +++ b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java @@@ -559,7 -567,7 +559,8 @@@ public abstract class FeatureRendererMo * Returns the configured colour for a particular feature instance. This * includes calculation of 'colour by label', or of a graduated score colour, * if applicable. It does not take into account feature visibility or colour -- * transparency. ++ * transparency. Returns null for a score feature whose score value lies ++ * outside any colour threshold. * * @param feature * @return diff --cc test/jalview/schemes/FeatureColourTest.java index 1beca80,c16d541..03f7efa --- a/test/jalview/schemes/FeatureColourTest.java +++ b/test/jalview/schemes/FeatureColourTest.java @@@ -22,6 -22,6 +22,7 @@@ package jalview.schemes import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertFalse; ++import static org.testng.AssertJUnit.assertNull; import static org.testng.AssertJUnit.assertTrue; import static org.testng.AssertJUnit.fail; @@@ -84,62 -84,56 +85,6 @@@ public class FeatureColourTes } @Test(groups = { "Functional" }) -- public void testIsColored_simpleColour() -- { -- FeatureColour fc = new FeatureColour(Color.RED); - assertTrue(fc - .isColored(new SequenceFeature("Cath", "", 1, 2, 0f, null))); - } - - @Test(groups = { "Functional" }) - public void testIsColored_colourByLabel() - { - FeatureColour fc = new FeatureColour(); - fc.setColourByLabel(true); - assertTrue(fc - .isColored(new SequenceFeature("Cath", "", 1, 2, 0f, null))); - } - - @Test(groups = { "Functional" }) - public void testIsColored_aboveThreshold() - { - // graduated colour range from score 20 to 100 - FeatureColour fc = new FeatureColour(Color.WHITE, Color.BLACK, 20f, - 100f); - - // score 0 is adjusted to bottom of range - SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 0f, - null); - assertTrue(fc.isColored(sf)); - assertEquals(Color.WHITE, fc.getColor(sf)); - - // score 120 is adjusted to top of range - sf = new SequenceFeature(sf, sf.getBegin(), sf.getEnd(), - sf.getFeatureGroup(), 120f); - assertEquals(Color.BLACK, fc.getColor(sf)); - - // value below threshold is still rendered - // setting threshold has no effect yet... - fc.setThreshold(60f); - sf = new SequenceFeature(sf, sf.getBegin(), sf.getEnd(), - sf.getFeatureGroup(), 36f); - assertTrue(fc.isColored(sf)); - assertEquals(new Color(204, 204, 204), fc.getColor(sf)); - - // now apply threshold: - fc.setAboveThreshold(true); - assertFalse(fc.isColored(sf)); - // colour is still returned though ?!? - assertEquals(new Color(204, 204, 204), fc.getColor(sf)); - - sf = new SequenceFeature(sf, sf.getBegin(), sf.getEnd(), - sf.getFeatureGroup(), 84f); - // above threshold now - assertTrue(fc.isColored(sf)); - assertEquals(new Color(51, 51, 51), fc.getColor(sf)); - } - - @Test(groups = { "Functional" }) - assertTrue(fc.isColored(new SequenceFeature())); - } - - @Test(groups = { "Functional" }) - public void testIsColored_colourByLabel() - { - FeatureColour fc = new FeatureColour(); - fc.setColourByLabel(true); - assertTrue(fc.isColored(new SequenceFeature())); - } - - @Test(groups = { "Functional" }) - public void testIsColored_aboveThreshold() - { - // graduated colour range from score 20 to 100 - FeatureColour fc = new FeatureColour(Color.WHITE, Color.BLACK, 20f, - 100f); - - // score 0 is adjusted to bottom of range - SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 0f, - null); - assertTrue(fc.isColored(sf)); - assertEquals(Color.WHITE, fc.getColor(sf)); - - // score 120 is adjusted to top of range - sf.setScore(120f); - assertEquals(Color.BLACK, fc.getColor(sf)); - - // value below threshold is still rendered - // setting threshold has no effect yet... - fc.setThreshold(60f); - sf.setScore(36f); - assertTrue(fc.isColored(sf)); - assertEquals(new Color(204, 204, 204), fc.getColor(sf)); - - // now apply threshold: - fc.setAboveThreshold(true); - assertFalse(fc.isColored(sf)); - // colour is still returned though ?!? - assertEquals(new Color(204, 204, 204), fc.getColor(sf)); - - sf.setScore(84); // above threshold now - assertTrue(fc.isColored(sf)); - assertEquals(new Color(51, 51, 51), fc.getColor(sf)); - } - - @Test(groups = { "Functional" }) public void testGetColor_simpleColour() { FeatureColour fc = new FeatureColour(Color.RED); @@@ -176,7 -169,7 +121,7 @@@ } @Test(groups = { "Functional" }) -- public void testGetColor_belowThreshold() ++ public void testGetColor_aboveBelowThreshold() { // gradient from [50, 150] from WHITE(255, 255, 255) to BLACK(0, 0, 0) FeatureColour fc = new FeatureColour(Color.WHITE, Color.BLACK, 50f, @@@ -184,12 -177,12 +129,16 @@@ SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 70f, null); fc.setThreshold(100f); // ignore for now assertEquals(new Color(204, 204, 204), fc.getColor(sf)); fc.setAboveThreshold(true); // feature lies below threshold -- assertFalse(fc.isColored(sf)); -- assertEquals(new Color(204, 204, 204), fc.getColor(sf)); ++ assertNull(fc.getColor(sf)); ++ ++ fc.setBelowThreshold(true); ++ fc.setThreshold(70f); ++ assertNull(fc.getColor(sf)); // feature score == threshold - hidden ++ fc.setThreshold(69f); ++ assertNull(fc.getColor(sf)); // feature score > threshold - hidden } /**