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
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
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<SequenceFeature> 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))
{
continue;
}
- for (int sfindex = 0; sfindex < sequenceFeatures.length; sfindex++)
+ List<SequenceFeature> 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;
++ }
}
}
}
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();
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()
{
* 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
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;
}
@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);
}
@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,
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
}
/**