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()
78 //required for Windows, only when in batch mode?
80 List<SequenceFeature> sfs = seq.getSequenceFeatures();
81 for (SequenceFeature sf : sfs)
83 seq.deleteFeature(sf);
85 fr.findAllFeatures(true);
88 * reset all feature groups to visible
90 for (String group : fr.getGroups(false))
92 fr.setGroupVisibility(group, true);
95 fr.clearRenderOrder();
96 av.setShowSequenceFeatures(true);
99 @Test(groups = "Functional")
100 public void testFindFeatureColour_noFeatures()
102 av.setShowSequenceFeatures(false);
103 Color c = finder.findFeatureColour(Color.blue, seq, 10);
104 assertEquals(c, Color.blue);
106 av.setShowSequenceFeatures(true);
107 c = finder.findFeatureColour(Color.blue, seq, 10);
108 assertEquals(c, Color.blue);
111 @Test(groups = "Functional")
112 public void testFindFeatureColour_noFeaturesShown()
114 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
115 Float.NaN, "MetalGroup"));
117 av.setShowSequenceFeatures(false);
118 Color c = finder.findFeatureColour(Color.blue, seq, 10);
119 assertEquals(c, Color.blue);
122 @Test(groups = "Functional")
123 public void testFindFeatureColour_singleFeatureAtPosition()
125 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
126 Float.NaN, "MetalGroup"));
127 fr.setColour("Metal", new FeatureColour(Color.red));
129 av.setShowSequenceFeatures(true);
130 Color c = finder.findFeatureColour(Color.blue, seq, 10);
131 assertEquals(c, Color.red);
135 * feature colour at a gap is null (not white) - a user defined colour scheme
136 * can then provide a bespoke gap colour if configured to do so
138 @Test(groups = "Functional")
139 public void testFindFeatureColour_gapPosition()
141 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12, 0f,
143 fr.setColour("Metal", new FeatureColour(Color.red));
145 av.setShowSequenceFeatures(true);
146 Color c = finder.findFeatureColour(null, seq, 6);
150 @Test(groups = "Functional")
151 public void testFindFeatureColour_multipleFeaturesAtPositionNoTransparency()
154 * featuresAdded -> FeatureRendererModel.updateRenderOrder which adds any
155 * new features 'on top' (but reverses the order of any added features)
157 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
158 Float.NaN, "MetalGroup"));
159 FeatureColour red = new FeatureColour(Color.red);
160 fr.setColour("Metal", red);
162 seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
163 Float.NaN, "DomainGroup"));
164 FeatureColour green = new FeatureColour(Color.green);
165 fr.setColour("Domain", green);
167 av.setShowSequenceFeatures(true);
170 * expect Domain (green) to be rendered above Metal (red)
172 Color c = finder.findFeatureColour(Color.blue, seq, 10);
173 assertEquals(c, Color.green);
176 * now promote Metal above Domain
177 * - currently no way other than mimicking reordering of
178 * table in Feature Settings
180 FeatureSettingsBean[] data = new FeatureSettingsBean[2];
181 data[0] = new FeatureSettingsBean("Metal", red, null, true);
182 data[1] = new FeatureSettingsBean("Domain", green, null, true);
183 fr.setFeaturePriority(data);
184 c = finder.findFeatureColour(Color.blue, seq, 10);
185 assertEquals(c, Color.red);
188 * ..and turn off display of Metal
190 data[0] = new FeatureSettingsBean("Metal", red, null, false);
191 fr.setFeaturePriority(data);
192 c = finder.findFeatureColour(Color.blue, seq, 10);
193 assertEquals(c, Color.green);
196 @Test(groups = "Functional")
197 public void testFindFeatureColour_singleFeatureNotAtPosition()
199 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 8, 12,
200 Float.NaN, "MetalGroup"));
201 fr.setColour("Metal", new FeatureColour(Color.red));
203 av.setShowSequenceFeatures(true);
204 // column 2 = sequence position 3
205 Color c = finder.findFeatureColour(Color.blue, seq, 2);
206 assertEquals(c, Color.blue);
209 @Test(groups = "Functional")
210 public void testFindFeatureColour_featureTypeNotDisplayed()
212 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
213 Float.NaN, "MetalGroup"));
214 FeatureColour red = new FeatureColour(Color.red);
215 fr.setColour("Metal", red);
217 av.setShowSequenceFeatures(true);
218 Color c = finder.findFeatureColour(Color.blue, seq, 10);
219 assertEquals(c, Color.red);
222 * turn off display of Metal - is this the easiest way to do it??
224 FeatureSettingsBean[] data = new FeatureSettingsBean[1];
225 data[0] = new FeatureSettingsBean("Metal", red, null, false);
226 fr.setFeaturePriority(data);
227 c = finder.findFeatureColour(Color.blue, seq, 10);
228 assertEquals(c, Color.blue);
231 * turn display of Metal back on
233 data[0] = new FeatureSettingsBean("Metal", red, null, true);
234 fr.setFeaturePriority(data);
235 c = finder.findFeatureColour(Color.blue, seq, 10);
236 assertEquals(c, Color.red);
239 @Test(groups = "Functional")
240 public void testFindFeatureColour_featureGroupNotDisplayed()
242 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
243 Float.NaN, "MetalGroup"));
244 FeatureColour red = new FeatureColour(Color.red);
245 fr.setColour("Metal", red);
247 av.setShowSequenceFeatures(true);
248 Color c = finder.findFeatureColour(Color.blue, seq, 10);
249 assertEquals(c, Color.red);
252 * turn off display of MetalGroup
254 fr.setGroupVisibility("MetalGroup", false);
255 c = finder.findFeatureColour(Color.blue, seq, 10);
256 assertEquals(c, Color.blue);
259 * turn display of MetalGroup back on
261 fr.setGroupVisibility("MetalGroup", true);
262 c = finder.findFeatureColour(Color.blue, seq, 10);
263 assertEquals(c, Color.red);
266 @Test(groups = "Functional")
267 public void testFindFeatureColour_contactFeature()
270 * currently contact feature == type "Disulphide Bond" or "Disulfide Bond" !!
272 seq.addSequenceFeature(new SequenceFeature("Disulphide Bond",
273 "Contact", 2, 12, Float.NaN, "Disulphide"));
274 fr.setColour("Disulphide Bond", new FeatureColour(Color.red));
276 av.setShowSequenceFeatures(true);
279 * Contact positions are residues 2 and 12
280 * which are columns 1 and 14
281 * positions in between don't count for a contact feature!
283 Color c = finder.findFeatureColour(Color.blue, seq, 10);
284 assertEquals(c, Color.blue);
285 c = finder.findFeatureColour(Color.blue, seq, 8);
286 assertEquals(c, Color.blue);
287 c = finder.findFeatureColour(Color.blue, seq, 1);
288 assertEquals(c, Color.red);
289 c = finder.findFeatureColour(Color.blue, seq, 14);
290 assertEquals(c, Color.red);
293 @Test(groups = "Functional")
294 public void testFindFeatureAtEnd()
297 * terminal residue feature
299 seq.addSequenceFeature(new SequenceFeature("PDBRESNUM", "pdb res 1",
300 seq.getEnd(), seq.getEnd(), Float.NaN, "1seq.pdb"));
301 fr.setColour("PDBRESNUM", new FeatureColour(Color.red));
303 av.setShowSequenceFeatures(true);
306 * final column should have PDBRESNUM feature, the others not
308 Color c = finder.findFeatureColour(Color.blue, seq,
309 seq.getLength() - 2);
310 assertNotEquals(c, Color.red);
311 c = finder.findFeatureColour(Color.blue, seq, seq.getLength() - 1);
312 assertEquals(c, Color.red);
315 @Test(groups = "Functional")
316 public void testFindFeatureColour_graduatedFeatureColour()
318 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 2,
320 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 4,
322 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 7,
326 * graduated colour from 0 to 10
328 Color min = new Color(100, 50, 150);
329 Color max = new Color(200, 0, 100);
330 FeatureColourI fc = new FeatureColour(null, min, max, null, 0, 10);
331 fr.setColour("kd", fc);
333 av.setShowSequenceFeatures(true);
336 * position 2, column 1, score 0 - minimum colour in range
338 Color c = finder.findFeatureColour(Color.blue, seq, 1);
339 assertEquals(c, min);
342 * position 7, column 9, score 10 - maximum colour in range
344 c = finder.findFeatureColour(Color.blue, seq, 9);
345 assertEquals(c, max);
348 * position 4, column 3, score 5 - half way from min to max
350 c = finder.findFeatureColour(Color.blue, seq, 3);
351 assertEquals(c, new Color(150, 25, 125));
354 @Test(groups = "Functional")
355 public void testFindFeatureColour_transparencySingleFeature()
357 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
358 Float.NaN, "MetalGroup"));
359 FeatureColour red = new FeatureColour(Color.red);
360 fr.setColour("Metal", red);
362 av.setShowSequenceFeatures(true);
365 * the FeatureSettings transparency slider has range 0-70 which
366 * corresponds to a transparency value of 1 - 0.3
367 * A value of 0.4 gives a combination of
368 * 0.4 * red(255, 0, 0) + 0.6 * cyan(0, 255, 255) = (102, 153, 153)
370 fr.setTransparency(0.4f);
371 Color c = finder.findFeatureColour(Color.cyan, seq, 10);
372 assertEquals(c, new Color(102, 153, 153));
375 @Test(groups = "Functional")
376 public void testFindFeatureColour_transparencyTwoFeatures()
378 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
379 Float.NaN, "MetalGroup"));
380 FeatureColour red = new FeatureColour(Color.red);
381 fr.setColour("Metal", red);
383 seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
384 Float.NaN, "DomainGroup"));
385 FeatureColour green = new FeatureColour(Color.green);
386 fr.setColour("Domain", green);
388 av.setShowSequenceFeatures(true);
391 * Domain (green) rendered above Metal (red) above background (cyan)
392 * 1) 0.6 * red(255, 0, 0) + 0.4 * cyan(0, 255, 255) = (153, 102, 102)
393 * 2) 0.6* green(0, 255, 0) + 0.4 * (153, 102, 102) = (61, 194, 41) rounded
395 fr.setTransparency(0.6f);
396 Color c = finder.findFeatureColour(Color.cyan, seq, 10);
397 assertEquals(c, new Color(61, 194, 41));
400 * now promote Metal above Domain
401 * - currently no way other than mimicking reordering of
402 * table in Feature Settings
403 * Metal (red) rendered above Domain (green) above background (cyan)
404 * 1) 0.6 * green(0, 255, 0) + 0.4 * cyan(0, 255, 255) = (0, 255, 102)
405 * 2) 0.6* red(255, 0, 0) + 0.4 * (0, 255, 102) = (153, 102, 41) rounded
407 FeatureSettingsBean[] data = new FeatureSettingsBean[2];
408 data[0] = new FeatureSettingsBean("Metal", red, null, true);
409 data[1] = new FeatureSettingsBean("Domain", green, null, true);
410 fr.setFeaturePriority(data);
411 c = finder.findFeatureColour(Color.cyan, seq, 10);
412 assertEquals(c, new Color(153, 102, 41));
415 * ..and turn off display of Metal
416 * Domain (green) above background (pink)
417 * 0.6 * green(0, 255, 0) + 0.4 * pink(255, 175, 175) = (102, 223, 70)
419 data[0] = new FeatureSettingsBean("Metal", red, null, false);
420 fr.setFeaturePriority(data);
421 c = finder.findFeatureColour(Color.pink, seq, 10);
422 assertEquals(c, new Color(102, 223, 70));
425 @Test(groups = "Functional")
426 public void testNoFeaturesDisplayed()
429 * no features on alignment to render
431 assertTrue(finder.noFeaturesDisplayed());
435 * it will be automatically set visible but we leave
436 * the viewport configured not to show features
438 av.setShowSequenceFeatures(false);
439 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
440 Float.NaN, "MetalGroup"));
441 FeatureColour red = new FeatureColour(Color.red);
442 fr.setColour("Metal", red);
444 assertTrue(finder.noFeaturesDisplayed());
447 * turn on feature display
449 av.setShowSequenceFeatures(true);
450 assertFalse(finder.noFeaturesDisplayed());
453 * turn off display of Metal
455 FeatureSettingsBean[] data = new FeatureSettingsBean[1];
456 data[0] = new FeatureSettingsBean("Metal", red, null, false);
457 fr.setFeaturePriority(data);
458 assertTrue(finder.noFeaturesDisplayed());
461 * turn display of Metal back on
463 fr.setVisible("Metal");
464 assertFalse(finder.noFeaturesDisplayed());
467 * turn off MetalGroup - has no effect here since the group of a
468 * sequence feature instance is independent of its type
470 fr.setGroupVisibility("MetalGroup", false);
471 assertFalse(finder.noFeaturesDisplayed());
474 * a finder with no feature renderer
476 FeatureColourFinder finder2 = new FeatureColourFinder(null);
477 assertTrue(finder2.noFeaturesDisplayed());
480 @Test(groups = "Functional")
481 public void testFindFeatureColour_graduatedWithThreshold()
483 String kdFeature = "kd";
484 String metalFeature = "Metal";
485 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 2,
487 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 4,
489 seq.addSequenceFeature(new SequenceFeature(metalFeature, "Fe", 4, 4,
491 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 7,
495 * kd feature has graduated colour from 0 to 10
496 * above threshold value of 5
498 Color min = new Color(100, 50, 150);
499 Color max = new Color(200, 0, 100);
500 FeatureColourI fc = new FeatureColour(null, min, max, null, 0, 10);
501 fc.setAboveThreshold(true);
503 fr.setColour(kdFeature, fc);
504 FeatureColour green = new FeatureColour(Color.green);
505 fr.setColour(metalFeature, green);
509 * render order is kd above Metal
511 FeatureSettingsBean[] data = new FeatureSettingsBean[2];
512 data[0] = new FeatureSettingsBean(kdFeature, fc, null, true);
513 data[1] = new FeatureSettingsBean(metalFeature, green, null, true);
514 fr.setFeaturePriority(data);
516 av.setShowSequenceFeatures(true);
519 * position 2, column 1, score 0 - below threshold - default colour
521 Color c = finder.findFeatureColour(Color.blue, seq, 1);
522 assertEquals(c, Color.blue);
525 * position 4, column 3, score 5 - at threshold
526 * should return Green (colour of Metal feature)
528 c = finder.findFeatureColour(Color.blue, seq, 3);
529 assertEquals(c, Color.green);
532 * position 7, column 9, score 10 - maximum colour in range
534 c = finder.findFeatureColour(Color.blue, seq, 9);
535 assertEquals(c, max);
538 * now colour below threshold of 5
540 fc.setBelowThreshold(true);
543 * position 2, column 1, score 0 - min colour
545 c = finder.findFeatureColour(Color.blue, seq, 1);
546 assertEquals(c, min);
549 * position 4, column 3, score 5 - at threshold
550 * should return Green (colour of Metal feature)
552 c = finder.findFeatureColour(Color.blue, seq, 3);
553 assertEquals(c, Color.green);
556 * position 7, column 9, score 10 - above threshold - default colour
558 c = finder.findFeatureColour(Color.blue, seq, 9);
559 assertEquals(c, Color.blue);