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