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