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