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