X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fschemes%2FFeatureColour.java;h=f1bade151686ca674cfd23fae878ea45e64e9270;hb=a7169b1c72607f3c9357195b4999869650a2a891;hp=213868be1b85515b4411d41530b5dca1b6abb9e2;hpb=bf0d052fef43e9809b7170dbfd372b3ea116391b;p=jalview.git
diff --git a/src/jalview/schemes/FeatureColour.java b/src/jalview/schemes/FeatureColour.java
index 213868b..f1bade1 100644
--- a/src/jalview/schemes/FeatureColour.java
+++ b/src/jalview/schemes/FeatureColour.java
@@ -1,17 +1,88 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see .
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
package jalview.schemes;
+import java.util.Locale;
+
import jalview.api.FeatureColourI;
import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.features.FeatureMatcher;
+import jalview.util.ColorUtils;
import jalview.util.Format;
+import jalview.util.MessageManager;
import java.awt.Color;
import java.util.StringTokenizer;
/**
- * A class that wraps either a simple colour or a graduated colour
+ * A class that represents a colour scheme for a feature type. Options supported
+ * are currently
+ *
+ * - a simple colour e.g. Red
+ * - colour by label - a colour is generated from the feature description
+ * - graduated colour by feature score
+ *
+ * - minimum and maximum score range must be provided
+ * - minimum and maximum value colours should be specified
+ * - a colour for 'no value' may optionally be provided
+ * - colours for intermediate scores are interpolated RGB values
+ * - there is an optional threshold above/below which to colour values
+ * - the range may be the full value range, or may be limited by the threshold
+ * value
+ *
+ * - colour by (text) value of a named attribute
+ * - graduated colour by (numeric) value of a named attribute
+ *
*/
public class FeatureColour implements FeatureColourI
{
+ private static final String I18N_LABEL = MessageManager
+ .getString("label.label");
+
+ private static final String I18N_SCORE = MessageManager
+ .getString("label.score");
+
+ private static final String ABSOLUTE = "abso";
+
+ private static final String ABOVE = "above";
+
+ private static final String BELOW = "below";
+
+ /*
+ * constants used to read or write a Jalview Features file
+ */
+ private static final String LABEL = "label";
+
+ private static final String SCORE = "score";
+
+ private static final String ATTRIBUTE = "attribute";
+
+ private static final String NO_VALUE_MIN = "noValueMin";
+
+ private static final String NO_VALUE_MAX = "noValueMax";
+
+ private static final String NO_VALUE_NONE = "noValueNone";
+
+ static final Color DEFAULT_NO_COLOUR = null;
+
private static final String BAR = "|";
final private Color colour;
@@ -20,10 +91,30 @@ public class FeatureColour implements FeatureColourI
final private Color maxColour;
+ /*
+ * colour to use for colour by attribute when the
+ * attribute value is absent
+ */
+ final private Color noColour;
+
+ /*
+ * if true, then colour has a gradient based on a numerical
+ * range (either feature score, or an attribute value)
+ */
private boolean graduatedColour;
+ /*
+ * if true, colour values are generated from a text string,
+ * either feature description, or an attribute value
+ */
private boolean colourByLabel;
+ /*
+ * if not null, the value of [attribute, [sub-attribute] ...]
+ * is used for colourByLabel or graduatedColour
+ */
+ private String[] attributeName;
+
private float threshold;
private float base;
@@ -34,8 +125,6 @@ public class FeatureColour implements FeatureColourI
private boolean aboveThreshold;
- private boolean thresholdIsMinOrMax;
-
private boolean isHighToLow;
private boolean autoScaled;
@@ -54,16 +143,29 @@ public class FeatureColour implements FeatureColourI
/**
* Parses a Jalview features file format colour descriptor
- * [label|][mincolour|maxcolour
- * |[absolute|]minvalue|maxvalue|thresholdtype|thresholdvalue] Examples:
+ *
+ *
+ * [label|score|[attribute|attributeName]|][mincolour|maxcolour|
+ * [absolute|]minvalue|maxvalue|[noValueOption|]thresholdtype|thresholdvalue]
+ *
+ * 'Score' is optional (default) for a graduated colour. An attribute with
+ * sub-attribute should be written as (for example) CSQ:Consequence.
+ * noValueOption is one of noValueMin, noValueMax, noValueNone
+ * with default noValueMin.
+ *
+ * Examples:
*
* - red
* - a28bbb
* - 25,125,213
* - label
+ * - attribute|CSQ:PolyPhen
* - label|||0.0|0.0|above|12.5
* - label|||0.0|0.0|below|12.5
* - red|green|12.0|26.0|none
+ * - score|red|green|12.0|26.0|none
+ * - attribute|AF|red|green|12.0|26.0|none
+ * - attribute|AF|red|green|noValueNone|12.0|26.0|none
* - a28bbb|3eb555|12.0|26.0|above|12.5
* - a28bbb|3eb555|abso|12.0|26.0|below|12.5
*
@@ -73,72 +175,139 @@ public class FeatureColour implements FeatureColourI
* @throws IllegalArgumentException
* if not parseable
*/
- public static FeatureColour parseJalviewFeatureColour(String descriptor)
+ public static FeatureColourI parseJalviewFeatureColour(String descriptor)
{
- StringTokenizer gcol = new StringTokenizer(descriptor, "|", true);
+ StringTokenizer gcol = new StringTokenizer(descriptor, BAR, true);
float min = Float.MIN_VALUE;
float max = Float.MAX_VALUE;
- boolean labelColour = false;
+ boolean byLabel = false;
+ boolean byAttribute = false;
+ String attName = null;
+ String mincol = null;
+ String maxcol = null;
- String mincol = gcol.nextToken();
- if (mincol == "|")
+ /*
+ * first token should be 'label', or 'score', or an
+ * attribute name, or simple colour, or minimum colour
+ */
+ String nextToken = gcol.nextToken();
+ if (nextToken == BAR)
{
throw new IllegalArgumentException(
"Expected either 'label' or a colour specification in the line: "
+ descriptor);
}
- String maxcol = null;
- if (mincol.toLowerCase().indexOf("label") == 0)
+ if (nextToken.toLowerCase(Locale.ROOT).startsWith(LABEL))
+ {
+ byLabel = true;
+ // get the token after the next delimiter:
+ mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
+ mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
+ }
+ else if (nextToken.toLowerCase(Locale.ROOT).startsWith(SCORE))
+ {
+ mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
+ mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
+ }
+ else if (nextToken.toLowerCase(Locale.ROOT).startsWith(ATTRIBUTE))
{
- labelColour = true;
+ byAttribute = true;
+ attName = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
+ attName = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
- // skip '|'
mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
}
+ else
+ {
+ mincol = nextToken;
+ }
- if (!labelColour && !gcol.hasMoreTokens())
+ /*
+ * if only one token, it can validly be label, attributeName,
+ * or a plain colour value
+ */
+ if (!gcol.hasMoreTokens())
{
- /*
- * only a simple colour specification - parse it
- */
- Color colour = UserColourScheme.getColourFromString(descriptor);
+ if (byLabel || byAttribute)
+ {
+ FeatureColourI fc = new FeatureColour();
+ fc.setColourByLabel(true);
+ if (byAttribute)
+ {
+ fc.setAttributeName(
+ FeatureMatcher.fromAttributeDisplayName(attName));
+ }
+ return fc;
+ }
+
+ Color colour = ColorUtils.parseColourString(descriptor);
if (colour == null)
{
- throw new IllegalArgumentException("Invalid colour descriptor: "
- + descriptor);
+ throw new IllegalArgumentException(
+ "Invalid colour descriptor: " + descriptor);
}
return new FeatureColour(colour);
}
/*
+ * continue parsing for min/max/no colour (if graduated)
+ * and for threshold (colour by text or graduated)
+ */
+
+ /*
* autoScaled == true: colours range over actual score range
* autoScaled == false ('abso'): colours range over min/max range
*/
boolean autoScaled = true;
String tok = null, minval, maxval;
+ String noValueColour = NO_VALUE_MIN;
+
if (mincol != null)
{
// at least four more tokens
- if (mincol.equals("|"))
+ if (mincol.equals(BAR))
{
- mincol = "";
+ mincol = null;
}
else
{
gcol.nextToken(); // skip next '|'
}
maxcol = gcol.nextToken();
- if (maxcol.equals("|"))
+ if (maxcol.equals(BAR))
{
- maxcol = "";
+ maxcol = null;
}
else
{
gcol.nextToken(); // skip next '|'
}
tok = gcol.nextToken();
+
+ /*
+ * check for specifier for colour for no attribute value
+ * (new in 2.11, defaults to minColour if not specified)
+ */
+ if (tok.equalsIgnoreCase(NO_VALUE_MIN))
+ {
+ tok = gcol.nextToken();
+ tok = gcol.nextToken();
+ }
+ else if (tok.equalsIgnoreCase(NO_VALUE_MAX))
+ {
+ noValueColour = NO_VALUE_MAX;
+ tok = gcol.nextToken();
+ tok = gcol.nextToken();
+ }
+ else if (tok.equalsIgnoreCase(NO_VALUE_NONE))
+ {
+ noValueColour = NO_VALUE_NONE;
+ tok = gcol.nextToken();
+ tok = gcol.nextToken();
+ }
+
gcol.nextToken(); // skip next '|'
- if (tok.toLowerCase().startsWith("abso"))
+ if (tok.toLowerCase(Locale.ROOT).startsWith(ABSOLUTE))
{
minval = gcol.nextToken();
gcol.nextToken(); // skip next '|'
@@ -157,19 +326,19 @@ public class FeatureColour implements FeatureColourI
{
if (minval.length() > 0)
{
- min = new Float(minval).floatValue();
+ min = Float.valueOf(minval).floatValue();
}
} catch (Exception e)
{
throw new IllegalArgumentException(
- "Couldn't parse the minimum value for graduated colour ("
- + descriptor + ")");
+ "Couldn't parse the minimum value for graduated colour ('"
+ + minval + "')");
}
try
{
if (maxval.length() > 0)
{
- max = new Float(maxval).floatValue();
+ max = Float.valueOf(maxval).floatValue();
}
} catch (Exception e)
{
@@ -180,43 +349,54 @@ public class FeatureColour implements FeatureColourI
}
else
{
- // add in some dummy min/max colours for the label-only
- // colourscheme.
- mincol = "FFFFFF";
- maxcol = "000000";
+ /*
+ * dummy min/max colours for colour by text
+ * (label or attribute value)
+ */
+ mincol = "white";
+ maxcol = "black";
+ byLabel = true;
}
/*
- * construct the FeatureColour
+ * construct the FeatureColour!
*/
FeatureColour featureColour;
try
{
- featureColour = new FeatureColour(
- new UserColourScheme(mincol).findColour('A'),
- new UserColourScheme(maxcol).findColour('A'), min, max);
- featureColour.setColourByLabel(labelColour);
+ Color minColour = ColorUtils.parseColourString(mincol);
+ Color maxColour = ColorUtils.parseColourString(maxcol);
+ Color noColour = noValueColour.equals(NO_VALUE_MAX) ? maxColour
+ : (noValueColour.equals(NO_VALUE_NONE) ? null : minColour);
+ featureColour = new FeatureColour(maxColour, minColour, maxColour,
+ noColour, min, max);
+ featureColour.setColourByLabel(minColour == null);
featureColour.setAutoScaled(autoScaled);
+ if (byAttribute)
+ {
+ featureColour.setAttributeName(
+ FeatureMatcher.fromAttributeDisplayName(attName));
+ }
// add in any additional parameters
String ttype = null, tval = null;
if (gcol.hasMoreTokens())
{
// threshold type and possibly a threshold value
ttype = gcol.nextToken();
- if (ttype.toLowerCase().startsWith("below"))
+ if (ttype.toLowerCase(Locale.ROOT).startsWith(BELOW))
{
featureColour.setBelowThreshold(true);
}
- else if (ttype.toLowerCase().startsWith("above"))
+ else if (ttype.toLowerCase(Locale.ROOT).startsWith(ABOVE))
{
featureColour.setAboveThreshold(true);
}
else
{
- if (!ttype.toLowerCase().startsWith("no"))
+ if (!ttype.toLowerCase(Locale.ROOT).startsWith("no"))
{
- System.err.println("Ignoring unrecognised threshold type : "
- + ttype);
+ System.err.println(
+ "Ignoring unrecognised threshold type : " + ttype);
}
}
}
@@ -226,7 +406,7 @@ public class FeatureColour implements FeatureColourI
{
gcol.nextToken();
tval = gcol.nextToken();
- featureColour.setThreshold(new Float(tval).floatValue());
+ featureColour.setThreshold(Float.valueOf(tval).floatValue());
} catch (Exception e)
{
System.err.println("Couldn't parse threshold value as a float: ("
@@ -235,11 +415,11 @@ public class FeatureColour implements FeatureColourI
}
if (gcol.hasMoreTokens())
{
- System.err
- .println("Ignoring additional tokens in parameters in graduated colour specification\n");
+ System.err.println(
+ "Ignoring additional tokens in parameters in graduated colour specification\n");
while (gcol.hasMoreTokens())
{
- System.err.println("|" + gcol.nextToken());
+ System.err.println(BAR + gcol.nextToken());
}
System.err.println("\n");
}
@@ -259,55 +439,25 @@ public class FeatureColour implements FeatureColourI
}
/**
- * Constructor given a simple colour
+ * Constructor given a simple colour. This also 'primes' a graduated colour
+ * range, where the maximum colour is the given simple colour, and the minimum
+ * colour a paler shade of it. This is for convenience when switching from a
+ * simple colour to a graduated colour scheme.
*
* @param c
*/
public FeatureColour(Color c)
{
- minColour = Color.WHITE;
- maxColour = Color.BLACK;
- minRed = 0f;
- minGreen = 0f;
- minBlue = 0f;
- deltaRed = 0f;
- deltaGreen = 0f;
- deltaBlue = 0f;
- colour = c;
- }
+ /*
+ * set max colour to the simple colour, min colour to a paler shade of it
+ */
+ this(c, c == null ? Color.white : ColorUtils.bleachColour(c, 0.9f),
+ c == null ? Color.black : c, DEFAULT_NO_COLOUR, 0, 0);
- /**
- * Constructor given a colour range and a score range
- *
- * @param low
- * @param high
- * @param min
- * @param max
- */
- public FeatureColour(Color low, Color high, float min, float max)
- {
- graduatedColour = true;
- colour = null;
- minColour = low;
- maxColour = high;
- threshold = Float.NaN;
- isHighToLow = min >= max;
- minRed = low.getRed() / 255f;
- minGreen = low.getGreen() / 255f;
- minBlue = low.getBlue() / 255f;
- deltaRed = (high.getRed() / 255f) - minRed;
- deltaGreen = (high.getGreen() / 255f) - minGreen;
- deltaBlue = (high.getBlue() / 255f) - minBlue;
- if (isHighToLow)
- {
- base = max;
- range = min - max;
- }
- else
- {
- base = min;
- range = max - min;
- }
+ /*
+ * but enforce simple colour for now!
+ */
+ setGraduatedColour(false);
}
/**
@@ -317,9 +467,11 @@ public class FeatureColour implements FeatureColourI
*/
public FeatureColour(FeatureColour fc)
{
+ graduatedColour = fc.graduatedColour;
colour = fc.colour;
minColour = fc.minColour;
maxColour = fc.maxColour;
+ noColour = fc.noColour;
minRed = fc.minRed;
minGreen = fc.minGreen;
minBlue = fc.minBlue;
@@ -329,24 +481,64 @@ public class FeatureColour implements FeatureColourI
base = fc.base;
range = fc.range;
isHighToLow = fc.isHighToLow;
+ attributeName = fc.attributeName;
setAboveThreshold(fc.isAboveThreshold());
setBelowThreshold(fc.isBelowThreshold());
setThreshold(fc.getThreshold());
setAutoScaled(fc.isAutoScaled());
setColourByLabel(fc.isColourByLabel());
}
-
+
/**
- * Copy constructor with new min/max ranges
- * @param fc
+ * Constructor that sets both simple and graduated colour values. This allows
+ * alternative colour schemes to be 'preserved' while switching between them
+ * to explore their effects on the visualisation.
+ *
+ * This sets the colour scheme to 'graduated' by default. Override this if
+ * wanted by calling setGraduatedColour(false)
for a simple
+ * colour, or setColourByLabel(true)
for colour by label.
+ *
+ * @param myColour
+ * @param low
+ * @param high
+ * @param noValueColour
* @param min
* @param max
*/
- public FeatureColour(FeatureColour fc, float min, float max)
+ public FeatureColour(Color myColour, Color low, Color high,
+ Color noValueColour, float min, float max)
{
- this(fc);
- graduatedColour = true;
- updateBounds(min, max);
+ if (low == null)
+ {
+ low = Color.white;
+ }
+ if (high == null)
+ {
+ high = Color.black;
+ }
+ colour = myColour;
+ minColour = low;
+ maxColour = high;
+ setGraduatedColour(true);
+ noColour = noValueColour;
+ threshold = Float.NaN;
+ isHighToLow = min >= max;
+ minRed = low.getRed() / 255f;
+ minGreen = low.getGreen() / 255f;
+ minBlue = low.getBlue() / 255f;
+ deltaRed = (high.getRed() / 255f) - minRed;
+ deltaGreen = (high.getGreen() / 255f) - minGreen;
+ deltaBlue = (high.getBlue() / 255f) - minBlue;
+ if (isHighToLow)
+ {
+ base = max;
+ range = min - max;
+ }
+ else
+ {
+ base = min;
+ range = max - min;
+ }
}
@Override
@@ -359,7 +551,7 @@ public class FeatureColour implements FeatureColourI
* Sets the 'graduated colour' flag. If true, also sets 'colour by label' to
* false.
*/
- void setGraduatedColour(boolean b)
+ public void setGraduatedColour(boolean b)
{
graduatedColour = b;
if (b)
@@ -387,6 +579,12 @@ public class FeatureColour implements FeatureColourI
}
@Override
+ public Color getNoColour()
+ {
+ return noColour;
+ }
+
+ @Override
public boolean isColourByLabel()
{
return colourByLabel;
@@ -405,6 +603,7 @@ public class FeatureColour implements FeatureColourI
setGraduatedColour(false);
}
}
+
@Override
public boolean isBelowThreshold()
{
@@ -438,18 +637,6 @@ public class FeatureColour implements FeatureColourI
}
@Override
- public boolean isThresholdMinMax()
- {
- return thresholdIsMinOrMax;
- }
-
- @Override
- public void setThresholdMinMax(boolean b)
- {
- thresholdIsMinOrMax = b;
- }
-
- @Override
public float getThreshold()
{
return threshold;
@@ -474,10 +661,7 @@ public class FeatureColour implements FeatureColourI
}
/**
- * Updates the base and range appropriately for the given minmax range
- *
- * @param min
- * @param max
+ * {@inheritDoc}
*/
@Override
public void updateBounds(float min, float max)
@@ -498,9 +682,12 @@ public class FeatureColour implements FeatureColourI
/**
* Returns the colour for the given instance of the feature. This may be a
- * simple colour, a colour generated from the feature description (if
- * isColourByLabel()), or a colour derived from the feature score (if
- * isGraduatedColour()).
+ * simple colour, a colour generated from the feature description or other
+ * attribute (if isColourByLabel()), or a colour derived from the feature
+ * score or other attribute (if isGraduatedColour()).
+ *
+ * Answers null if feature score (or attribute) value lies outside a
+ * configured threshold.
*
* @param feature
* @return
@@ -510,8 +697,10 @@ public class FeatureColour implements FeatureColourI
{
if (isColourByLabel())
{
- return UserColourScheme
- .createColourFromName(feature.getDescription());
+ String label = attributeName == null ? feature.getDescription()
+ : feature.getValueAsString(attributeName);
+ return label == null ? noColour
+ : ColorUtils.createColourFromName(label);
}
if (!isGraduatedColour())
@@ -519,15 +708,40 @@ public class FeatureColour implements FeatureColourI
return getColour();
}
- // todo should we check for above/below threshold here?
- if (range == 0.0)
+ /*
+ * graduated colour case, optionally with threshold
+ * may be based on feature score on an attribute value
+ * Float.NaN, or no value, is assigned the 'no value' colour
+ */
+ float scr = feature.getScore();
+ if (attributeName != null)
{
- return getMaxColour();
+ try
+ {
+ String attVal = feature.getValueAsString(attributeName);
+ scr = Float.valueOf(attVal);
+ } catch (Throwable e)
+ {
+ scr = Float.NaN;
+ }
}
- float scr = feature.getScore();
if (Float.isNaN(scr))
{
- return getMinColour();
+ return noColour;
+ }
+
+ if (isAboveThreshold() && scr <= threshold)
+ {
+ return null;
+ }
+
+ if (isBelowThreshold() && scr >= threshold)
+ {
+ return null;
+ }
+ if (range == 0.0)
+ {
+ return getMaxColour();
}
float scl = (scr - base) / range;
if (isHighToLow)
@@ -542,7 +756,8 @@ public class FeatureColour implements FeatureColourI
{
scl = 1f;
}
- return new Color(minRed + scl * deltaRed, minGreen + scl * deltaGreen, minBlue + scl * deltaBlue);
+ return new Color(minRed + scl * deltaRed, minGreen + scl * deltaGreen,
+ minBlue + scl * deltaBlue);
}
/**
@@ -569,44 +784,6 @@ public class FeatureColour implements FeatureColourI
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()
{
@@ -630,21 +807,54 @@ public class FeatureColour implements FeatureColourI
else
{
StringBuilder sb = new StringBuilder(32);
- if (isColourByLabel())
+ if (isColourByAttribute())
{
- sb.append("label");
- if (hasThreshold())
- {
- sb.append(BAR).append(BAR).append(BAR);
- }
+ sb.append(ATTRIBUTE).append(BAR);
+ sb.append(
+ FeatureMatcher.toAttributeDisplayName(getAttributeName()));
+ }
+ else if (isColourByLabel())
+ {
+ sb.append(LABEL);
+ }
+ else
+ {
+ sb.append(SCORE);
}
if (isGraduatedColour())
{
- sb.append(Format.getHexString(getMinColour())).append(BAR);
+ sb.append(BAR).append(Format.getHexString(getMinColour()))
+ .append(BAR);
sb.append(Format.getHexString(getMaxColour())).append(BAR);
+
+ /*
+ * 'no value' colour should be null, min or max colour;
+ * if none of these, coerce to minColour
+ */
+ String noValue = NO_VALUE_MIN;
+ if (maxColour.equals(noColour))
+ {
+ noValue = NO_VALUE_MAX;
+ }
+ if (noColour == null)
+ {
+ noValue = NO_VALUE_NONE;
+ }
+ sb.append(noValue).append(BAR);
if (!isAutoScaled())
{
- sb.append("abso").append(BAR);
+ sb.append(ABSOLUTE).append(BAR);
+ }
+ }
+ else
+ {
+ /*
+ * colour by text with score threshold: empty fields for
+ * minColour and maxColour (not used)
+ */
+ if (hasThreshold())
+ {
+ sb.append(BAR).append(BAR).append(BAR);
}
}
if (hasThreshold() || isGraduatedColour())
@@ -653,11 +863,11 @@ public class FeatureColour implements FeatureColourI
sb.append(getMax()).append(BAR);
if (isBelowThreshold())
{
- sb.append("below").append(BAR).append(getThreshold());
+ sb.append(BELOW).append(BAR).append(getThreshold());
}
else if (isAboveThreshold())
{
- sb.append("above").append(BAR).append(getThreshold());
+ sb.append(ABOVE).append(BAR).append(getThreshold());
}
else
{
@@ -669,4 +879,96 @@ public class FeatureColour implements FeatureColourI
return String.format("%s\t%s", featureType, colourString);
}
+ @Override
+ public boolean isColourByAttribute()
+ {
+ return attributeName != null;
+ }
+
+ @Override
+ public String[] getAttributeName()
+ {
+ return attributeName;
+ }
+
+ @Override
+ public void setAttributeName(String... name)
+ {
+ attributeName = name;
+ }
+
+ @Override
+ public boolean isOutwithThreshold(SequenceFeature feature)
+ {
+ if (!isGraduatedColour())
+ {
+ return false;
+ }
+ float scr = feature.getScore();
+ if (attributeName != null)
+ {
+ try
+ {
+ String attVal = feature.getValueAsString(attributeName);
+ scr = Float.valueOf(attVal);
+ } catch (Throwable e)
+ {
+ scr = Float.NaN;
+ }
+ }
+ if (Float.isNaN(scr))
+ {
+ return false;
+ }
+
+ return ((isAboveThreshold() && scr <= threshold)
+ || (isBelowThreshold() && scr >= threshold));
+ }
+
+ @Override
+ public String getDescription()
+ {
+ if (isSimpleColour())
+ {
+ return "r=" + colour.getRed() + ",g=" + colour.getGreen() + ",b="
+ + colour.getBlue();
+ }
+ StringBuilder tt = new StringBuilder();
+ String by = null;
+
+ if (getAttributeName() != null)
+ {
+ by = FeatureMatcher.toAttributeDisplayName(getAttributeName());
+ }
+ else if (isColourByLabel())
+ {
+ by = I18N_LABEL;
+ }
+ else
+ {
+ by = I18N_SCORE;
+ }
+ tt.append(MessageManager.formatMessage("action.by_title_param", by));
+
+ /*
+ * add threshold if any
+ */
+ if (isAboveThreshold() || isBelowThreshold())
+ {
+ tt.append(" (");
+ if (isColourByLabel())
+ {
+ /*
+ * Jalview features file supports the combination of
+ * colour by label or attribute text with score threshold
+ */
+ tt.append(I18N_SCORE).append(" ");
+ }
+ tt.append(isAboveThreshold() ? "> " : "< ");
+ tt.append(getThreshold()).append(")");
+ }
+
+ return tt.toString();
+ }
+
}