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