03f7efa53de6e402c402800cd1b0c306e3e5ca29
[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     fc.setThreshold(100f); // ignore for now
132     assertEquals(new Color(204, 204, 204), fc.getColor(sf));
133
134     fc.setAboveThreshold(true); // feature lies below threshold
135     assertNull(fc.getColor(sf));
136
137     fc.setBelowThreshold(true);
138     fc.setThreshold(70f);
139     assertNull(fc.getColor(sf)); // feature score == threshold - hidden
140     fc.setThreshold(69f);
141     assertNull(fc.getColor(sf)); // feature score > threshold - hidden
142   }
143
144   /**
145    * Test output of feature colours to Jalview features file format
146    */
147   @Test(groups = { "Functional" })
148   public void testToJalviewFormat()
149   {
150     /*
151      * plain colour - to RGB hex code
152      */
153     FeatureColour fc = new FeatureColour(Color.RED);
154     String redHex = Format.getHexString(Color.RED);
155     String hexColour = redHex;
156     assertEquals("domain\t" + hexColour, fc.toJalviewFormat("domain"));
157
158     /*
159      * colour by label (no threshold)
160      */
161     fc = new FeatureColour();
162     fc.setColourByLabel(true);
163     assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
164
165     /*
166      * colour by label (autoscaled) (an odd state you can reach by selecting
167      * 'above threshold', then deselecting 'threshold is min/max' then 'colour
168      * by label')
169      */
170     fc.setAutoScaled(true);
171     assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
172
173     /*
174      * colour by label (above threshold) (min/max values are output though not
175      * used by this scheme)
176      */
177     fc.setAutoScaled(false);
178     fc.setThreshold(12.5f);
179     fc.setAboveThreshold(true);
180     assertEquals("domain\tlabel|||0.0|0.0|above|12.5",
181             fc.toJalviewFormat("domain"));
182
183     /*
184      * colour by label (below threshold)
185      */
186     fc.setBelowThreshold(true);
187     assertEquals("domain\tlabel|||0.0|0.0|below|12.5",
188             fc.toJalviewFormat("domain"));
189
190     /*
191      * graduated colour, no threshold
192      */
193     fc = new FeatureColour(Color.GREEN, Color.RED, 12f, 25f);
194     String greenHex = Format.getHexString(Color.GREEN);
195     String expected = String.format("domain\t%s|%s|abso|12.0|25.0|none",
196             greenHex, redHex);
197     assertEquals(expected, fc.toJalviewFormat("domain"));
198
199     /*
200      * colour ranges over the actual score ranges (not min/max)
201      */
202     fc.setAutoScaled(true);
203     expected = String.format("domain\t%s|%s|12.0|25.0|none", greenHex,
204             redHex);
205     assertEquals(expected, fc.toJalviewFormat("domain"));
206
207     /*
208      * graduated colour below threshold
209      */
210     fc.setThreshold(12.5f);
211     fc.setBelowThreshold(true);
212     expected = String.format("domain\t%s|%s|12.0|25.0|below|12.5",
213             greenHex, redHex);
214     assertEquals(expected, fc.toJalviewFormat("domain"));
215
216     /*
217      * graduated colour above threshold
218      */
219     fc.setThreshold(12.5f);
220     fc.setAboveThreshold(true);
221     fc.setAutoScaled(false);
222     expected = String.format("domain\t%s|%s|abso|12.0|25.0|above|12.5",
223             greenHex, redHex);
224     assertEquals(expected, fc.toJalviewFormat("domain"));
225   }
226
227   /**
228    * Test parsing of feature colours from Jalview features file format
229    */
230   @Test(groups = { "Functional" })
231   public void testParseJalviewFeatureColour()
232   {
233     /*
234      * simple colour by name
235      */
236     FeatureColour fc = FeatureColour.parseJalviewFeatureColour("red");
237     assertTrue(fc.isSimpleColour());
238     assertEquals(Color.RED, fc.getColour());
239
240     /*
241      * simple colour by hex code
242      */
243     fc = FeatureColour.parseJalviewFeatureColour(Format
244             .getHexString(Color.RED));
245     assertTrue(fc.isSimpleColour());
246     assertEquals(Color.RED, fc.getColour());
247
248     /*
249      * simple colour by rgb triplet
250      */
251     fc = FeatureColour.parseJalviewFeatureColour("255,0,0");
252     assertTrue(fc.isSimpleColour());
253     assertEquals(Color.RED, fc.getColour());
254
255     /*
256      * malformed colour
257      */
258     try
259     {
260       fc = FeatureColour.parseJalviewFeatureColour("oops");
261       fail("expected exception");
262     } catch (IllegalArgumentException e)
263     {
264       assertEquals("Invalid colour descriptor: oops", e.getMessage());
265     }
266
267     /*
268      * colour by label (no threshold)
269      */
270     fc = FeatureColour.parseJalviewFeatureColour("label");
271     assertTrue(fc.isColourByLabel());
272     assertFalse(fc.hasThreshold());
273
274     /*
275      * colour by label (with threshold)
276      */
277     fc = FeatureColour
278             .parseJalviewFeatureColour("label|||0.0|0.0|above|12.0");
279     assertTrue(fc.isColourByLabel());
280     assertTrue(fc.isAboveThreshold());
281     assertEquals(12.0f, fc.getThreshold());
282
283     /*
284      * graduated colour (by name) (no threshold)
285      */
286     fc = FeatureColour.parseJalviewFeatureColour("red|green|10.0|20.0");
287     assertTrue(fc.isGraduatedColour());
288     assertFalse(fc.hasThreshold());
289     assertEquals(Color.RED, fc.getMinColour());
290     assertEquals(Color.GREEN, fc.getMaxColour());
291     assertEquals(10f, fc.getMin());
292     assertEquals(20f, fc.getMax());
293     assertTrue(fc.isAutoScaled());
294
295     /*
296      * graduated colour (by hex code) (above threshold)
297      */
298     String descriptor = String.format("%s|%s|10.0|20.0|above|15",
299             Format.getHexString(Color.RED),
300             Format.getHexString(Color.GREEN));
301     fc = FeatureColour.parseJalviewFeatureColour(descriptor);
302     assertTrue(fc.isGraduatedColour());
303     assertTrue(fc.hasThreshold());
304     assertTrue(fc.isAboveThreshold());
305     assertEquals(15f, fc.getThreshold());
306     assertEquals(Color.RED, fc.getMinColour());
307     assertEquals(Color.GREEN, fc.getMaxColour());
308     assertEquals(10f, fc.getMin());
309     assertEquals(20f, fc.getMax());
310     assertTrue(fc.isAutoScaled());
311
312     /*
313      * graduated colour (by RGB triplet) (below threshold), absolute scale
314      */
315     descriptor = String.format("255,0,0|0,255,0|abso|10.0|20.0|below|15");
316     fc = FeatureColour.parseJalviewFeatureColour(descriptor);
317     assertTrue(fc.isGraduatedColour());
318     assertFalse(fc.isAutoScaled());
319     assertTrue(fc.hasThreshold());
320     assertTrue(fc.isBelowThreshold());
321     assertEquals(15f, fc.getThreshold());
322     assertEquals(Color.RED, fc.getMinColour());
323     assertEquals(Color.GREEN, fc.getMaxColour());
324     assertEquals(10f, fc.getMin());
325     assertEquals(20f, fc.getMax());
326
327     descriptor = String
328             .format("blue|255,0,255|absolute|20.0|95.0|below|66.0");
329     fc = FeatureColour.parseJalviewFeatureColour(descriptor);
330     assertTrue(fc.isGraduatedColour());
331   }
332 }