1 package jalview.renderer.seqfeatures;
3 import static org.testng.Assert.assertEquals;
4 import static org.testng.Assert.assertFalse;
5 import static org.testng.Assert.assertNotEquals;
6 import static org.testng.Assert.assertNull;
7 import static org.testng.Assert.assertTrue;
9 import jalview.api.FeatureColourI;
10 import jalview.bin.Cache;
11 import jalview.datamodel.SequenceFeature;
12 import jalview.datamodel.SequenceI;
13 import jalview.gui.AlignFrame;
14 import jalview.gui.AlignViewport;
15 import jalview.gui.FeatureRenderer;
16 import jalview.io.DataSourceType;
17 import jalview.io.FileLoader;
18 import jalview.schemes.FeatureColour;
19 import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
21 import java.awt.Color;
22 import java.util.List;
24 import org.testng.annotations.BeforeMethod;
25 import org.testng.annotations.BeforeTest;
26 import org.testng.annotations.Test;
29 * Unit tests for feature colour determination, including but not limited to
31 * <li>gap position</li>
32 * <li>no features present</li>
33 * <li>features present but show features turned off</li>
34 * <li>features displayed but selected feature turned off</li>
35 * <li>features displayed but feature group turned off</li>
36 * <li>feature displayed but none at the specified position</li>
37 * <li>multiple features at position, with no transparency</li>
38 * <li>multiple features at position, with transparency</li>
39 * <li>score graduated feature colour</li>
40 * <li>contact feature start at the selected position</li>
41 * <li>contact feature end at the selected position</li>
42 * <li>contact feature straddling the selected position (not shown)</li>
45 public class FeatureColourFinderTest
47 private AlignViewport av;
49 private SequenceI seq;
51 private FeatureColourFinder finder;
53 private AlignFrame af;
55 private FeatureRenderer fr;
57 @BeforeTest(alwaysRun = true)
61 // aligned column 8 is sequence position 6
62 String s = ">s1\nABCDE---FGHIJKLMNOPQRSTUVWXYZ\n";
63 af = new FileLoader().LoadFileWaitTillLoaded(s,
64 DataSourceType.PASTE);
65 av = af.getViewport();
66 seq = av.getAlignment().getSequenceAt(0);
67 fr = af.getFeatureRenderer();
68 finder = new FeatureColourFinder(fr);
72 * Clear down any sequence features before each test (not as easy as it
75 @BeforeMethod(alwaysRun = true)
76 public void setUpBeforeTest()
79 * fudge for failure in test suite on Windows;
80 * without this call added, av.getAlignment() is null;
81 * root cause not known - AlignViewport.dispose() called??
85 List<SequenceFeature> sfs = seq.getSequenceFeatures();
86 for (SequenceFeature sf : sfs)
88 seq.deleteFeature(sf);
90 fr.findAllFeatures(true);
93 * reset all feature groups to visible
95 for (String group : fr.getGroups(false))
97 fr.setGroupVisibility(group, true);
100 fr.clearRenderOrder();
101 av.setShowSequenceFeatures(true);
104 @Test(groups = "Functional")
105 public void testFindFeatureColour_noFeatures()
107 av.setShowSequenceFeatures(false);
108 Color c = finder.findFeatureColour(Color.blue, seq, 10);
109 assertEquals(c, Color.blue);
111 av.setShowSequenceFeatures(true);
112 c = finder.findFeatureColour(Color.blue, seq, 10);
113 assertEquals(c, Color.blue);
116 @Test(groups = "Functional")
117 public void testFindFeatureColour_noFeaturesShown()
119 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
120 Float.NaN, "MetalGroup"));
122 av.setShowSequenceFeatures(false);
123 Color c = finder.findFeatureColour(Color.blue, seq, 10);
124 assertEquals(c, Color.blue);
127 @Test(groups = "Functional")
128 public void testFindFeatureColour_singleFeatureAtPosition()
130 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
131 Float.NaN, "MetalGroup"));
132 fr.setColour("Metal", new FeatureColour(Color.red));
134 av.setShowSequenceFeatures(true);
135 Color c = finder.findFeatureColour(Color.blue, seq, 10);
136 assertEquals(c, Color.red);
140 * feature colour at a gap is null (not white) - a user defined colour scheme
141 * can then provide a bespoke gap colour if configured to do so
143 @Test(groups = "Functional")
144 public void testFindFeatureColour_gapPosition()
146 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12, 0f,
148 fr.setColour("Metal", new FeatureColour(Color.red));
150 av.setShowSequenceFeatures(true);
151 Color c = finder.findFeatureColour(null, seq, 6);
155 @Test(groups = "Functional")
156 public void testFindFeatureColour_multipleFeaturesAtPositionNoTransparency()
159 * featuresAdded -> FeatureRendererModel.updateRenderOrder which adds any
160 * new features 'on top' (but reverses the order of any added features)
162 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
163 Float.NaN, "MetalGroup"));
164 FeatureColour red = new FeatureColour(Color.red);
165 fr.setColour("Metal", red);
167 seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
168 Float.NaN, "DomainGroup"));
169 FeatureColour green = new FeatureColour(Color.green);
170 fr.setColour("Domain", green);
172 av.setShowSequenceFeatures(true);
175 * expect Domain (green) to be rendered above Metal (red)
177 Color c = finder.findFeatureColour(Color.blue, seq, 10);
178 assertEquals(c, Color.green);
181 * now promote Metal above Domain
182 * - currently no way other than mimicking reordering of
183 * table in Feature Settings
185 FeatureSettingsBean[] data = new FeatureSettingsBean[2];
186 data[0] = new FeatureSettingsBean("Metal", red, null, true);
187 data[1] = new FeatureSettingsBean("Domain", green, null, true);
188 fr.setFeaturePriority(data);
189 c = finder.findFeatureColour(Color.blue, seq, 10);
190 assertEquals(c, Color.red);
193 * ..and turn off display of Metal
195 data[0] = new FeatureSettingsBean("Metal", red, null, false);
196 fr.setFeaturePriority(data);
197 c = finder.findFeatureColour(Color.blue, seq, 10);
198 assertEquals(c, Color.green);
201 @Test(groups = "Functional")
202 public void testFindFeatureColour_singleFeatureNotAtPosition()
204 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 8, 12,
205 Float.NaN, "MetalGroup"));
206 fr.setColour("Metal", new FeatureColour(Color.red));
208 av.setShowSequenceFeatures(true);
209 // column 2 = sequence position 3
210 Color c = finder.findFeatureColour(Color.blue, seq, 2);
211 assertEquals(c, Color.blue);
214 @Test(groups = "Functional")
215 public void testFindFeatureColour_featureTypeNotDisplayed()
217 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
218 Float.NaN, "MetalGroup"));
219 FeatureColour red = new FeatureColour(Color.red);
220 fr.setColour("Metal", red);
222 av.setShowSequenceFeatures(true);
223 Color c = finder.findFeatureColour(Color.blue, seq, 10);
224 assertEquals(c, Color.red);
227 * turn off display of Metal - is this the easiest way to do it??
229 FeatureSettingsBean[] data = new FeatureSettingsBean[1];
230 data[0] = new FeatureSettingsBean("Metal", red, null, false);
231 fr.setFeaturePriority(data);
232 c = finder.findFeatureColour(Color.blue, seq, 10);
233 assertEquals(c, Color.blue);
236 * turn display of Metal back on
238 data[0] = new FeatureSettingsBean("Metal", red, null, true);
239 fr.setFeaturePriority(data);
240 c = finder.findFeatureColour(Color.blue, seq, 10);
241 assertEquals(c, Color.red);
244 @Test(groups = "Functional")
245 public void testFindFeatureColour_featureGroupNotDisplayed()
247 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
248 Float.NaN, "MetalGroup"));
249 FeatureColour red = new FeatureColour(Color.red);
250 fr.setColour("Metal", red);
252 av.setShowSequenceFeatures(true);
253 Color c = finder.findFeatureColour(Color.blue, seq, 10);
254 assertEquals(c, Color.red);
257 * turn off display of MetalGroup
259 fr.setGroupVisibility("MetalGroup", false);
260 c = finder.findFeatureColour(Color.blue, seq, 10);
261 assertEquals(c, Color.blue);
264 * turn display of MetalGroup back on
266 fr.setGroupVisibility("MetalGroup", true);
267 c = finder.findFeatureColour(Color.blue, seq, 10);
268 assertEquals(c, Color.red);
271 @Test(groups = "Functional")
272 public void testFindFeatureColour_contactFeature()
275 * currently contact feature == type "Disulphide Bond" or "Disulfide Bond" !!
277 seq.addSequenceFeature(new SequenceFeature("Disulphide Bond",
278 "Contact", 2, 12, Float.NaN, "Disulphide"));
279 fr.setColour("Disulphide Bond", new FeatureColour(Color.red));
281 av.setShowSequenceFeatures(true);
284 * Contact positions are residues 2 and 12
285 * which are columns 1 and 14
286 * positions in between don't count for a contact feature!
288 Color c = finder.findFeatureColour(Color.blue, seq, 10);
289 assertEquals(c, Color.blue);
290 c = finder.findFeatureColour(Color.blue, seq, 8);
291 assertEquals(c, Color.blue);
292 c = finder.findFeatureColour(Color.blue, seq, 1);
293 assertEquals(c, Color.red);
294 c = finder.findFeatureColour(Color.blue, seq, 14);
295 assertEquals(c, Color.red);
298 @Test(groups = "Functional")
299 public void testFindFeatureAtEnd()
302 * terminal residue feature
304 seq.addSequenceFeature(new SequenceFeature("PDBRESNUM", "pdb res 1",
305 seq.getEnd(), seq.getEnd(), Float.NaN, "1seq.pdb"));
306 fr.setColour("PDBRESNUM", new FeatureColour(Color.red));
308 av.setShowSequenceFeatures(true);
311 * final column should have PDBRESNUM feature, the others not
313 Color c = finder.findFeatureColour(Color.blue, seq,
314 seq.getLength() - 2);
315 assertNotEquals(c, Color.red);
316 c = finder.findFeatureColour(Color.blue, seq, seq.getLength() - 1);
317 assertEquals(c, Color.red);
320 @Test(groups = "Functional")
321 public void testFindFeatureColour_graduatedFeatureColour()
323 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 2,
325 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 4,
327 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 7,
331 * graduated colour from 0 to 10
333 Color min = new Color(100, 50, 150);
334 Color max = new Color(200, 0, 100);
335 FeatureColourI fc = new FeatureColour(null, min, max, null, 0, 10);
336 fr.setColour("kd", fc);
338 av.setShowSequenceFeatures(true);
341 * position 2, column 1, score 0 - minimum colour in range
343 Color c = finder.findFeatureColour(Color.blue, seq, 1);
344 assertEquals(c, min);
347 * position 7, column 9, score 10 - maximum colour in range
349 c = finder.findFeatureColour(Color.blue, seq, 9);
350 assertEquals(c, max);
353 * position 4, column 3, score 5 - half way from min to max
355 c = finder.findFeatureColour(Color.blue, seq, 3);
356 assertEquals(c, new Color(150, 25, 125));
359 @Test(groups = "Functional")
360 public void testFindFeatureColour_transparencySingleFeature()
362 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
363 Float.NaN, "MetalGroup"));
364 FeatureColour red = new FeatureColour(Color.red);
365 fr.setColour("Metal", red);
367 av.setShowSequenceFeatures(true);
370 * the FeatureSettings transparency slider has range 0-70 which
371 * corresponds to a transparency value of 1 - 0.3
372 * A value of 0.4 gives a combination of
373 * 0.4 * red(255, 0, 0) + 0.6 * cyan(0, 255, 255) = (102, 153, 153)
375 fr.setTransparency(0.4f);
376 Color c = finder.findFeatureColour(Color.cyan, seq, 10);
377 assertEquals(c, new Color(102, 153, 153));
380 @Test(groups = "Functional")
381 public void testFindFeatureColour_transparencyTwoFeatures()
383 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
384 Float.NaN, "MetalGroup"));
385 FeatureColour red = new FeatureColour(Color.red);
386 fr.setColour("Metal", red);
388 seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
389 Float.NaN, "DomainGroup"));
390 FeatureColour green = new FeatureColour(Color.green);
391 fr.setColour("Domain", green);
393 av.setShowSequenceFeatures(true);
396 * Domain (green) rendered above Metal (red) above background (cyan)
397 * 1) 0.6 * red(255, 0, 0) + 0.4 * cyan(0, 255, 255) = (153, 102, 102)
398 * 2) 0.6* green(0, 255, 0) + 0.4 * (153, 102, 102) = (61, 194, 41) rounded
400 fr.setTransparency(0.6f);
401 Color c = finder.findFeatureColour(Color.cyan, seq, 10);
402 assertEquals(c, new Color(61, 194, 41));
405 * now promote Metal above Domain
406 * - currently no way other than mimicking reordering of
407 * table in Feature Settings
408 * Metal (red) rendered above Domain (green) above background (cyan)
409 * 1) 0.6 * green(0, 255, 0) + 0.4 * cyan(0, 255, 255) = (0, 255, 102)
410 * 2) 0.6* red(255, 0, 0) + 0.4 * (0, 255, 102) = (153, 102, 41) rounded
412 FeatureSettingsBean[] data = new FeatureSettingsBean[2];
413 data[0] = new FeatureSettingsBean("Metal", red, null, true);
414 data[1] = new FeatureSettingsBean("Domain", green, null, true);
415 fr.setFeaturePriority(data);
416 c = finder.findFeatureColour(Color.cyan, seq, 10);
417 assertEquals(c, new Color(153, 102, 41));
420 * ..and turn off display of Metal
421 * Domain (green) above background (pink)
422 * 0.6 * green(0, 255, 0) + 0.4 * pink(255, 175, 175) = (102, 223, 70)
424 data[0] = new FeatureSettingsBean("Metal", red, null, false);
425 fr.setFeaturePriority(data);
426 c = finder.findFeatureColour(Color.pink, seq, 10);
427 assertEquals(c, new Color(102, 223, 70));
430 @Test(groups = "Functional")
431 public void testNoFeaturesDisplayed()
434 * no features on alignment to render
436 assertTrue(finder.noFeaturesDisplayed());
440 * it will be automatically set visible but we leave
441 * the viewport configured not to show features
443 av.setShowSequenceFeatures(false);
444 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
445 Float.NaN, "MetalGroup"));
446 FeatureColour red = new FeatureColour(Color.red);
447 fr.setColour("Metal", red);
449 assertTrue(finder.noFeaturesDisplayed());
452 * turn on feature display
454 av.setShowSequenceFeatures(true);
455 assertFalse(finder.noFeaturesDisplayed());
458 * turn off display of Metal
460 FeatureSettingsBean[] data = new FeatureSettingsBean[1];
461 data[0] = new FeatureSettingsBean("Metal", red, null, false);
462 fr.setFeaturePriority(data);
463 assertTrue(finder.noFeaturesDisplayed());
466 * turn display of Metal back on
468 fr.setVisible("Metal");
469 assertFalse(finder.noFeaturesDisplayed());
472 * turn off MetalGroup - has no effect here since the group of a
473 * sequence feature instance is independent of its type
475 fr.setGroupVisibility("MetalGroup", false);
476 assertFalse(finder.noFeaturesDisplayed());
479 * a finder with no feature renderer
481 FeatureColourFinder finder2 = new FeatureColourFinder(null);
482 assertTrue(finder2.noFeaturesDisplayed());
485 @Test(groups = "Functional")
486 public void testFindFeatureColour_graduatedWithThreshold()
488 String kdFeature = "kd";
489 String metalFeature = "Metal";
490 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 2,
492 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 4,
494 seq.addSequenceFeature(new SequenceFeature(metalFeature, "Fe", 4, 4,
496 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 7,
500 * kd feature has graduated colour from 0 to 10
501 * above threshold value of 5
503 Color min = new Color(100, 50, 150);
504 Color max = new Color(200, 0, 100);
505 FeatureColourI fc = new FeatureColour(null, min, max, null, 0, 10);
506 fc.setAboveThreshold(true);
508 fr.setColour(kdFeature, fc);
509 FeatureColour green = new FeatureColour(Color.green);
510 fr.setColour(metalFeature, green);
514 * render order is kd above Metal
516 FeatureSettingsBean[] data = new FeatureSettingsBean[2];
517 data[0] = new FeatureSettingsBean(kdFeature, fc, null, true);
518 data[1] = new FeatureSettingsBean(metalFeature, green, null, true);
519 fr.setFeaturePriority(data);
521 av.setShowSequenceFeatures(true);
524 * position 2, column 1, score 0 - below threshold - default colour
526 Color c = finder.findFeatureColour(Color.blue, seq, 1);
527 assertEquals(c, Color.blue);
530 * position 4, column 3, score 5 - at threshold
531 * should return Green (colour of Metal feature)
533 c = finder.findFeatureColour(Color.blue, seq, 3);
534 assertEquals(c, Color.green);
537 * position 7, column 9, score 10 - maximum colour in range
539 c = finder.findFeatureColour(Color.blue, seq, 9);
540 assertEquals(c, max);
543 * now colour below threshold of 5
545 fc.setBelowThreshold(true);
548 * position 2, column 1, score 0 - min colour
550 c = finder.findFeatureColour(Color.blue, seq, 1);
551 assertEquals(c, min);
554 * position 4, column 3, score 5 - at threshold
555 * should return Green (colour of Metal feature)
557 c = finder.findFeatureColour(Color.blue, seq, 3);
558 assertEquals(c, Color.green);
561 * position 7, column 9, score 10 - above threshold - default colour
563 c = finder.findFeatureColour(Color.blue, seq, 9);
564 assertEquals(c, Color.blue);