dae70f7b15b7084cea8b48fa9eff479274253bd5
[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 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
29
30 import jalview.api.FeatureColourI;
31 import jalview.datamodel.SequenceFeature;
32 import jalview.gui.JvOptionPane;
33 import jalview.util.ColorUtils;
34 import jalview.util.Format;
35
36 import java.awt.Color;
37
38 import org.testng.annotations.BeforeClass;
39 import org.testng.annotations.Test;
40
41 public class FeatureColourTest
42 {
43
44   @BeforeClass(alwaysRun = true)
45   public void setUpJvOptionPane()
46   {
47     JvOptionPane.setInteractiveMode(false);
48     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
49   }
50
51   @Test(groups = { "Functional" })
52   public void testConstructors()
53   {
54     FeatureColourI fc = new FeatureColour();
55     assertNull(fc.getColour());
56     assertTrue(fc.isSimpleColour());
57     assertFalse(fc.isColourByLabel());
58     assertFalse(fc.isGraduatedColour());
59     assertFalse(fc.isColourByAttribute());
60     assertEquals(Color.white, fc.getMinColour());
61     assertEquals(Color.black, fc.getMaxColour());
62
63     fc = new FeatureColour(Color.RED);
64     assertEquals(Color.red, fc.getColour());
65     assertTrue(fc.isSimpleColour());
66     assertFalse(fc.isColourByLabel());
67     assertFalse(fc.isGraduatedColour());
68     assertFalse(fc.isColourByAttribute());
69     assertEquals(ColorUtils.bleachColour(Color.RED, 0.9f),
70             fc.getMinColour());
71     assertEquals(Color.RED, fc.getMaxColour());
72
73   }
74
75   @Test(groups = { "Functional" })
76   public void testCopyConstructor()
77   {
78     /*
79      * plain colour
80      */
81     FeatureColour fc = new FeatureColour(Color.RED);
82     FeatureColour fc1 = new FeatureColour(fc);
83     assertTrue(fc1.getColour().equals(Color.RED));
84     assertFalse(fc1.isGraduatedColour());
85     assertFalse(fc1.isColourByLabel());
86     assertFalse(fc1.isColourByAttribute());
87     assertNull(fc1.getAttributeName());
88
89     /*
90      * min-max colour
91      */
92     fc = new FeatureColour(null, Color.gray, Color.black, Color.gray, 10f,
93             20f);
94     fc.setAboveThreshold(true);
95     fc.setThreshold(12f);
96     fc1 = new FeatureColour(fc);
97     assertTrue(fc1.isGraduatedColour());
98     assertFalse(fc1.isColourByLabel());
99     assertTrue(fc1.isAboveThreshold());
100     assertFalse(fc1.isColourByAttribute());
101     assertNull(fc1.getAttributeName());
102     assertEquals(12f, fc1.getThreshold());
103     assertEquals(Color.gray, fc1.getMinColour());
104     assertEquals(Color.black, fc1.getMaxColour());
105     assertEquals(Color.gray, fc1.getNoColour());
106     assertEquals(10f, fc1.getMin());
107     assertEquals(20f, fc1.getMax());
108
109     /*
110      * min-max-noValue colour
111      */
112     fc = new FeatureColour(Color.red, Color.gray, Color.black, Color.green,
113             10f, 20f);
114     fc.setAboveThreshold(true);
115     fc.setThreshold(12f);
116     fc1 = new FeatureColour(fc);
117     assertTrue(fc1.isGraduatedColour());
118     assertFalse(fc1.isColourByLabel());
119     assertFalse(fc1.isSimpleColour());
120     assertFalse(fc1.isColourByAttribute());
121     assertNull(fc1.getAttributeName());
122     assertTrue(fc1.isAboveThreshold());
123     assertEquals(12f, fc1.getThreshold());
124     assertEquals(Color.gray, fc1.getMinColour());
125     assertEquals(Color.black, fc1.getMaxColour());
126     assertEquals(Color.green, fc1.getNoColour());
127     assertEquals(Color.red, fc1.getColour());
128     assertEquals(10f, fc1.getMin());
129     assertEquals(20f, fc1.getMax());
130
131     /*
132      * colour by label
133      */
134     fc = new FeatureColour();
135     fc.setColourByLabel(true);
136     fc1 = new FeatureColour(fc);
137     assertTrue(fc1.isColourByLabel());
138     assertFalse(fc1.isGraduatedColour());
139     assertFalse(fc1.isColourByAttribute());
140     assertNull(fc1.getAttributeName());
141
142     /*
143      * colour by attribute (label)
144      */
145     fc = new FeatureColour();
146     fc.setColourByLabel(true);
147     fc.setAttributeName("AF");
148     fc1 = new FeatureColour(fc);
149     assertTrue(fc1.isColourByLabel());
150     assertFalse(fc1.isGraduatedColour());
151     assertTrue(fc1.isColourByAttribute());
152     assertArrayEquals(new String[] { "AF" }, fc1.getAttributeName());
153
154     /*
155      * colour by attribute (value)
156      */
157     fc = new FeatureColour(Color.yellow, Color.gray, Color.black,
158             Color.green, 10f, 20f);
159     fc.setAboveThreshold(true);
160     fc.setThreshold(12f);
161     fc.setAttributeName("AF");
162     fc1 = new FeatureColour(fc);
163     assertTrue(fc1.isGraduatedColour());
164     assertFalse(fc1.isColourByLabel());
165     assertTrue(fc1.isColourByAttribute());
166     assertFalse(fc1.isSimpleColour());
167     assertArrayEquals(new String[] { "AF" }, fc1.getAttributeName());
168     assertTrue(fc1.isAboveThreshold());
169     assertEquals(12f, fc1.getThreshold());
170     assertEquals(Color.gray, fc1.getMinColour());
171     assertEquals(Color.black, fc1.getMaxColour());
172     assertEquals(Color.green, fc1.getNoColour());
173     assertEquals(Color.yellow, fc1.getColour());
174     assertEquals(10f, fc1.getMin());
175     assertEquals(20f, fc1.getMax());
176
177     /*
178      * modify original attribute label and check that copy doesn't change
179      */
180     fc.setAttributeName("MAF", "AF");
181     assertArrayEquals(new String[] { "AF" }, fc1.getAttributeName());
182
183   }
184
185   @Test(groups = { "Functional" })
186   public void testGetColor_simpleColour()
187   {
188     FeatureColour fc = new FeatureColour(Color.RED);
189     assertEquals(Color.RED,
190             fc.getColor(new SequenceFeature("Cath", "", 1, 2, 0f, null)));
191   }
192
193   @Test(groups = { "Functional" })
194   public void testGetColor_colourByLabel()
195   {
196     FeatureColour fc = new FeatureColour();
197     fc.setColourByLabel(true);
198     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 1f,
199             null);
200     Color expected = ColorUtils.createColourFromName("desc");
201     assertEquals(expected, fc.getColor(sf));
202   }
203
204   @Test(groups = { "Functional" })
205   public void testGetColor_Graduated()
206   {
207     /*
208      * graduated colour from 
209      * score 0 to 100
210      * gray(128, 128, 128) to red(255, 0, 0)
211      */
212     FeatureColour fc = new FeatureColour(null, Color.GRAY, Color.RED, null,
213             0f, 100f);
214     // feature score is 75 which is 3/4 of the way from GRAY to RED
215     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 75f,
216             null);
217     // the colour gradient is computed in float values from 0-1 (where 1 == 255)
218     float red = 128 / 255f + 3 / 4f * (255 - 128) / 255f;
219     float green = 128 / 255f + 3 / 4f * (0 - 128) / 255f;
220     float blue = 128 / 255f + 3 / 4f * (0 - 128) / 255f;
221     Color expected = new Color(red, green, blue);
222     assertEquals(expected, fc.getColor(sf));
223   }
224
225   @Test(groups = { "Functional" })
226   public void testGetColor_aboveBelowThreshold()
227   {
228     // gradient from [50, 150] from WHITE(255, 255, 255) to BLACK(0, 0, 0)
229     FeatureColour fc = new FeatureColour(null, Color.WHITE, Color.BLACK,
230             Color.white, 50f, 150f);
231     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 70f,
232             null);
233
234     /*
235      * feature with score of Float.NaN is always assigned minimum colour
236      */
237     SequenceFeature sf2 = new SequenceFeature("type", "desc", 0, 20,
238             Float.NaN, null);
239
240     fc.setThreshold(100f); // ignore for now
241     assertEquals(new Color(204, 204, 204), fc.getColor(sf));
242     assertEquals(Color.white, fc.getColor(sf2));
243
244     fc.setAboveThreshold(true); // feature lies below threshold
245     assertNull(fc.getColor(sf));
246     assertEquals(Color.white, fc.getColor(sf2));
247
248     fc.setBelowThreshold(true);
249     fc.setThreshold(70f);
250     assertNull(fc.getColor(sf)); // feature score == threshold - hidden
251     assertEquals(Color.white, fc.getColor(sf2));
252     fc.setThreshold(69f);
253     assertNull(fc.getColor(sf)); // feature score > threshold - hidden
254     assertEquals(Color.white, fc.getColor(sf2));
255   }
256
257   /**
258    * Test output of feature colours to Jalview features file format
259    */
260   @Test(groups = { "Functional" })
261   public void testToJalviewFormat()
262   {
263     /*
264      * plain colour - to RGB hex code
265      */
266     FeatureColour fc = new FeatureColour(Color.RED);
267     String redHex = Format.getHexString(Color.RED);
268     String hexColour = redHex;
269     assertEquals("domain\t" + hexColour, fc.toJalviewFormat("domain"));
270
271     /*
272      * colour by label (no threshold)
273      */
274     fc = new FeatureColour();
275     fc.setColourByLabel(true);
276     assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
277
278     /*
279      * colour by attribute text (no threshold)
280      */
281     fc = new FeatureColour();
282     fc.setColourByLabel(true);
283     fc.setAttributeName("CLIN_SIG");
284     assertEquals("domain\tattribute|CLIN_SIG", fc.toJalviewFormat("domain"));
285     
286     /*
287      * colour by label (autoscaled) (an odd state you can reach by selecting
288      * 'above threshold', then deselecting 'threshold is min/max' then 'colour
289      * by label')
290      */
291     fc.setAttributeName((String[]) null);
292     fc.setAutoScaled(true);
293     assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
294
295     /*
296      * colour by label (above threshold) 
297      */
298     fc.setAutoScaled(false);
299     fc.setThreshold(12.5f);
300     fc.setAboveThreshold(true);
301     // min/max values are output though not used by this scheme
302     assertEquals("domain\tlabel|||0.0|0.0|above|12.5",
303             fc.toJalviewFormat("domain"));
304
305     /*
306      * colour by label (below threshold)
307      */
308     fc.setBelowThreshold(true);
309     assertEquals("domain\tlabel|||0.0|0.0|below|12.5",
310             fc.toJalviewFormat("domain"));
311
312     /*
313      * colour by attributes text (below threshold)
314      */
315     fc.setBelowThreshold(true);
316     fc.setAttributeName("CSQ", "Consequence");
317     assertEquals("domain\tattribute|CSQ:Consequence|||0.0|0.0|below|12.5",
318             fc.toJalviewFormat("domain"));
319
320     /*
321      * graduated colour by score, no threshold
322      * - default constructor sets noValueColor = minColor
323      */
324     fc = new FeatureColour(null, Color.GREEN, Color.RED, Color.GREEN, 12f,
325             25f);
326     String greenHex = Format.getHexString(Color.GREEN);
327     String expected = String.format(
328             "domain\tscore|%s|%s|noValueMin|abso|12.0|25.0|none", greenHex,
329             redHex);
330     assertEquals(expected, fc.toJalviewFormat("domain"));
331
332     /*
333      * graduated colour by score, no threshold, no value gets min colour
334      */
335     fc = new FeatureColour(Color.RED, Color.GREEN, Color.RED, Color.GREEN,
336             12f, 25f);
337     expected = String.format(
338             "domain\tscore|%s|%s|noValueMin|abso|12.0|25.0|none", greenHex,
339             redHex);
340     assertEquals(expected, fc.toJalviewFormat("domain"));
341
342     /*
343      * graduated colour by score, no threshold, no value gets max colour
344      */
345     fc = new FeatureColour(Color.RED, Color.GREEN, Color.RED, Color.RED,
346             12f, 25f);
347     expected = String.format(
348             "domain\tscore|%s|%s|noValueMax|abso|12.0|25.0|none", greenHex,
349             redHex);
350     assertEquals(expected, fc.toJalviewFormat("domain"));
351     
352     /*
353      * colour ranges over the actual score ranges (not min/max)
354      */
355     fc.setAutoScaled(true);
356     expected = String.format(
357             "domain\tscore|%s|%s|noValueMax|12.0|25.0|none", greenHex,
358             redHex);
359     assertEquals(expected, fc.toJalviewFormat("domain"));
360
361     /*
362      * graduated colour by score, below threshold
363      */
364     fc.setThreshold(12.5f);
365     fc.setBelowThreshold(true);
366     expected = String.format(
367             "domain\tscore|%s|%s|noValueMax|12.0|25.0|below|12.5",
368             greenHex, redHex);
369     assertEquals(expected, fc.toJalviewFormat("domain"));
370
371     /*
372      * graduated colour by score, above threshold
373      */
374     fc.setThreshold(12.5f);
375     fc.setAboveThreshold(true);
376     fc.setAutoScaled(false);
377     expected = String.format(
378             "domain\tscore|%s|%s|noValueMax|abso|12.0|25.0|above|12.5",
379             greenHex, redHex);
380     assertEquals(expected, fc.toJalviewFormat("domain"));
381
382     /*
383      * graduated colour by attribute, above threshold
384      */
385     fc.setAttributeName("CSQ", "AF");
386     fc.setAboveThreshold(true);
387     fc.setAutoScaled(false);
388     expected = String.format(
389             "domain\tattribute|CSQ:AF|%s|%s|noValueMax|abso|12.0|25.0|above|12.5",
390             greenHex, redHex);
391     assertEquals(expected, fc.toJalviewFormat("domain"));
392   }
393
394   /**
395    * Test parsing of feature colours from Jalview features file format
396    */
397   @Test(groups = { "Functional" })
398   public void testParseJalviewFeatureColour()
399   {
400     /*
401      * simple colour by name
402      */
403     FeatureColourI fc = FeatureColour.parseJalviewFeatureColour("red");
404     assertTrue(fc.isSimpleColour());
405     assertEquals(Color.RED, fc.getColour());
406
407     /*
408      * simple colour by hex code
409      */
410     fc = FeatureColour.parseJalviewFeatureColour(Format
411             .getHexString(Color.RED));
412     assertTrue(fc.isSimpleColour());
413     assertEquals(Color.RED, fc.getColour());
414
415     /*
416      * simple colour by rgb triplet
417      */
418     fc = FeatureColour.parseJalviewFeatureColour("255,0,0");
419     assertTrue(fc.isSimpleColour());
420     assertEquals(Color.RED, fc.getColour());
421
422     /*
423      * malformed colour
424      */
425     try
426     {
427       fc = FeatureColour.parseJalviewFeatureColour("oops");
428       fail("expected exception");
429     } catch (IllegalArgumentException e)
430     {
431       assertEquals("Invalid colour descriptor: oops", e.getMessage());
432     }
433
434     /*
435      * colour by label (no threshold)
436      */
437     fc = FeatureColour.parseJalviewFeatureColour("label");
438     assertTrue(fc.isColourByLabel());
439     assertFalse(fc.hasThreshold());
440
441     /*
442      * colour by label (with threshold)
443      */
444     fc = FeatureColour
445             .parseJalviewFeatureColour("label|||0.0|0.0|above|12.0");
446     assertTrue(fc.isColourByLabel());
447     assertTrue(fc.isAboveThreshold());
448     assertEquals(12.0f, fc.getThreshold());
449
450     /*
451      * colour by attribute text (no threshold)
452      */
453     fc = FeatureColour.parseJalviewFeatureColour("attribute|CLIN_SIG");
454     assertTrue(fc.isColourByAttribute());
455     assertTrue(fc.isColourByLabel());
456     assertFalse(fc.hasThreshold());
457     assertArrayEquals(new String[] { "CLIN_SIG" }, fc.getAttributeName());
458
459     /*
460      * colour by attributes text (with score threshold)
461      */
462     fc = FeatureColour.parseJalviewFeatureColour(
463             "attribute|CSQ:Consequence|||0.0|0.0|above|12.0");
464     assertTrue(fc.isColourByLabel());
465     assertTrue(fc.isColourByAttribute());
466     assertArrayEquals(new String[] { "CSQ", "Consequence" },
467             fc.getAttributeName());
468     assertTrue(fc.isAboveThreshold());
469     assertEquals(12.0f, fc.getThreshold());
470
471     /*
472      * graduated colour by score (with colour names) (no threshold)
473      */
474     fc = FeatureColour.parseJalviewFeatureColour("red|green|10.0|20.0");
475     assertTrue(fc.isGraduatedColour());
476     assertFalse(fc.hasThreshold());
477     assertEquals(Color.RED, fc.getMinColour());
478     assertEquals(Color.GREEN, fc.getMaxColour());
479     assertEquals(Color.RED, fc.getNoColour());
480     assertEquals(10f, fc.getMin());
481     assertEquals(20f, fc.getMax());
482     assertTrue(fc.isAutoScaled());
483
484     /*
485      * the same, with 'no value colour' specified as max
486      */
487     fc = FeatureColour
488             .parseJalviewFeatureColour("red|green|novaluemax|10.0|20.0");
489     assertEquals(Color.RED, fc.getMinColour());
490     assertEquals(Color.GREEN, fc.getMaxColour());
491     assertEquals(Color.GREEN, fc.getNoColour());
492     assertEquals(10f, fc.getMin());
493     assertEquals(20f, fc.getMax());
494
495     /*
496      * the same, with 'no value colour' specified as min
497      */
498     fc = FeatureColour
499             .parseJalviewFeatureColour("red|green|novalueMin|10.0|20.0");
500     assertEquals(Color.RED, fc.getMinColour());
501     assertEquals(Color.GREEN, fc.getMaxColour());
502     assertEquals(Color.RED, fc.getNoColour());
503     assertEquals(10f, fc.getMin());
504     assertEquals(20f, fc.getMax());
505
506     /*
507      * the same, with 'no value colour' specified as none
508      */
509     fc = FeatureColour
510             .parseJalviewFeatureColour("red|green|novaluenone|10.0|20.0");
511     assertEquals(Color.RED, fc.getMinColour());
512     assertEquals(Color.GREEN, fc.getMaxColour());
513     assertNull(fc.getNoColour());
514     assertEquals(10f, fc.getMin());
515     assertEquals(20f, fc.getMax());
516
517     /*
518      * the same, with invalid 'no value colour'
519      */
520     try
521     {
522       fc = FeatureColour
523               .parseJalviewFeatureColour("red|green|blue|10.0|20.0");
524       fail("expected exception");
525     } catch (IllegalArgumentException e)
526     {
527       assertEquals(
528               "Couldn't parse the minimum value for graduated colour ('blue')",
529               e.getMessage());
530     }
531
532     /*
533      * graduated colour (explicitly by 'score') (no threshold)
534      */
535     fc = FeatureColour
536             .parseJalviewFeatureColour("Score|red|green|10.0|20.0");
537     assertTrue(fc.isGraduatedColour());
538     assertFalse(fc.hasThreshold());
539     assertEquals(Color.RED, fc.getMinColour());
540     assertEquals(Color.GREEN, fc.getMaxColour());
541     assertEquals(10f, fc.getMin());
542     assertEquals(20f, fc.getMax());
543     assertTrue(fc.isAutoScaled());
544
545     /*
546      * graduated colour by attribute (no threshold)
547      */
548     fc = FeatureColour
549             .parseJalviewFeatureColour("attribute|AF|red|green|10.0|20.0");
550     assertTrue(fc.isGraduatedColour());
551     assertTrue(fc.isColourByAttribute());
552     assertArrayEquals(new String[] { "AF" }, fc.getAttributeName());
553     assertFalse(fc.hasThreshold());
554     assertEquals(Color.RED, fc.getMinColour());
555     assertEquals(Color.GREEN, fc.getMaxColour());
556     assertEquals(10f, fc.getMin());
557     assertEquals(20f, fc.getMax());
558     assertTrue(fc.isAutoScaled());
559
560     /*
561      * graduated colour by score (colours by hex code) (above threshold)
562      */
563     String descriptor = String.format("%s|%s|10.0|20.0|above|15",
564             Format.getHexString(Color.RED),
565             Format.getHexString(Color.GREEN));
566     fc = FeatureColour.parseJalviewFeatureColour(descriptor);
567     assertTrue(fc.isGraduatedColour());
568     assertTrue(fc.hasThreshold());
569     assertTrue(fc.isAboveThreshold());
570     assertEquals(15f, fc.getThreshold());
571     assertEquals(Color.RED, fc.getMinColour());
572     assertEquals(Color.GREEN, fc.getMaxColour());
573     assertEquals(10f, fc.getMin());
574     assertEquals(20f, fc.getMax());
575     assertTrue(fc.isAutoScaled());
576
577     /*
578      * graduated colour by attributes (below threshold)
579      */
580     fc = FeatureColour.parseJalviewFeatureColour(
581             "attribute|CSQ:AF|red|green|10.0|20.0|below|13");
582     assertTrue(fc.isGraduatedColour());
583     assertTrue(fc.isColourByAttribute());
584     assertArrayEquals(new String[] { "CSQ", "AF" }, fc.getAttributeName());
585     assertTrue(fc.hasThreshold());
586     assertTrue(fc.isBelowThreshold());
587     assertEquals(13f, fc.getThreshold());
588     assertEquals(Color.RED, fc.getMinColour());
589     assertEquals(Color.GREEN, fc.getMaxColour());
590     assertEquals(10f, fc.getMin());
591     assertEquals(20f, fc.getMax());
592     assertTrue(fc.isAutoScaled());
593
594     /*
595      * graduated colour (by RGB triplet) (below threshold), absolute scale
596      */
597     descriptor = "255,0,0|0,255,0|abso|10.0|20.0|below|15";
598     fc = FeatureColour.parseJalviewFeatureColour(descriptor);
599     assertTrue(fc.isGraduatedColour());
600     assertFalse(fc.isAutoScaled());
601     assertTrue(fc.hasThreshold());
602     assertTrue(fc.isBelowThreshold());
603     assertEquals(15f, fc.getThreshold());
604     assertEquals(Color.RED, fc.getMinColour());
605     assertEquals(Color.GREEN, fc.getMaxColour());
606     assertEquals(10f, fc.getMin());
607     assertEquals(20f, fc.getMax());
608
609     descriptor = "blue|255,0,255|absolute|20.0|95.0|below|66.0";
610     fc = FeatureColour.parseJalviewFeatureColour(descriptor);
611     assertTrue(fc.isGraduatedColour());
612   }
613
614   @Test(groups = { "Functional" })
615   public void testGetColor_colourByAttributeText()
616   {
617     FeatureColour fc = new FeatureColour();
618     fc.setColourByLabel(true);
619     fc.setAttributeName("consequence");
620     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 1f,
621             null);
622
623     /*
624      * if feature has no such attribute, use 'no value' colour
625      */
626     assertEquals(FeatureColour.DEFAULT_NO_COLOUR, fc.getColor(sf));
627
628     /*
629      * if feature has attribute, generate colour from value
630      */
631     sf.setValue("consequence", "benign");
632     Color expected = ColorUtils.createColourFromName("benign");
633     assertEquals(expected, fc.getColor(sf));
634   }
635
636   @Test(groups = { "Functional" })
637   public void testGetColor_GraduatedByAttributeValue()
638   {
639     /*
640      * graduated colour based on attribute value for AF
641      * given a min-max range of 0-100
642      */
643     FeatureColour fc = new FeatureColour(Color.white,
644             new Color(50, 100, 150), new Color(150, 200, 250), Color.yellow,
645             0f, 100f);
646     String attName = "AF";
647     fc.setAttributeName(attName);
648
649     /*
650      * first case: feature lacks the attribute - use 'no value' colour
651      */
652     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 75f,
653             null);
654     assertEquals(Color.yellow, fc.getColor(sf));
655
656     /*
657      * second case: attribute present but not numeric - treat as if absent
658      */
659     sf.setValue(attName, "twelve");
660     assertEquals(Color.yellow, fc.getColor(sf));
661
662     /*
663      * third case: valid attribute value
664      */
665     sf.setValue(attName, "20.0");
666     Color expected = new Color(70, 120, 170);
667     assertEquals(expected, fc.getColor(sf));
668   }
669
670   @Test(groups = { "Functional" })
671   public void testIsOutwithThreshold()
672   {
673     FeatureColourI fc = new FeatureColour(Color.red);
674     SequenceFeature sf = new SequenceFeature("METAL", "desc", 10, 12, 1.2f, "grp");
675     assertFalse(fc.isOutwithThreshold(null));
676     assertFalse(fc.isOutwithThreshold(sf));
677
678     fc = new FeatureColour(null, Color.white, Color.black, Color.green, 0f,
679             10f);
680     assertFalse(fc.isOutwithThreshold(sf)); // no threshold
681
682     fc.setAboveThreshold(true);
683     fc.setThreshold(1f);
684     assertFalse(fc.isOutwithThreshold(sf)); // feature score 1.2 is above 1
685
686     fc.setThreshold(2f);
687     assertTrue(fc.isOutwithThreshold(sf)); // feature score 1.2 is not above 2
688
689     fc.setBelowThreshold(true);
690     assertFalse(fc.isOutwithThreshold(sf)); // feature score 1.2 is below 2
691
692     fc.setThreshold(1f);
693     assertTrue(fc.isOutwithThreshold(sf)); // feature score 1.2 is not below 1
694
695     /*
696      * with attribute value threshold
697      */
698     fc.setAttributeName("AC");
699     assertFalse(fc.isOutwithThreshold(sf)); // missing attribute AC is ignored
700
701     sf.setValue("AC", "-1");
702     assertFalse(fc.isOutwithThreshold(sf)); // value -1 is below 1
703
704     sf.setValue("AC", "1");
705     assertTrue(fc.isOutwithThreshold(sf)); // value 1 is not below 1
706
707     sf.setValue("AC", "junk");
708     assertFalse(fc.isOutwithThreshold(sf)); // bad value is ignored
709   }
710
711   /**
712    * Test description of feature colour suitable for a tooltip
713    */
714   @Test(groups = { "Functional" })
715   public void testGetDescription()
716   {
717     /*
718      * plain colour
719      */
720     FeatureColour fc = new FeatureColour(Color.RED);
721     assertEquals(
722             String.format("r=%d,g=%d,b=%d", Color.RED.getRed(),
723                     Color.red.getGreen(), Color.red.getBlue()),
724             fc.getDescription());
725   
726     /*
727      * colour by label (no threshold)
728      */
729     fc = new FeatureColour();
730     fc.setColourByLabel(true);
731     assertEquals("By Label", fc.getDescription());
732   
733     /*
734      * colour by attribute text (no threshold)
735      */
736     fc = new FeatureColour();
737     fc.setColourByLabel(true);
738     fc.setAttributeName("CLIN_SIG");
739     assertEquals("By CLIN_SIG", fc.getDescription());
740   
741     /*
742      * colour by label (above score threshold) 
743      */
744     fc = new FeatureColour();
745     fc.setColourByLabel(true);
746     fc.setAutoScaled(false);
747     fc.setThreshold(12.5f);
748     fc.setAboveThreshold(true);
749     assertEquals("By Label (Score > 12.5)",
750             fc.getDescription());
751   
752     /*
753      * colour by label (below score threshold)
754      */
755     fc.setBelowThreshold(true);
756     assertEquals("By Label (Score < 12.5)",
757             fc.getDescription());
758   
759     /*
760      * colour by attributes text (below score threshold)
761      */
762     fc.setBelowThreshold(true);
763     fc.setAttributeName("CSQ", "Consequence");
764     assertEquals(
765             "By CSQ:Consequence (Score < 12.5)",
766             fc.getDescription());
767   
768     /*
769      * graduated colour by score, no threshold
770      */
771     fc = new FeatureColour(null, Color.GREEN, Color.RED, null, 12f, 25f);
772     assertEquals("By Score", fc.getDescription());
773   
774     /*
775      * graduated colour by score, below threshold
776      */
777     fc.setThreshold(12.5f);
778     fc.setBelowThreshold(true);
779     assertEquals("By Score (< 12.5)",
780             fc.getDescription());
781   
782     /*
783      * graduated colour by score, above threshold
784      */
785     fc.setThreshold(12.5f);
786     fc.setAboveThreshold(true);
787     fc.setAutoScaled(false);
788     assertEquals("By Score (> 12.5)",
789             fc.getDescription());
790
791     /*
792      * graduated colour by attribute, no threshold
793      */
794     fc.setAttributeName("CSQ", "AF");
795     fc.setAboveThreshold(false);
796     fc.setAutoScaled(false);
797     assertEquals("By CSQ:AF", fc.getDescription());
798   
799     /*
800      * graduated colour by attribute, above threshold
801      */
802     fc.setAboveThreshold(true);
803     fc.setAutoScaled(false);
804     assertEquals("By CSQ:AF (> 12.5)",
805             fc.getDescription());
806   }
807 }