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 List<SequenceFeature> sfs = seq.getSequenceFeatures();
79 for (SequenceFeature sf : sfs)
81 seq.deleteFeature(sf);
83 fr.findAllFeatures(true);
86 * reset all feature groups to visible
88 for (String group : fr.getGroups(false))
90 fr.setGroupVisibility(group, true);
93 fr.clearRenderOrder();
94 av.setShowSequenceFeatures(true);
97 @Test(groups = "Functional")
98 public void testFindFeatureColour_noFeatures()
100 av.setShowSequenceFeatures(false);
101 Color c = finder.findFeatureColour(Color.blue, seq, 10);
102 assertEquals(c, Color.blue);
104 av.setShowSequenceFeatures(true);
105 c = finder.findFeatureColour(Color.blue, seq, 10);
106 assertEquals(c, Color.blue);
109 @Test(groups = "Functional")
110 public void testFindFeatureColour_noFeaturesShown()
112 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
113 Float.NaN, "MetalGroup"));
115 av.setShowSequenceFeatures(false);
116 Color c = finder.findFeatureColour(Color.blue, seq, 10);
117 assertEquals(c, Color.blue);
120 @Test(groups = "Functional")
121 public void testFindFeatureColour_singleFeatureAtPosition()
123 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
124 Float.NaN, "MetalGroup"));
125 fr.setColour("Metal", new FeatureColour(Color.red));
127 av.setShowSequenceFeatures(true);
128 Color c = finder.findFeatureColour(Color.blue, seq, 10);
129 assertEquals(c, Color.red);
133 * feature colour at a gap is null (not white) - a user defined colour scheme
134 * can then provide a bespoke gap colour if configured to do so
136 @Test(groups = "Functional")
137 public void testFindFeatureColour_gapPosition()
139 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12, 0f,
141 fr.setColour("Metal", new FeatureColour(Color.red));
143 av.setShowSequenceFeatures(true);
144 Color c = finder.findFeatureColour(null, seq, 6);
148 @Test(groups = "Functional")
149 public void testFindFeatureColour_multipleFeaturesAtPositionNoTransparency()
152 * featuresAdded -> FeatureRendererModel.updateRenderOrder which adds any
153 * new features 'on top' (but reverses the order of any added features)
155 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
156 Float.NaN, "MetalGroup"));
157 FeatureColour red = new FeatureColour(Color.red);
158 fr.setColour("Metal", red);
160 seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
161 Float.NaN, "DomainGroup"));
162 FeatureColour green = new FeatureColour(Color.green);
163 fr.setColour("Domain", green);
165 av.setShowSequenceFeatures(true);
168 * expect Domain (green) to be rendered above Metal (red)
170 Color c = finder.findFeatureColour(Color.blue, seq, 10);
171 assertEquals(c, Color.green);
174 * now promote Metal above Domain
175 * - currently no way other than mimicking reordering of
176 * table in Feature Settings
178 FeatureSettingsBean[] data = new FeatureSettingsBean[2];
179 data[0] = new FeatureSettingsBean("Metal", red, null, true);
180 data[1] = new FeatureSettingsBean("Domain", green, null, true);
181 fr.setFeaturePriority(data);
182 c = finder.findFeatureColour(Color.blue, seq, 10);
183 assertEquals(c, Color.red);
186 * ..and turn off display of Metal
188 data[0] = new FeatureSettingsBean("Metal", red, null, false);
189 fr.setFeaturePriority(data);
190 c = finder.findFeatureColour(Color.blue, seq, 10);
191 assertEquals(c, Color.green);
194 @Test(groups = "Functional")
195 public void testFindFeatureColour_singleFeatureNotAtPosition()
197 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 8, 12,
198 Float.NaN, "MetalGroup"));
199 fr.setColour("Metal", new FeatureColour(Color.red));
201 av.setShowSequenceFeatures(true);
202 // column 2 = sequence position 3
203 Color c = finder.findFeatureColour(Color.blue, seq, 2);
204 assertEquals(c, Color.blue);
207 @Test(groups = "Functional")
208 public void testFindFeatureColour_featureTypeNotDisplayed()
210 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
211 Float.NaN, "MetalGroup"));
212 FeatureColour red = new FeatureColour(Color.red);
213 fr.setColour("Metal", red);
215 av.setShowSequenceFeatures(true);
216 Color c = finder.findFeatureColour(Color.blue, seq, 10);
217 assertEquals(c, Color.red);
220 * turn off display of Metal - is this the easiest way to do it??
222 FeatureSettingsBean[] data = new FeatureSettingsBean[1];
223 data[0] = new FeatureSettingsBean("Metal", red, null, false);
224 fr.setFeaturePriority(data);
225 c = finder.findFeatureColour(Color.blue, seq, 10);
226 assertEquals(c, Color.blue);
229 * turn display of Metal back on
231 data[0] = new FeatureSettingsBean("Metal", red, null, true);
232 fr.setFeaturePriority(data);
233 c = finder.findFeatureColour(Color.blue, seq, 10);
234 assertEquals(c, Color.red);
237 @Test(groups = "Functional")
238 public void testFindFeatureColour_featureGroupNotDisplayed()
240 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
241 Float.NaN, "MetalGroup"));
242 FeatureColour red = new FeatureColour(Color.red);
243 fr.setColour("Metal", red);
245 av.setShowSequenceFeatures(true);
246 Color c = finder.findFeatureColour(Color.blue, seq, 10);
247 assertEquals(c, Color.red);
250 * turn off display of MetalGroup
252 fr.setGroupVisibility("MetalGroup", false);
253 c = finder.findFeatureColour(Color.blue, seq, 10);
254 assertEquals(c, Color.blue);
257 * turn display of MetalGroup back on
259 fr.setGroupVisibility("MetalGroup", true);
260 c = finder.findFeatureColour(Color.blue, seq, 10);
261 assertEquals(c, Color.red);
264 @Test(groups = "Functional")
265 public void testFindFeatureColour_contactFeature()
268 * currently contact feature == type "Disulphide Bond" or "Disulfide Bond" !!
270 seq.addSequenceFeature(new SequenceFeature("Disulphide Bond",
271 "Contact", 2, 12, Float.NaN, "Disulphide"));
272 fr.setColour("Disulphide Bond", new FeatureColour(Color.red));
274 av.setShowSequenceFeatures(true);
277 * Contact positions are residues 2 and 12
278 * which are columns 1 and 14
279 * positions in between don't count for a contact feature!
281 Color c = finder.findFeatureColour(Color.blue, seq, 10);
282 assertEquals(c, Color.blue);
283 c = finder.findFeatureColour(Color.blue, seq, 8);
284 assertEquals(c, Color.blue);
285 c = finder.findFeatureColour(Color.blue, seq, 1);
286 assertEquals(c, Color.red);
287 c = finder.findFeatureColour(Color.blue, seq, 14);
288 assertEquals(c, Color.red);
291 @Test(groups = "Functional")
292 public void testFindFeatureAtEnd()
295 * terminal residue feature
297 seq.addSequenceFeature(new SequenceFeature("PDBRESNUM", "pdb res 1",
298 seq.getEnd(), seq.getEnd(), Float.NaN, "1seq.pdb"));
299 fr.setColour("PDBRESNUM", new FeatureColour(Color.red));
301 av.setShowSequenceFeatures(true);
304 * final column should have PDBRESNUM feature, the others not
306 Color c = finder.findFeatureColour(Color.blue, seq,
307 seq.getLength() - 2);
308 assertNotEquals(c, Color.red);
309 c = finder.findFeatureColour(Color.blue, seq, seq.getLength() - 1);
310 assertEquals(c, Color.red);
313 @Test(groups = "Functional")
314 public void testFindFeatureColour_graduatedFeatureColour()
316 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 2,
318 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 4,
320 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 7,
324 * graduated colour from 0 to 10
326 Color min = new Color(100, 50, 150);
327 Color max = new Color(200, 0, 100);
328 FeatureColourI fc = new FeatureColour(null, min, max, null, 0, 10);
329 fr.setColour("kd", fc);
331 av.setShowSequenceFeatures(true);
334 * position 2, column 1, score 0 - minimum colour in range
336 Color c = finder.findFeatureColour(Color.blue, seq, 1);
337 assertEquals(c, min);
340 * position 7, column 9, score 10 - maximum colour in range
342 c = finder.findFeatureColour(Color.blue, seq, 9);
343 assertEquals(c, max);
346 * position 4, column 3, score 5 - half way from min to max
348 c = finder.findFeatureColour(Color.blue, seq, 3);
349 assertEquals(c, new Color(150, 25, 125));
352 @Test(groups = "Functional")
353 public void testFindFeatureColour_transparencySingleFeature()
355 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
356 Float.NaN, "MetalGroup"));
357 FeatureColour red = new FeatureColour(Color.red);
358 fr.setColour("Metal", red);
360 av.setShowSequenceFeatures(true);
363 * the FeatureSettings transparency slider has range 0-70 which
364 * corresponds to a transparency value of 1 - 0.3
365 * A value of 0.4 gives a combination of
366 * 0.4 * red(255, 0, 0) + 0.6 * cyan(0, 255, 255) = (102, 153, 153)
368 fr.setTransparency(0.4f);
369 Color c = finder.findFeatureColour(Color.cyan, seq, 10);
370 assertEquals(c, new Color(102, 153, 153));
373 @Test(groups = "Functional")
374 public void testFindFeatureColour_transparencyTwoFeatures()
376 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
377 Float.NaN, "MetalGroup"));
378 FeatureColour red = new FeatureColour(Color.red);
379 fr.setColour("Metal", red);
381 seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
382 Float.NaN, "DomainGroup"));
383 FeatureColour green = new FeatureColour(Color.green);
384 fr.setColour("Domain", green);
386 av.setShowSequenceFeatures(true);
389 * Domain (green) rendered above Metal (red) above background (cyan)
390 * 1) 0.6 * red(255, 0, 0) + 0.4 * cyan(0, 255, 255) = (153, 102, 102)
391 * 2) 0.6* green(0, 255, 0) + 0.4 * (153, 102, 102) = (61, 194, 41) rounded
393 fr.setTransparency(0.6f);
394 Color c = finder.findFeatureColour(Color.cyan, seq, 10);
395 assertEquals(c, new Color(61, 194, 41));
398 * now promote Metal above Domain
399 * - currently no way other than mimicking reordering of
400 * table in Feature Settings
401 * Metal (red) rendered above Domain (green) above background (cyan)
402 * 1) 0.6 * green(0, 255, 0) + 0.4 * cyan(0, 255, 255) = (0, 255, 102)
403 * 2) 0.6* red(255, 0, 0) + 0.4 * (0, 255, 102) = (153, 102, 41) rounded
405 FeatureSettingsBean[] data = new FeatureSettingsBean[2];
406 data[0] = new FeatureSettingsBean("Metal", red, null, true);
407 data[1] = new FeatureSettingsBean("Domain", green, null, true);
408 fr.setFeaturePriority(data);
409 c = finder.findFeatureColour(Color.cyan, seq, 10);
410 assertEquals(c, new Color(153, 102, 41));
413 * ..and turn off display of Metal
414 * Domain (green) above background (pink)
415 * 0.6 * green(0, 255, 0) + 0.4 * pink(255, 175, 175) = (102, 223, 70)
417 data[0] = new FeatureSettingsBean("Metal", red, null, false);
418 fr.setFeaturePriority(data);
419 c = finder.findFeatureColour(Color.pink, seq, 10);
420 assertEquals(c, new Color(102, 223, 70));
423 @Test(groups = "Functional")
424 public void testNoFeaturesDisplayed()
427 * no features on alignment to render
429 assertTrue(finder.noFeaturesDisplayed());
433 * it will be automatically set visible but we leave
434 * the viewport configured not to show features
436 av.setShowSequenceFeatures(false);
437 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
438 Float.NaN, "MetalGroup"));
439 FeatureColour red = new FeatureColour(Color.red);
440 fr.setColour("Metal", red);
442 assertTrue(finder.noFeaturesDisplayed());
445 * turn on feature display
447 av.setShowSequenceFeatures(true);
448 assertFalse(finder.noFeaturesDisplayed());
451 * turn off display of Metal
453 FeatureSettingsBean[] data = new FeatureSettingsBean[1];
454 data[0] = new FeatureSettingsBean("Metal", red, null, false);
455 fr.setFeaturePriority(data);
456 assertTrue(finder.noFeaturesDisplayed());
459 * turn display of Metal back on
461 fr.setVisible("Metal");
462 assertFalse(finder.noFeaturesDisplayed());
465 * turn off MetalGroup - has no effect here since the group of a
466 * sequence feature instance is independent of its type
468 fr.setGroupVisibility("MetalGroup", false);
469 assertFalse(finder.noFeaturesDisplayed());
472 * a finder with no feature renderer
474 FeatureColourFinder finder2 = new FeatureColourFinder(null);
475 assertTrue(finder2.noFeaturesDisplayed());
478 @Test(groups = "Functional")
479 public void testFindFeatureColour_graduatedWithThreshold()
481 String kdFeature = "kd";
482 String metalFeature = "Metal";
483 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 2,
485 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 4,
487 seq.addSequenceFeature(new SequenceFeature(metalFeature, "Fe", 4, 4,
489 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 7,
493 * kd feature has graduated colour from 0 to 10
494 * above threshold value of 5
496 Color min = new Color(100, 50, 150);
497 Color max = new Color(200, 0, 100);
498 FeatureColourI fc = new FeatureColour(null, min, max, null, 0, 10);
499 fc.setAboveThreshold(true);
501 fr.setColour(kdFeature, fc);
502 FeatureColour green = new FeatureColour(Color.green);
503 fr.setColour(metalFeature, green);
507 * render order is kd above Metal
509 FeatureSettingsBean[] data = new FeatureSettingsBean[2];
510 data[0] = new FeatureSettingsBean(kdFeature, fc, null, true);
511 data[1] = new FeatureSettingsBean(metalFeature, green, null, true);
512 fr.setFeaturePriority(data);
514 av.setShowSequenceFeatures(true);
517 * position 2, column 1, score 0 - below threshold - default colour
519 Color c = finder.findFeatureColour(Color.blue, seq, 1);
520 assertEquals(c, Color.blue);
523 * position 4, column 3, score 5 - at threshold
524 * should return Green (colour of Metal feature)
526 c = finder.findFeatureColour(Color.blue, seq, 3);
527 assertEquals(c, Color.green);
530 * position 7, column 9, score 10 - maximum colour in range
532 c = finder.findFeatureColour(Color.blue, seq, 9);
533 assertEquals(c, max);
536 * now colour below threshold of 5
538 fc.setBelowThreshold(true);
541 * position 2, column 1, score 0 - min colour
543 c = finder.findFeatureColour(Color.blue, seq, 1);
544 assertEquals(c, min);
547 * position 4, column 3, score 5 - at threshold
548 * should return Green (colour of Metal feature)
550 c = finder.findFeatureColour(Color.blue, seq, 3);
551 assertEquals(c, Color.green);
554 * position 7, column 9, score 10 - above threshold - default colour
556 c = finder.findFeatureColour(Color.blue, seq, 9);
557 assertEquals(c, Color.blue);