--- /dev/null
+package jalview.schemes;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.AssertJUnit.fail;
+
+import jalview.datamodel.SequenceFeature;
+import jalview.util.Format;
+
+import java.awt.Color;
+
+import org.testng.annotations.Test;
+
+public class FeatureColourTest
+{
+ @Test(groups = { "Functional" })
+ public void testIsColored_simpleColour()
+ {
+ FeatureColour fc = new FeatureColour(Color.RED);
+ 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);
+ assertEquals(Color.RED, fc.getColor(new SequenceFeature()));
+ }
+
+ @Test(groups = { "Functional" })
+ public void testGetColor_colourByLabel()
+ {
+ FeatureColour fc = new FeatureColour();
+ fc.setColourByLabel(true);
+ SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 1f,
+ null);
+ Color expected = UserColourScheme.createColourFromName("desc");
+ assertEquals(expected, fc.getColor(sf));
+ }
+
+ @Test(groups = { "Functional" })
+ public void testGetColor_Graduated()
+ {
+ // graduated colour from score 0 to 100, gray(128, 128, 128) to red(255, 0, 0)
+ FeatureColour fc = new FeatureColour(Color.GRAY, Color.RED, 0f, 100f);
+ // feature score is 75 which is 3/4 of the way from GRAY to RED
+ SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 75f,
+ null);
+ // the colour gradient is computed in float values from 0-1 (where 1 == 255)
+ float red = 128 / 255f + 3 / 4f * (255 - 128) / 255f;
+ float green = 128 / 255f + 3 / 4f * (0 - 128) / 255f;
+ float blue = 128 / 255f + 3 / 4f * (0 - 128) / 255f;
+ Color expected = new Color(red, green, blue);
+ assertEquals(expected, fc.getColor(sf));
+ }
+
+ @Test(groups = { "Functional" })
+ public void testGetColor_belowThreshold()
+ {
+ // gradient from [50, 150] from WHITE(255, 255, 255) to BLACK(0, 0, 0)
+ FeatureColour fc = new FeatureColour(Color.WHITE, Color.BLACK, 50f,
+ 150f);
+ SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 70f,
+ null);
+ fc.setThreshold(100f); // ignore for now
+ assertTrue(fc.isColored(sf));
+ 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));
+ }
+
+ /**
+ * Test output of feature colours to Jalview features file format
+ */
+ @Test(groups = { "Functional" })
+ public void testToJalviewFormat()
+ {
+ /*
+ * plain colour - to RGB hex code
+ */
+ FeatureColour fc = new FeatureColour(Color.RED);
+ String redHex = Format.getHexString(Color.RED);
+ String hexColour = redHex;
+ assertEquals("domain\t" + hexColour, fc.toJalviewFormat("domain"));
+
+ /*
+ * colour by label (no threshold)
+ */
+ fc = new FeatureColour();
+ fc.setColourByLabel(true);
+ assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
+
+ /*
+ * colour by label (autoscaled) (an odd state you can reach by selecting
+ * 'above threshold', then deselecting 'threshold is min/max' then 'colour
+ * by label')
+ */
+ fc.setAutoScaled(true);
+ assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
+
+ /*
+ * colour by label (above threshold) (min/max values are output though not
+ * used by this scheme)
+ */
+ fc.setAutoScaled(false);
+ fc.setThreshold(12.5f);
+ fc.setAboveThreshold(true);
+ assertEquals("domain\tlabel|||0.0|0.0|above|12.5",
+ fc.toJalviewFormat("domain"));
+
+ /*
+ * colour by label (below threshold)
+ */
+ fc.setBelowThreshold(true);
+ assertEquals("domain\tlabel|||0.0|0.0|below|12.5",
+ fc.toJalviewFormat("domain"));
+
+ /*
+ * graduated colour, no threshold
+ */
+ fc = new FeatureColour(Color.GREEN, Color.RED, 12f, 25f);
+ String greenHex = Format.getHexString(Color.GREEN);
+ String expected = String.format("domain\t%s|%s|abso|12.0|25.0|none",
+ greenHex, redHex);
+ assertEquals(expected, fc.toJalviewFormat("domain"));
+
+ /*
+ * colour ranges over the actual score ranges (not min/max)
+ */
+ fc.setAutoScaled(true);
+ expected = String.format("domain\t%s|%s|12.0|25.0|none", greenHex,
+ redHex);
+ assertEquals(expected, fc.toJalviewFormat("domain"));
+
+ /*
+ * graduated colour below threshold
+ */
+ fc.setThreshold(12.5f);
+ fc.setBelowThreshold(true);
+ expected = String.format("domain\t%s|%s|12.0|25.0|below|12.5",
+ greenHex, redHex);
+ assertEquals(expected, fc.toJalviewFormat("domain"));
+
+ /*
+ * graduated colour above threshold
+ */
+ fc.setThreshold(12.5f);
+ fc.setAboveThreshold(true);
+ fc.setAutoScaled(false);
+ expected = String.format("domain\t%s|%s|abso|12.0|25.0|above|12.5",
+ greenHex, redHex);
+ assertEquals(expected, fc.toJalviewFormat("domain"));
+ }
+
+ /**
+ * Test parsing of feature colours from Jalview features file format
+ */
+ @Test(groups = { "Functional" })
+ public void testParseJalviewFeatureColour()
+ {
+ /*
+ * simple colour by name
+ */
+ FeatureColour fc = FeatureColour.parseJalviewFeatureColour("red");
+ assertTrue(fc.isSimpleColour());
+ assertEquals(Color.RED, fc.getColour());
+
+ /*
+ * simple colour by hex code
+ */
+ fc = FeatureColour.parseJalviewFeatureColour(Format
+ .getHexString(Color.RED));
+ assertTrue(fc.isSimpleColour());
+ assertEquals(Color.RED, fc.getColour());
+
+ /*
+ * simple colour by rgb triplet
+ */
+ fc = FeatureColour.parseJalviewFeatureColour("255,0,0");
+ assertTrue(fc.isSimpleColour());
+ assertEquals(Color.RED, fc.getColour());
+
+ /*
+ * malformed colour
+ */
+ try
+ {
+ fc = FeatureColour.parseJalviewFeatureColour("oops");
+ fail("expected exception");
+ } catch (IllegalArgumentException e)
+ {
+ assertEquals("Invalid colour descriptor: oops", e.getMessage());
+ }
+
+ /*
+ * colour by label (no threshold)
+ */
+ fc = FeatureColour.parseJalviewFeatureColour("label");
+ assertTrue(fc.isColourByLabel());
+ assertFalse(fc.hasThreshold());
+
+ /*
+ * colour by label (with threshold)
+ */
+ fc = FeatureColour
+ .parseJalviewFeatureColour("label|||0.0|0.0|above|12.0");
+ assertTrue(fc.isColourByLabel());
+ assertTrue(fc.isAboveThreshold());
+ assertEquals(12.0f, fc.getThreshold());
+
+ /*
+ * graduated colour (by name) (no threshold)
+ */
+ fc = FeatureColour.parseJalviewFeatureColour("red|green|10.0|20.0");
+ assertTrue(fc.isGraduatedColour());
+ assertFalse(fc.hasThreshold());
+ assertEquals(Color.RED, fc.getMinColour());
+ assertEquals(Color.GREEN, fc.getMaxColour());
+ assertEquals(10f, fc.getMin());
+ assertEquals(20f, fc.getMax());
+ assertTrue(fc.isAutoScaled());
+
+ /*
+ * graduated colour (by hex code) (above threshold)
+ */
+ String descriptor = String.format("%s|%s|10.0|20.0|above|15",
+ Format.getHexString(Color.RED),
+ Format.getHexString(Color.GREEN));
+ fc = FeatureColour.parseJalviewFeatureColour(descriptor);
+ assertTrue(fc.isGraduatedColour());
+ assertTrue(fc.hasThreshold());
+ assertTrue(fc.isAboveThreshold());
+ assertEquals(15f, fc.getThreshold());
+ assertEquals(Color.RED, fc.getMinColour());
+ assertEquals(Color.GREEN, fc.getMaxColour());
+ assertEquals(10f, fc.getMin());
+ assertEquals(20f, fc.getMax());
+ assertTrue(fc.isAutoScaled());
+
+ /*
+ * graduated colour (by RGB triplet) (below threshold), absolute scale
+ */
+ descriptor = String.format("255,0,0|0,255,0|abso|10.0|20.0|below|15");
+ fc = FeatureColour.parseJalviewFeatureColour(descriptor);
+ assertTrue(fc.isGraduatedColour());
+ assertFalse(fc.isAutoScaled());
+ assertTrue(fc.hasThreshold());
+ assertTrue(fc.isBelowThreshold());
+ assertEquals(15f, fc.getThreshold());
+ assertEquals(Color.RED, fc.getMinColour());
+ assertEquals(Color.GREEN, fc.getMaxColour());
+ assertEquals(10f, fc.getMin());
+ assertEquals(20f, fc.getMax());
+ }
+}