*/
public class FeatureColour implements FeatureColourI
{
- private static final String BAR = "|";
+ private static final float _255F = 255f;
- final private Color colour;
+ private static final String ABOVE = "above";
- final private Color minColour;
+ private static final String BELOW = "below";
- final private Color maxColour;
+ private static final String ABSO = "abso";
+
+ private static final String LABEL = "label";
+
+ private static final String PIPE = "|";
+
+ private final Color colour;
+
+ private final Color minColour;
+
+ private final Color maxColour;
private boolean graduatedColour;
private boolean autoScaled;
- final private float minRed;
+ private final float minRed;
+
+ private final float minGreen;
+
+ private final float minBlue;
- final private float minGreen;
+ private final float deltaRed;
- final private float minBlue;
+ private final float deltaGreen;
+
+ private final float deltaBlue;
+
+ /**
+ * Default constructor
+ */
+ public FeatureColour()
+ {
+ this((Color) null);
+ }
- final private float deltaRed;
+ /**
+ * Constructor given a simple colour
+ *
+ * @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;
+ }
+
+ /**
+ * 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 == null ? Color.WHITE : low;
+ maxColour = high == null ? Color.BLACK : high;
+ threshold = Float.NaN;
+ isHighToLow = min >= max;
+ minRed = minColour.getRed() / _255F;
+ minGreen = minColour.getGreen() / _255F;
+ minBlue = minColour.getBlue() / _255F;
+ deltaRed = (maxColour.getRed() / _255F) - minRed;
+ deltaGreen = (maxColour.getGreen() / _255F) - minGreen;
+ deltaBlue = (maxColour.getBlue() / _255F) - minBlue;
+ if (isHighToLow)
+ {
+ base = max;
+ range = min - max;
+ }
+ else
+ {
+ base = min;
+ range = max - min;
+ }
+ }
- final private float deltaGreen;
+ /**
+ * Copy constructor
+ *
+ * @param fc
+ */
+ public FeatureColour(FeatureColour fc)
+ {
+ graduatedColour = fc.graduatedColour;
+ colour = fc.colour;
+ minColour = fc.minColour;
+ maxColour = fc.maxColour;
+ minRed = fc.minRed;
+ minGreen = fc.minGreen;
+ minBlue = fc.minBlue;
+ deltaRed = fc.deltaRed;
+ deltaGreen = fc.deltaGreen;
+ deltaBlue = fc.deltaBlue;
+ base = fc.base;
+ range = fc.range;
+ isHighToLow = fc.isHighToLow;
+ setAboveThreshold(fc.isAboveThreshold());
+ setBelowThreshold(fc.isBelowThreshold());
+ setThreshold(fc.getThreshold());
+ setAutoScaled(fc.isAutoScaled());
+ setColourByLabel(fc.isColourByLabel());
+ }
- final private float deltaBlue;
+ /**
+ * Copy constructor with new min/max ranges
+ *
+ * @param fc
+ * @param min
+ * @param max
+ */
+ public FeatureColour(FeatureColour fc, float min, float max)
+ {
+ this(fc);
+ graduatedColour = true;
+ updateBounds(min, max);
+ }
/**
* Parses a Jalview features file format colour descriptor
*/
public static FeatureColour parseJalviewFeatureColour(String descriptor)
{
- StringTokenizer gcol = new StringTokenizer(descriptor, "|", true);
+ StringTokenizer gcol = new StringTokenizer(descriptor, PIPE, true);
float min = Float.MIN_VALUE;
float max = Float.MAX_VALUE;
boolean labelColour = false;
String mincol = gcol.nextToken();
- if (mincol == "|")
+ if (mincol == PIPE)
{
throw new IllegalArgumentException(
"Expected either 'label' or a colour specification in the line: "
+ descriptor);
}
String maxcol = null;
- if (mincol.toLowerCase().indexOf("label") == 0)
+ if (mincol.toLowerCase().indexOf(LABEL) == 0)
{
labelColour = true;
mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
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);
}
* autoScaled == false ('abso'): colours range over min/max range
*/
boolean autoScaled = true;
- String tok = null, minval, maxval;
+ String tok = null;
+ String minval;
+ String maxval;
if (mincol != null)
{
// at least four more tokens
- if (mincol.equals("|"))
+ if (mincol.equals(PIPE))
{
mincol = "";
}
gcol.nextToken(); // skip next '|'
}
maxcol = gcol.nextToken();
- if (maxcol.equals("|"))
+ if (maxcol.equals(PIPE))
{
maxcol = "";
}
}
tok = gcol.nextToken();
gcol.nextToken(); // skip next '|'
- if (tok.toLowerCase().startsWith("abso"))
+ if (tok.toLowerCase().startsWith(ABSO))
{
minval = gcol.nextToken();
gcol.nextToken(); // skip next '|'
{
min = new Float(minval).floatValue();
}
- } catch (Exception e)
+ } catch (NumberFormatException e)
{
throw new IllegalArgumentException(
"Couldn't parse the minimum value for graduated colour ("
{
max = new Float(maxval).floatValue();
}
- } catch (Exception e)
+ } catch (NumberFormatException e)
{
throw new IllegalArgumentException(
"Couldn't parse the maximum value for graduated colour ("
featureColour.setColourByLabel(labelColour);
featureColour.setAutoScaled(autoScaled);
// add in any additional parameters
- String ttype = null, tval = null;
+ String ttype = null;
+ String tval = null;
if (gcol.hasMoreTokens())
{
// threshold type and possibly a threshold value
ttype = gcol.nextToken();
- if (ttype.toLowerCase().startsWith("below"))
+ if (ttype.toLowerCase().startsWith(BELOW))
{
featureColour.setBelowThreshold(true);
}
- else if (ttype.toLowerCase().startsWith("above"))
+ else if (ttype.toLowerCase().startsWith(ABOVE))
{
featureColour.setAboveThreshold(true);
}
{
if (!ttype.toLowerCase().startsWith("no"))
{
- System.err.println("Ignoring unrecognised threshold type : "
- + ttype);
+ System.err.println(
+ "Ignoring unrecognised threshold type : " + ttype);
}
}
}
gcol.nextToken();
tval = gcol.nextToken();
featureColour.setThreshold(new Float(tval).floatValue());
- } catch (Exception e)
+ } catch (NumberFormatException e)
{
System.err.println("Couldn't parse threshold value as a float: ("
+ tval + ")");
}
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(PIPE + gcol.nextToken());
}
System.err.println("\n");
}
}
}
- /**
- * Default constructor
- */
- public FeatureColour()
- {
- this((Color) null);
- }
-
- /**
- * Constructor given a simple colour
- *
- * @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;
- }
-
- /**
- * 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)
- {
- if (low == null)
- {
- low = Color.white;
- }
- if (high == null)
- {
- high = Color.black;
- }
- 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;
- }
- }
-
- /**
- * Copy constructor
- *
- * @param fc
- */
- public FeatureColour(FeatureColour fc)
- {
- graduatedColour = fc.graduatedColour;
- colour = fc.colour;
- minColour = fc.minColour;
- maxColour = fc.maxColour;
- minRed = fc.minRed;
- minGreen = fc.minGreen;
- minBlue = fc.minBlue;
- deltaRed = fc.deltaRed;
- deltaGreen = fc.deltaGreen;
- deltaBlue = fc.deltaBlue;
- base = fc.base;
- range = fc.range;
- isHighToLow = fc.isHighToLow;
- setAboveThreshold(fc.isAboveThreshold());
- setBelowThreshold(fc.isBelowThreshold());
- setThreshold(fc.getThreshold());
- setAutoScaled(fc.isAutoScaled());
- setColourByLabel(fc.isColourByLabel());
- }
-
- /**
- * Copy constructor with new min/max ranges
- *
- * @param fc
- * @param min
- * @param max
- */
- public FeatureColour(FeatureColour fc, float min, float max)
- {
- this(fc);
- graduatedColour = true;
- updateBounds(min, max);
- }
-
@Override
public boolean isGraduatedColour()
{
}
/**
- * 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()).
+ * {@inheritDoc}
*
* @param feature
* @return
*/
@Override
- public Color getColor(SequenceFeature feature)
+ public Color getColour(SequenceFeature feature)
{
- if (isColourByLabel())
- {
- return ColorUtils
- .createColourFromName(feature.getDescription());
- }
-
- if (!isGraduatedColour())
+ if (isSimpleColour())
{
return getColour();
}
/*
- * graduated colour case, optionally with threshold
- * Float.NaN is assigned minimum visible score colour
+ * return null if score is outwith any threshold
+ * (for graduated colour or colour by label)
*/
float scr = feature.getScore();
- if (Float.isNaN(scr))
- {
- return getMinColour();
- }
- if (isAboveThreshold() && scr <= threshold)
+ boolean isNan = Float.isNaN(scr);
+ if (!isNan)
{
- return null;
- }
- if (isBelowThreshold() && scr >= threshold)
- {
- return null;
+ boolean isAbove = isAboveThreshold() && scr <= threshold;
+ boolean isBelow = !isNan && isBelowThreshold() && scr >= threshold;
+ if (isAbove || isBelow)
+ {
+ return null;
+ }
}
- if (range == 0.0)
+
+ if (isColourByLabel())
{
- return getMaxColour();
+ return ColorUtils.createColourFromName(feature.getDescription());
}
- float scl = (scr - base) / range;
- if (isHighToLow)
+
+ Color result = null;
+
+ if (isNan)
{
- scl = -scl;
+ result = getMinColour();
}
- if (scl < 0f)
+ else if (range == 0.0)
{
- scl = 0f;
+ result = getMaxColour();
}
- if (scl > 1f)
+ else
{
- scl = 1f;
+ float scl = (scr - base) / range;
+ if (isHighToLow)
+ {
+ scl = -scl;
+ }
+ if (scl < 0f)
+ {
+ scl = 0f;
+ }
+ if (scl > 1f)
+ {
+ scl = 1f;
+ }
+ result = new Color(minRed + scl * deltaRed,
+ minGreen + scl * deltaGreen, minBlue + scl * deltaBlue);
}
- return new Color(minRed + scl * deltaRed, minGreen + scl * deltaGreen,
- minBlue + scl * deltaBlue);
+
+ return result;
}
/**
StringBuilder sb = new StringBuilder(32);
if (isColourByLabel())
{
- sb.append("label");
+ sb.append(LABEL);
if (hasThreshold())
{
- sb.append(BAR).append(BAR).append(BAR);
+ sb.append(PIPE).append(PIPE).append(PIPE);
}
}
if (isGraduatedColour())
{
- sb.append(Format.getHexString(getMinColour())).append(BAR);
- sb.append(Format.getHexString(getMaxColour())).append(BAR);
+ sb.append(Format.getHexString(getMinColour())).append(PIPE);
+ sb.append(Format.getHexString(getMaxColour())).append(PIPE);
if (!isAutoScaled())
{
- sb.append("abso").append(BAR);
+ sb.append(ABSO).append(PIPE);
}
}
if (hasThreshold() || isGraduatedColour())
{
- sb.append(getMin()).append(BAR);
- sb.append(getMax()).append(BAR);
+ sb.append(getMin()).append(PIPE);
+ sb.append(getMax()).append(PIPE);
if (isBelowThreshold())
{
- sb.append("below").append(BAR).append(getThreshold());
+ sb.append(BELOW).append(PIPE).append(getThreshold());
}
else if (isAboveThreshold())
{
- sb.append("above").append(BAR).append(getThreshold());
+ sb.append(ABOVE).append(PIPE).append(getThreshold());
}
else
{