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.datamodel.SequenceFeature;
11 import jalview.datamodel.SequenceI;
12 import jalview.gui.AlignFrame;
13 import jalview.gui.AlignViewport;
14 import jalview.gui.FeatureRenderer;
15 import jalview.io.DataSourceType;
16 import jalview.io.FileLoader;
17 import jalview.schemes.FeatureColour;
19 import java.awt.Color;
20 import java.util.List;
22 import org.testng.annotations.BeforeMethod;
23 import org.testng.annotations.BeforeTest;
24 import org.testng.annotations.Test;
27 * Unit tests for feature colour determination, including but not limited to
29 * <li>gap position</li>
30 * <li>no features present</li>
31 * <li>features present but show features turned off</li>
32 * <li>features displayed but selected feature turned off</li>
33 * <li>features displayed but feature group turned off</li>
34 * <li>feature displayed but none at the specified position</li>
35 * <li>multiple features at position, with no transparency</li>
36 * <li>multiple features at position, with transparency</li>
37 * <li>score graduated feature colour</li>
38 * <li>contact feature start at the selected position</li>
39 * <li>contact feature end at the selected position</li>
40 * <li>contact feature straddling the selected position (not shown)</li>
43 public class FeatureColourFinderTest
45 private AlignViewport av;
47 private SequenceI seq;
49 private FeatureColourFinder finder;
51 private AlignFrame af;
53 private FeatureRenderer fr;
55 @BeforeTest(alwaysRun = true)
58 // aligned column 8 is sequence position 6
59 String s = ">s1\nABCDE---FGHIJKLMNOPQRSTUVWXYZ\n";
60 af = new FileLoader().LoadFileWaitTillLoaded(s,
61 DataSourceType.PASTE);
62 av = af.getViewport();
63 seq = av.getAlignment().getSequenceAt(0);
64 fr = af.getFeatureRenderer();
65 finder = new FeatureColourFinder(fr);
69 * Clear down any sequence features before each test (not as easy as it
72 @BeforeMethod(alwaysRun = true)
73 public void setUpBeforeTest()
75 List<SequenceFeature> sfs = seq.getSequenceFeatures();
76 for (SequenceFeature sf : sfs)
78 seq.deleteFeature(sf);
80 fr.findAllFeatures(true);
83 * reset all feature groups to visible
85 for (String group : fr.getGroups(false))
87 fr.setGroupVisibility(group, true);
90 fr.clearRenderOrder();
91 av.setShowSequenceFeatures(true);
94 @Test(groups = "Functional")
95 public void testFindFeatureColour_noFeatures()
97 av.setShowSequenceFeatures(false);
98 Color c = finder.findFeatureColour(Color.blue, seq, 10);
99 assertEquals(c, Color.blue);
101 av.setShowSequenceFeatures(true);
102 c = finder.findFeatureColour(Color.blue, seq, 10);
103 assertEquals(c, Color.blue);
106 @Test(groups = "Functional")
107 public void testFindFeatureColour_noFeaturesShown()
109 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
110 Float.NaN, "MetalGroup"));
112 av.setShowSequenceFeatures(false);
113 Color c = finder.findFeatureColour(Color.blue, seq, 10);
114 assertEquals(c, Color.blue);
117 @Test(groups = "Functional")
118 public void testFindFeatureColour_singleFeatureAtPosition()
120 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
121 Float.NaN, "MetalGroup"));
122 fr.setColour("Metal", new FeatureColour(Color.red));
124 av.setShowSequenceFeatures(true);
125 Color c = finder.findFeatureColour(Color.blue, seq, 10);
126 assertEquals(c, Color.red);
130 * feature colour at a gap is null (not white) - a user defined colour scheme
131 * can then provide a bespoke gap colour if configured to do so
133 @Test(groups = "Functional")
134 public void testFindFeatureColour_gapPosition()
136 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12, 0f,
138 fr.setColour("Metal", new FeatureColour(Color.red));
140 av.setShowSequenceFeatures(true);
141 Color c = finder.findFeatureColour(null, seq, 6);
145 @Test(groups = "Functional")
146 public void testFindFeatureColour_multipleFeaturesAtPositionNoTransparency()
149 * featuresAdded -> FeatureRendererModel.updateRenderOrder which adds any
150 * new features 'on top' (but reverses the order of any added features)
152 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
153 Float.NaN, "MetalGroup"));
154 FeatureColour red = new FeatureColour(Color.red);
155 fr.setColour("Metal", red);
157 seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
158 Float.NaN, "DomainGroup"));
159 FeatureColour green = new FeatureColour(Color.green);
160 fr.setColour("Domain", green);
162 av.setShowSequenceFeatures(true);
165 * expect Domain (green) to be rendered above Metal (red)
167 Color c = finder.findFeatureColour(Color.blue, seq, 10);
168 assertEquals(c, Color.green);
171 * now promote Metal above Domain
172 * - currently no way other than mimicking reordering of
173 * table in Feature Settings
175 Object[][] data = new Object[2][];
176 data[0] = new Object[] { "Metal", red, true };
177 data[1] = new Object[] { "Domain", green, true };
178 fr.setFeaturePriority(data);
179 c = finder.findFeatureColour(Color.blue, seq, 10);
180 assertEquals(c, Color.red);
183 * ..and turn off display of Metal
186 fr.setFeaturePriority(data);
187 c = finder.findFeatureColour(Color.blue, seq, 10);
188 assertEquals(c, Color.green);
191 @Test(groups = "Functional")
192 public void testFindFeatureColour_singleFeatureNotAtPosition()
194 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 8, 12,
195 Float.NaN, "MetalGroup"));
196 fr.setColour("Metal", new FeatureColour(Color.red));
198 av.setShowSequenceFeatures(true);
199 // column 2 = sequence position 3
200 Color c = finder.findFeatureColour(Color.blue, seq, 2);
201 assertEquals(c, Color.blue);
204 @Test(groups = "Functional")
205 public void testFindFeatureColour_featureTypeNotDisplayed()
207 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
208 Float.NaN, "MetalGroup"));
209 FeatureColour red = new FeatureColour(Color.red);
210 fr.setColour("Metal", red);
212 av.setShowSequenceFeatures(true);
213 Color c = finder.findFeatureColour(Color.blue, seq, 10);
214 assertEquals(c, Color.red);
217 * turn off display of Metal - is this the easiest way to do it??
219 Object[][] data = new Object[1][];
220 data[0] = new Object[] { "Metal", red, false };
221 fr.setFeaturePriority(data);
222 c = finder.findFeatureColour(Color.blue, seq, 10);
223 assertEquals(c, Color.blue);
226 * turn display of Metal back on
228 data[0] = new Object[] { "Metal", red, true };
229 fr.setFeaturePriority(data);
230 c = finder.findFeatureColour(Color.blue, seq, 10);
231 assertEquals(c, Color.red);
234 @Test(groups = "Functional")
235 public void testFindFeatureColour_featureGroupNotDisplayed()
237 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
238 Float.NaN, "MetalGroup"));
239 FeatureColour red = new FeatureColour(Color.red);
240 fr.setColour("Metal", red);
242 av.setShowSequenceFeatures(true);
243 Color c = finder.findFeatureColour(Color.blue, seq, 10);
244 assertEquals(c, Color.red);
247 * turn off display of MetalGroup
249 fr.setGroupVisibility("MetalGroup", false);
250 c = finder.findFeatureColour(Color.blue, seq, 10);
251 assertEquals(c, Color.blue);
254 * turn display of MetalGroup back on
256 fr.setGroupVisibility("MetalGroup", true);
257 c = finder.findFeatureColour(Color.blue, seq, 10);
258 assertEquals(c, Color.red);
261 @Test(groups = "Functional")
262 public void testFindFeatureColour_contactFeature()
265 * currently contact feature == type "Disulphide Bond" or "Disulfide Bond" !!
267 seq.addSequenceFeature(new SequenceFeature("Disulphide Bond",
268 "Contact", 2, 12, Float.NaN, "Disulphide"));
269 fr.setColour("Disulphide Bond", new FeatureColour(Color.red));
271 av.setShowSequenceFeatures(true);
274 * Contact positions are residues 2 and 12
275 * which are columns 1 and 14
276 * positions in between don't count for a contact feature!
278 Color c = finder.findFeatureColour(Color.blue, seq, 10);
279 assertEquals(c, Color.blue);
280 c = finder.findFeatureColour(Color.blue, seq, 8);
281 assertEquals(c, Color.blue);
282 c = finder.findFeatureColour(Color.blue, seq, 1);
283 assertEquals(c, Color.red);
284 c = finder.findFeatureColour(Color.blue, seq, 14);
285 assertEquals(c, Color.red);
288 @Test(groups = "Functional")
289 public void testFindFeatureAtEnd()
292 * terminal residue feature
294 seq.addSequenceFeature(new SequenceFeature("PDBRESNUM", "pdb res 1",
295 seq.getEnd(), seq.getEnd(), Float.NaN, "1seq.pdb"));
296 fr.setColour("PDBRESNUM", new FeatureColour(Color.red));
298 av.setShowSequenceFeatures(true);
301 * final column should have PDBRESNUM feature, the others not
303 Color c = finder.findFeatureColour(Color.blue, seq,
304 seq.getLength() - 2);
305 assertNotEquals(c, Color.red);
306 c = finder.findFeatureColour(Color.blue, seq, seq.getLength() - 1);
307 assertEquals(c, Color.red);
310 @Test(groups = "Functional")
311 public void testFindFeatureColour_graduatedFeatureColour()
313 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 2,
315 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 4,
317 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 7,
321 * graduated colour from 0 to 10
323 Color min = new Color(100, 50, 150);
324 Color max = new Color(200, 0, 100);
325 FeatureColourI fc = new FeatureColour(min, max, 0, 10);
326 fr.setColour("kd", fc);
328 av.setShowSequenceFeatures(true);
331 * position 2, column 1, score 0 - minimum colour in range
333 Color c = finder.findFeatureColour(Color.blue, seq, 1);
334 assertEquals(c, min);
337 * position 7, column 9, score 10 - maximum colour in range
339 c = finder.findFeatureColour(Color.blue, seq, 9);
340 assertEquals(c, max);
343 * position 4, column 3, score 5 - half way from min to max
345 c = finder.findFeatureColour(Color.blue, seq, 3);
346 assertEquals(c, new Color(150, 25, 125));
349 @Test(groups = "Functional")
350 public void testFindFeatureColour_transparencySingleFeature()
352 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
353 Float.NaN, "MetalGroup"));
354 FeatureColour red = new FeatureColour(Color.red);
355 fr.setColour("Metal", red);
357 av.setShowSequenceFeatures(true);
360 * the FeatureSettings transparency slider has range 0-70 which
361 * corresponds to a transparency value of 1 - 0.3
362 * A value of 0.4 gives a combination of
363 * 0.4 * red(255, 0, 0) + 0.6 * cyan(0, 255, 255) = (102, 153, 153)
365 fr.setTransparency(0.4f);
366 Color c = finder.findFeatureColour(Color.cyan, seq, 10);
367 assertEquals(c, new Color(102, 153, 153));
370 @Test(groups = "Functional")
371 public void testFindFeatureColour_transparencyTwoFeatures()
373 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
374 Float.NaN, "MetalGroup"));
375 FeatureColour red = new FeatureColour(Color.red);
376 fr.setColour("Metal", red);
378 seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
379 Float.NaN, "DomainGroup"));
380 FeatureColour green = new FeatureColour(Color.green);
381 fr.setColour("Domain", green);
383 av.setShowSequenceFeatures(true);
386 * Domain (green) rendered above Metal (red) above background (cyan)
387 * 1) 0.6 * red(255, 0, 0) + 0.4 * cyan(0, 255, 255) = (153, 102, 102)
388 * 2) 0.6* green(0, 255, 0) + 0.4 * (153, 102, 102) = (61, 194, 41) rounded
390 fr.setTransparency(0.6f);
391 Color c = finder.findFeatureColour(Color.cyan, seq, 10);
392 assertEquals(c, new Color(61, 194, 41));
395 * now promote Metal above Domain
396 * - currently no way other than mimicking reordering of
397 * table in Feature Settings
398 * Metal (red) rendered above Domain (green) above background (cyan)
399 * 1) 0.6 * green(0, 255, 0) + 0.4 * cyan(0, 255, 255) = (0, 255, 102)
400 * 2) 0.6* red(255, 0, 0) + 0.4 * (0, 255, 102) = (153, 102, 41) rounded
402 Object[][] data = new Object[2][];
403 data[0] = new Object[] { "Metal", red, true };
404 data[1] = new Object[] { "Domain", green, true };
405 fr.setFeaturePriority(data);
406 c = finder.findFeatureColour(Color.cyan, seq, 10);
407 assertEquals(c, new Color(153, 102, 41));
410 * ..and turn off display of Metal
411 * Domain (green) above background (pink)
412 * 0.6 * green(0, 255, 0) + 0.4 * pink(255, 175, 175) = (102, 223, 70)
415 fr.setFeaturePriority(data);
416 c = finder.findFeatureColour(Color.pink, seq, 10);
417 assertEquals(c, new Color(102, 223, 70));
420 @Test(groups = "Functional")
421 public void testNoFeaturesDisplayed()
424 * no features on alignment to render
426 assertTrue(finder.noFeaturesDisplayed());
430 * it will be automatically set visible but we leave
431 * the viewport configured not to show features
433 av.setShowSequenceFeatures(false);
434 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
435 Float.NaN, "MetalGroup"));
436 FeatureColour red = new FeatureColour(Color.red);
437 fr.setColour("Metal", red);
439 assertTrue(finder.noFeaturesDisplayed());
442 * turn on feature display
444 av.setShowSequenceFeatures(true);
445 assertFalse(finder.noFeaturesDisplayed());
448 * turn off display of Metal
450 Object[][] data = new Object[1][];
451 data[0] = new Object[] { "Metal", red, false };
452 fr.setFeaturePriority(data);
453 assertTrue(finder.noFeaturesDisplayed());
456 * turn display of Metal back on
458 fr.setVisible("Metal");
459 assertFalse(finder.noFeaturesDisplayed());
462 * turn off MetalGroup - has no effect here since the group of a
463 * sequence feature instance is independent of its type
465 fr.setGroupVisibility("MetalGroup", false);
466 assertFalse(finder.noFeaturesDisplayed());
469 * a finder with no feature renderer
471 FeatureColourFinder finder2 = new FeatureColourFinder(null);
472 assertTrue(finder2.noFeaturesDisplayed());
475 @Test(groups = "Functional")
476 public void testFindFeatureColour_graduatedWithThreshold()
478 String kdFeature = "kd";
479 String metalFeature = "Metal";
480 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 2,
482 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 4,
484 seq.addSequenceFeature(new SequenceFeature(metalFeature, "Fe", 4, 4,
486 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 7,
490 * kd feature has graduated colour from 0 to 10
491 * above threshold value of 5
493 Color min = new Color(100, 50, 150);
494 Color max = new Color(200, 0, 100);
495 FeatureColourI fc = new FeatureColour(min, max, 0, 10);
496 fc.setAboveThreshold(true);
498 fr.setColour(kdFeature, fc);
499 FeatureColour green = new FeatureColour(Color.green);
500 fr.setColour(metalFeature, green);
504 * render order is kd above Metal
506 Object[][] data = new Object[2][];
507 data[0] = new Object[] { kdFeature, fc, true };
508 data[1] = new Object[] { metalFeature, green, true };
509 fr.setFeaturePriority(data);
511 av.setShowSequenceFeatures(true);
514 * position 2, column 1, score 0 - below threshold - default colour
516 Color c = finder.findFeatureColour(Color.blue, seq, 1);
517 assertEquals(c, Color.blue);
520 * position 4, column 3, score 5 - at threshold
521 * should return Green (colour of Metal feature)
523 c = finder.findFeatureColour(Color.blue, seq, 3);
524 assertEquals(c, Color.green);
527 * position 7, column 9, score 10 - maximum colour in range
529 c = finder.findFeatureColour(Color.blue, seq, 9);
530 assertEquals(c, max);
533 * now colour below threshold of 5
535 fc.setBelowThreshold(true);
538 * position 2, column 1, score 0 - min colour
540 c = finder.findFeatureColour(Color.blue, seq, 1);
541 assertEquals(c, min);
544 * position 4, column 3, score 5 - at threshold
545 * should return Green (colour of Metal feature)
547 c = finder.findFeatureColour(Color.blue, seq, 3);
548 assertEquals(c, Color.green);
551 * position 7, column 9, score 10 - above threshold - default colour
553 c = finder.findFeatureColour(Color.blue, seq, 9);
554 assertEquals(c, Color.blue);