Merge branch 'develop' into features/JAL-1956_featureStyles
[jalview.git] / test / jalview / schemes / FeatureColourTest.java
1 package jalview.schemes;
2
3 import static org.testng.AssertJUnit.assertEquals;
4 import static org.testng.AssertJUnit.assertFalse;
5 import static org.testng.AssertJUnit.assertTrue;
6 import static org.testng.AssertJUnit.fail;
7
8 import jalview.datamodel.SequenceFeature;
9 import jalview.util.Format;
10
11 import java.awt.Color;
12
13 import org.testng.annotations.Test;
14
15 public class FeatureColourTest
16 {
17   @Test(groups = { "Functional" })
18   public void testIsColored_simpleColour()
19   {
20     FeatureColour fc = new FeatureColour(Color.RED);
21     assertTrue(fc.isColored(new SequenceFeature()));
22   }
23
24   @Test(groups = { "Functional" })
25   public void testIsColored_colourByLabel()
26   {
27     FeatureColour fc = new FeatureColour();
28     fc.setColourByLabel(true);
29     assertTrue(fc.isColored(new SequenceFeature()));
30   }
31
32   @Test(groups = { "Functional" })
33   public void testIsColored_aboveThreshold()
34   {
35     // graduated colour range from score 20 to 100
36     FeatureColour fc = new FeatureColour(Color.WHITE, Color.BLACK, 20f,
37             100f);
38
39     // score 0 is adjusted to bottom of range
40     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 0f,
41             null);
42     assertTrue(fc.isColored(sf));
43     assertEquals(Color.WHITE, fc.getColor(sf));
44
45     // score 120 is adjusted to top of range
46     sf.setScore(120f);
47     assertEquals(Color.BLACK, fc.getColor(sf));
48
49     // value below threshold is still rendered
50     // setting threshold has no effect yet...
51     fc.setThreshold(60f);
52     sf.setScore(36f);
53     assertTrue(fc.isColored(sf));
54     assertEquals(new Color(204, 204, 204), fc.getColor(sf));
55
56     // now apply threshold:
57     fc.setAboveThreshold(true);
58     assertFalse(fc.isColored(sf));
59     // colour is still returned though ?!?
60     assertEquals(new Color(204, 204, 204), fc.getColor(sf));
61
62     sf.setScore(84); // above threshold now
63     assertTrue(fc.isColored(sf));
64     assertEquals(new Color(51, 51, 51), fc.getColor(sf));
65   }
66
67   @Test(groups = { "Functional" })
68   public void testGetColor_simpleColour()
69   {
70     FeatureColour fc = new FeatureColour(Color.RED);
71     assertEquals(Color.RED, fc.getColor(new SequenceFeature()));
72   }
73
74   @Test(groups = { "Functional" })
75   public void testGetColor_colourByLabel()
76   {
77     FeatureColour fc = new FeatureColour();
78     fc.setColourByLabel(true);
79     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 1f,
80             null);
81     Color expected = UserColourScheme.createColourFromName("desc");
82     assertEquals(expected, fc.getColor(sf));
83   }
84
85   @Test(groups = { "Functional" })
86   public void testGetColor_Graduated()
87   {
88     // graduated colour from score 0 to 100, gray(128, 128, 128) to red(255, 0, 0)
89     FeatureColour fc = new FeatureColour(Color.GRAY, Color.RED, 0f, 100f);
90     // feature score is 75 which is 3/4 of the way from GRAY to RED
91     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 75f,
92             null);
93     // the colour gradient is computed in float values from 0-1 (where 1 == 255)
94     float red = 128 / 255f + 3 / 4f * (255 - 128) / 255f;
95     float green = 128 / 255f + 3 / 4f * (0 - 128) / 255f;
96     float blue = 128 / 255f + 3 / 4f * (0 - 128) / 255f;
97     Color expected = new Color(red, green, blue);
98     assertEquals(expected, fc.getColor(sf));
99   }
100
101   @Test(groups = { "Functional" })
102   public void testGetColor_belowThreshold()
103   {
104     // gradient from [50, 150] from WHITE(255, 255, 255) to BLACK(0, 0, 0)
105     FeatureColour fc = new FeatureColour(Color.WHITE, Color.BLACK, 50f,
106             150f);
107     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 70f,
108             null);
109     fc.setThreshold(100f); // ignore for now
110     assertTrue(fc.isColored(sf));
111     assertEquals(new Color(204, 204, 204), fc.getColor(sf));
112
113     fc.setAboveThreshold(true); // feature lies below threshold
114     assertFalse(fc.isColored(sf));
115     assertEquals(new Color(204, 204, 204), fc.getColor(sf));
116   }
117
118   /**
119    * Test output of feature colours to Jalview features file format
120    */
121   @Test(groups = { "Functional" })
122   public void testToJalviewFormat()
123   {
124     /*
125      * plain colour - to RGB hex code
126      */
127     FeatureColour fc = new FeatureColour(Color.RED);
128     String redHex = Format.getHexString(Color.RED);
129     String hexColour = redHex;
130     assertEquals("domain\t" + hexColour, fc.toJalviewFormat("domain"));
131     
132     /*
133      * colour by label (no threshold)
134      */
135     fc = new FeatureColour();
136     fc.setColourByLabel(true);
137     assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
138
139     /*
140      * colour by label (autoscaled) (an odd state you can reach by selecting
141      * 'above threshold', then deselecting 'threshold is min/max' then 'colour
142      * by label')
143      */
144     fc.setAutoScaled(true);
145     assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
146
147     /*
148      * colour by label (above threshold) (min/max values are output though not
149      * used by this scheme)
150      */
151     fc.setAutoScaled(false);
152     fc.setThreshold(12.5f);
153     fc.setAboveThreshold(true);
154     assertEquals("domain\tlabel|||0.0|0.0|above|12.5",
155             fc.toJalviewFormat("domain"));
156
157     /*
158      * colour by label (below threshold)
159      */
160     fc.setBelowThreshold(true);
161     assertEquals("domain\tlabel|||0.0|0.0|below|12.5",
162             fc.toJalviewFormat("domain"));
163
164     /*
165      * graduated colour, no threshold
166      */
167     fc = new FeatureColour(Color.GREEN, Color.RED, 12f, 25f);
168     String greenHex = Format.getHexString(Color.GREEN);
169     String expected = String.format("domain\t%s|%s|abso|12.0|25.0|none",
170             greenHex, redHex);
171     assertEquals(expected, fc.toJalviewFormat("domain"));
172
173     /*
174      * colour ranges over the actual score ranges (not min/max)
175      */
176     fc.setAutoScaled(true);
177     expected = String.format("domain\t%s|%s|12.0|25.0|none", greenHex,
178             redHex);
179     assertEquals(expected, fc.toJalviewFormat("domain"));
180
181     /*
182      * graduated colour below threshold
183      */
184     fc.setThreshold(12.5f);
185     fc.setBelowThreshold(true);
186     expected = String.format("domain\t%s|%s|12.0|25.0|below|12.5",
187             greenHex, redHex);
188     assertEquals(expected, fc.toJalviewFormat("domain"));
189
190     /*
191      * graduated colour above threshold
192      */
193     fc.setThreshold(12.5f);
194     fc.setAboveThreshold(true);
195     fc.setAutoScaled(false);
196     expected = String.format("domain\t%s|%s|abso|12.0|25.0|above|12.5",
197             greenHex, redHex);
198     assertEquals(expected, fc.toJalviewFormat("domain"));
199   }
200
201   /**
202    * Test parsing of feature colours from Jalview features file format
203    */
204   @Test(groups = { "Functional" })
205   public void testParseJalviewFeatureColour()
206   {
207     /*
208      * simple colour by name
209      */
210     FeatureColour fc = FeatureColour.parseJalviewFeatureColour("red");
211     assertTrue(fc.isSimpleColour());
212     assertEquals(Color.RED, fc.getColour());
213
214     /*
215      * simple colour by hex code
216      */
217     fc = FeatureColour.parseJalviewFeatureColour(Format
218             .getHexString(Color.RED));
219     assertTrue(fc.isSimpleColour());
220     assertEquals(Color.RED, fc.getColour());
221
222     /*
223      * simple colour by rgb triplet
224      */
225     fc = FeatureColour.parseJalviewFeatureColour("255,0,0");
226     assertTrue(fc.isSimpleColour());
227     assertEquals(Color.RED, fc.getColour());
228
229     /*
230      * malformed colour
231      */
232     try
233     {
234       fc = FeatureColour.parseJalviewFeatureColour("oops");
235       fail("expected exception");
236     } catch (IllegalArgumentException e)
237     {
238       assertEquals("Invalid colour descriptor: oops", e.getMessage());
239     }
240
241     /*
242      * colour by label (no threshold)
243      */
244     fc = FeatureColour.parseJalviewFeatureColour("label");
245     assertTrue(fc.isColourByLabel());
246     assertFalse(fc.hasThreshold());
247
248     /*
249      * colour by label (with threshold)
250      */
251     fc = FeatureColour
252             .parseJalviewFeatureColour("label|||0.0|0.0|above|12.0");
253     assertTrue(fc.isColourByLabel());
254     assertTrue(fc.isAboveThreshold());
255     assertEquals(12.0f, fc.getThreshold());
256
257     /*
258      * graduated colour (by name) (no threshold)
259      */
260     fc = FeatureColour.parseJalviewFeatureColour("red|green|10.0|20.0");
261     assertTrue(fc.isGraduatedColour());
262     assertFalse(fc.hasThreshold());
263     assertEquals(Color.RED, fc.getMinColour());
264     assertEquals(Color.GREEN, fc.getMaxColour());
265     assertEquals(10f, fc.getMin());
266     assertEquals(20f, fc.getMax());
267     assertTrue(fc.isAutoScaled());
268
269     /*
270      * graduated colour (by hex code) (above threshold)
271      */
272     String descriptor = String.format("%s|%s|10.0|20.0|above|15",
273             Format.getHexString(Color.RED),
274             Format.getHexString(Color.GREEN));
275     fc = FeatureColour.parseJalviewFeatureColour(descriptor);
276     assertTrue(fc.isGraduatedColour());
277     assertTrue(fc.hasThreshold());
278     assertTrue(fc.isAboveThreshold());
279     assertEquals(15f, fc.getThreshold());
280     assertEquals(Color.RED, fc.getMinColour());
281     assertEquals(Color.GREEN, fc.getMaxColour());
282     assertEquals(10f, fc.getMin());
283     assertEquals(20f, fc.getMax());
284     assertTrue(fc.isAutoScaled());
285
286     /*
287      * graduated colour (by RGB triplet) (below threshold), absolute scale
288      */
289     descriptor = String.format("255,0,0|0,255,0|abso|10.0|20.0|below|15");
290     fc = FeatureColour.parseJalviewFeatureColour(descriptor);
291     assertTrue(fc.isGraduatedColour());
292     assertFalse(fc.isAutoScaled());
293     assertTrue(fc.hasThreshold());
294     assertTrue(fc.isBelowThreshold());
295     assertEquals(15f, fc.getThreshold());
296     assertEquals(Color.RED, fc.getMinColour());
297     assertEquals(Color.GREEN, fc.getMaxColour());
298     assertEquals(10f, fc.getMin());
299     assertEquals(20f, fc.getMax());
300   }
301 }