X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fschemes%2FFeatureColour.java;h=71a89b045936865a9d3f365cf785c7ffcc7c3c9e;hb=f8b17a9e7363b8a9e7cd12d61bc6d611c7c97d7d;hp=bdc70c94718da9e0b5bb0f861c7895c8b339d14e;hpb=579d3d1bccf00ce126ab3574758c6558b1bc3367;p=jalview.git
diff --git a/src/jalview/schemes/FeatureColour.java b/src/jalview/schemes/FeatureColour.java
index bdc70c9..71a89b0 100644
--- a/src/jalview/schemes/FeatureColour.java
+++ b/src/jalview/schemes/FeatureColour.java
@@ -1,17 +1,56 @@
+/*
+ * 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 jalview.api.FeatureColourI;
import jalview.datamodel.SequenceFeature;
+import jalview.util.ColorUtils;
import jalview.util.Format;
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
{
+ static final Color DEFAULT_NO_COLOUR = Color.LIGHT_GRAY;
+
private static final String BAR = "|";
final private Color colour;
@@ -20,10 +59,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;
@@ -101,11 +160,11 @@ public class FeatureColour implements FeatureColourI
/*
* only a simple colour specification - parse it
*/
- Color colour = UserColourScheme.getColourFromString(descriptor);
+ 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);
}
@@ -192,9 +251,9 @@ public class FeatureColour implements FeatureColourI
FeatureColour featureColour;
try
{
- featureColour = new FeatureColour(
- new UserColourScheme(mincol).findColour('A'),
- new UserColourScheme(maxcol).findColour('A'), min, max);
+ Color minColour = ColorUtils.parseColourString(mincol);
+ Color maxColour = ColorUtils.parseColourString(maxcol);
+ featureColour = new FeatureColour(minColour, maxColour, min, max);
featureColour.setColourByLabel(labelColour);
featureColour.setAutoScaled(autoScaled);
// add in any additional parameters
@@ -215,8 +274,8 @@ public class FeatureColour implements FeatureColourI
{
if (!ttype.toLowerCase().startsWith("no"))
{
- System.err.println("Ignoring unrecognised threshold type : "
- + ttype);
+ System.err.println(
+ "Ignoring unrecognised threshold type : " + ttype);
}
}
}
@@ -235,8 +294,8 @@ 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());
@@ -267,6 +326,7 @@ public class FeatureColour implements FeatureColourI
{
minColour = Color.WHITE;
maxColour = Color.BLACK;
+ noColour = DEFAULT_NO_COLOUR;
minRed = 0f;
minGreen = 0f;
minBlue = 0f;
@@ -277,7 +337,8 @@ public class FeatureColour implements FeatureColourI
}
/**
- * Constructor given a colour range and a score range
+ * Constructor given a colour range and a score range, defaulting 'no value
+ * colour' to be the same as minimum colour
*
* @param low
* @param high
@@ -286,28 +347,7 @@ public class FeatureColour implements FeatureColourI
*/
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;
- }
+ this(low, high, low, min, max);
}
/**
@@ -321,6 +361,7 @@ public class FeatureColour implements FeatureColourI
colour = fc.colour;
minColour = fc.minColour;
maxColour = fc.maxColour;
+ noColour = fc.noColour;
minRed = fc.minRed;
minGreen = fc.minGreen;
minBlue = fc.minBlue;
@@ -330,15 +371,17 @@ 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
* @param min
* @param max
@@ -346,10 +389,45 @@ public class FeatureColour implements FeatureColourI
public FeatureColour(FeatureColour fc, float min, float max)
{
this(fc);
- graduatedColour = true;
updateBounds(min, max);
}
+ public FeatureColour(Color low, Color high, Color noValueColour,
+ float min, float max)
+ {
+ if (low == null)
+ {
+ low = Color.white;
+ }
+ if (high == null)
+ {
+ high = Color.black;
+ }
+ graduatedColour = true;
+ colour = null;
+ minColour = low;
+ maxColour = high;
+ 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
public boolean isGraduatedColour()
{
@@ -388,6 +466,12 @@ public class FeatureColour implements FeatureColourI
}
@Override
+ public Color getNoColour()
+ {
+ return noColour;
+ }
+
+ @Override
public boolean isColourByLabel()
{
return colourByLabel;
@@ -406,6 +490,7 @@ public class FeatureColour implements FeatureColourI
setGraduatedColour(false);
}
}
+
@Override
public boolean isBelowThreshold()
{
@@ -475,10 +560,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)
@@ -511,8 +593,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())
@@ -520,15 +604,41 @@ 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 is assigned minimum visible score colour
+ * no such attribute 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)
@@ -543,7 +653,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);
}
/**
@@ -570,44 +681,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()
{
@@ -670,4 +743,22 @@ 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;
+ }
+
}