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