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.assertNull;
6 import static org.testng.Assert.assertTrue;
8 import jalview.api.FeatureColourI;
9 import jalview.datamodel.SequenceFeature;
10 import jalview.datamodel.SequenceI;
11 import jalview.gui.AlignFrame;
12 import jalview.gui.AlignViewport;
13 import jalview.gui.FeatureRenderer;
14 import jalview.io.DataSourceType;
15 import jalview.io.FileLoader;
16 import jalview.schemes.FeatureColour;
18 import java.awt.Color;
19 import java.util.List;
21 import org.testng.annotations.BeforeMethod;
22 import org.testng.annotations.BeforeTest;
23 import org.testng.annotations.Test;
26 * Unit tests for feature colour determination, including but not limited to
28 * <li>gap position</li>
29 * <li>no features present</li>
30 * <li>features present but show features turned off</li>
31 * <li>features displayed but selected feature turned off</li>
32 * <li>features displayed but feature group turned off</li>
33 * <li>feature displayed but none at the specified position</li>
34 * <li>multiple features at position, with no transparency</li>
35 * <li>multiple features at position, with transparency</li>
36 * <li>score graduated feature colour</li>
37 * <li>contact feature start at the selected position</li>
38 * <li>contact feature end at the selected position</li>
39 * <li>contact feature straddling the selected position (not shown)</li>
42 public class FeatureColourFinderTest
44 private AlignViewport av;
46 private SequenceI seq;
48 private FeatureColourFinder finder;
50 private AlignFrame af;
52 private FeatureRenderer fr;
54 @BeforeTest(alwaysRun = true)
57 // aligned column 8 is sequence position 6
58 String s = ">s1\nABCDE---FGHIJKLMNOPQRSTUVWXYZ\n";
59 af = new FileLoader().LoadFileWaitTillLoaded(s,
60 DataSourceType.PASTE);
61 av = af.getViewport();
62 seq = av.getAlignment().getSequenceAt(0);
63 fr = af.getFeatureRenderer();
64 finder = new FeatureColourFinder(fr);
68 * Clear down any sequence features before each test (not as easy as it
71 @BeforeMethod(alwaysRun = true)
72 public void setUpBeforeTest()
74 List<SequenceFeature> sfs = seq.getSequenceFeatures();
75 for (SequenceFeature sf : sfs)
77 seq.deleteFeature(sf);
79 fr.findAllFeatures(true);
82 * reset all feature groups to visible
84 for (String group : fr.getGroups(false))
86 fr.setGroupVisibility(group, true);
89 fr.clearRenderOrder();
90 av.setShowSequenceFeatures(true);
93 @Test(groups = "Functional")
94 public void testFindFeatureColour_noFeatures()
96 av.setShowSequenceFeatures(false);
97 Color c = finder.findFeatureColour(Color.blue, seq, 10);
98 assertEquals(c, Color.blue);
100 av.setShowSequenceFeatures(true);
101 c = finder.findFeatureColour(Color.blue, seq, 10);
102 assertEquals(c, Color.blue);
105 @Test(groups = "Functional")
106 public void testFindFeatureColour_noFeaturesShown()
108 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
109 Float.NaN, "MetalGroup"));
111 av.setShowSequenceFeatures(false);
112 Color c = finder.findFeatureColour(Color.blue, seq, 10);
113 assertEquals(c, Color.blue);
116 @Test(groups = "Functional")
117 public void testFindFeatureColour_singleFeatureAtPosition()
119 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
120 Float.NaN, "MetalGroup"));
121 fr.setColour("Metal", new FeatureColour(Color.red));
123 av.setShowSequenceFeatures(true);
124 Color c = finder.findFeatureColour(Color.blue, seq, 10);
125 assertEquals(c, Color.red);
129 * feature colour at a gap is null (not white) - a user defined colour scheme
130 * can then provide a bespoke gap colour if configured to do so
132 @Test(groups = "Functional")
133 public void testFindFeatureColour_gapPosition()
135 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12, 0f,
137 fr.setColour("Metal", new FeatureColour(Color.red));
139 av.setShowSequenceFeatures(true);
140 Color c = finder.findFeatureColour(null, seq, 6);
144 @Test(groups = "Functional")
145 public void testFindFeatureColour_multipleFeaturesAtPositionNoTransparency()
148 * featuresAdded -> FeatureRendererModel.updateRenderOrder which adds any
149 * new features 'on top' (but reverses the order of any added features)
151 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
152 Float.NaN, "MetalGroup"));
153 FeatureColour red = new FeatureColour(Color.red);
154 fr.setColour("Metal", red);
156 seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
157 Float.NaN, "DomainGroup"));
158 FeatureColour green = new FeatureColour(Color.green);
159 fr.setColour("Domain", green);
161 av.setShowSequenceFeatures(true);
164 * expect Domain (green) to be rendered above Metal (red)
166 Color c = finder.findFeatureColour(Color.blue, seq, 10);
167 assertEquals(c, Color.green);
170 * now promote Metal above Domain
171 * - currently no way other than mimicking reordering of
172 * table in Feature Settings
174 Object[][] data = new Object[2][];
175 data[0] = new Object[] { "Metal", red, true };
176 data[1] = new Object[] { "Domain", green, true };
177 fr.setFeaturePriority(data);
178 c = finder.findFeatureColour(Color.blue, seq, 10);
179 assertEquals(c, Color.red);
182 * ..and turn off display of Metal
185 fr.setFeaturePriority(data);
186 c = finder.findFeatureColour(Color.blue, seq, 10);
187 assertEquals(c, Color.green);
190 @Test(groups = "Functional")
191 public void testFindFeatureColour_singleFeatureNotAtPosition()
193 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 8, 12,
194 Float.NaN, "MetalGroup"));
195 fr.setColour("Metal", new FeatureColour(Color.red));
197 av.setShowSequenceFeatures(true);
198 // column 2 = sequence position 3
199 Color c = finder.findFeatureColour(Color.blue, seq, 2);
200 assertEquals(c, Color.blue);
203 @Test(groups = "Functional")
204 public void testFindFeatureColour_featureTypeNotDisplayed()
206 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
207 Float.NaN, "MetalGroup"));
208 FeatureColour red = new FeatureColour(Color.red);
209 fr.setColour("Metal", red);
211 av.setShowSequenceFeatures(true);
212 Color c = finder.findFeatureColour(Color.blue, seq, 10);
213 assertEquals(c, Color.red);
216 * turn off display of Metal - is this the easiest way to do it??
218 Object[][] data = new Object[1][];
219 data[0] = new Object[] { "Metal", red, false };
220 fr.setFeaturePriority(data);
221 c = finder.findFeatureColour(Color.blue, seq, 10);
222 assertEquals(c, Color.blue);
225 * turn display of Metal back on
227 data[0] = new Object[] { "Metal", red, true };
228 fr.setFeaturePriority(data);
229 c = finder.findFeatureColour(Color.blue, seq, 10);
230 assertEquals(c, Color.red);
233 @Test(groups = "Functional")
234 public void testFindFeatureColour_featureGroupNotDisplayed()
236 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
237 Float.NaN, "MetalGroup"));
238 FeatureColour red = new FeatureColour(Color.red);
239 fr.setColour("Metal", red);
241 av.setShowSequenceFeatures(true);
242 Color c = finder.findFeatureColour(Color.blue, seq, 10);
243 assertEquals(c, Color.red);
246 * turn off display of MetalGroup
248 fr.setGroupVisibility("MetalGroup", false);
249 c = finder.findFeatureColour(Color.blue, seq, 10);
250 assertEquals(c, Color.blue);
253 * turn display of MetalGroup back on
255 fr.setGroupVisibility("MetalGroup", true);
256 c = finder.findFeatureColour(Color.blue, seq, 10);
257 assertEquals(c, Color.red);
260 @Test(groups = "Functional")
261 public void testFindFeatureColour_contactFeature()
264 * currently contact feature == type "Disulphide Bond" or "Disulfide Bond" !!
266 seq.addSequenceFeature(new SequenceFeature("Disulphide Bond",
267 "Contact", 2, 12, Float.NaN, "Disulphide"));
268 fr.setColour("Disulphide Bond", new FeatureColour(Color.red));
270 av.setShowSequenceFeatures(true);
273 * Contact positions are residues 2 and 12
274 * which are columns 1 and 14
275 * positions in between don't count for a contact feature!
277 Color c = finder.findFeatureColour(Color.blue, seq, 10);
278 assertEquals(c, Color.blue);
279 c = finder.findFeatureColour(Color.blue, seq, 8);
280 assertEquals(c, Color.blue);
281 c = finder.findFeatureColour(Color.blue, seq, 1);
282 assertEquals(c, Color.red);
283 c = finder.findFeatureColour(Color.blue, seq, 14);
284 assertEquals(c, Color.red);
287 @Test(groups = "Functional")
288 public void testFindFeatureColour_graduatedFeatureColour()
290 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 2,
292 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 4,
294 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 7,
298 * graduated colour from 0 to 10
300 Color min = new Color(100, 50, 150);
301 Color max = new Color(200, 0, 100);
302 FeatureColourI fc = new FeatureColour(min, max, 0, 10);
303 fr.setColour("kd", fc);
305 av.setShowSequenceFeatures(true);
308 * position 2, column 1, score 0 - minimum colour in range
310 Color c = finder.findFeatureColour(Color.blue, seq, 1);
311 assertEquals(c, min);
314 * position 7, column 9, score 10 - maximum colour in range
316 c = finder.findFeatureColour(Color.blue, seq, 9);
317 assertEquals(c, max);
320 * position 4, column 3, score 5 - half way from min to max
322 c = finder.findFeatureColour(Color.blue, seq, 3);
323 assertEquals(c, new Color(150, 25, 125));
326 @Test(groups = "Functional")
327 public void testFindFeatureColour_transparencySingleFeature()
329 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
330 Float.NaN, "MetalGroup"));
331 FeatureColour red = new FeatureColour(Color.red);
332 fr.setColour("Metal", red);
334 av.setShowSequenceFeatures(true);
337 * the FeatureSettings transparency slider has range 0-70 which
338 * corresponds to a transparency value of 1 - 0.3
339 * A value of 0.4 gives a combination of
340 * 0.4 * red(255, 0, 0) + 0.6 * cyan(0, 255, 255) = (102, 153, 153)
342 fr.setTransparency(0.4f);
343 Color c = finder.findFeatureColour(Color.cyan, seq, 10);
344 assertEquals(c, new Color(102, 153, 153));
347 @Test(groups = "Functional")
348 public void testFindFeatureColour_transparencyTwoFeatures()
350 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
351 Float.NaN, "MetalGroup"));
352 FeatureColour red = new FeatureColour(Color.red);
353 fr.setColour("Metal", red);
355 seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
356 Float.NaN, "DomainGroup"));
357 FeatureColour green = new FeatureColour(Color.green);
358 fr.setColour("Domain", green);
360 av.setShowSequenceFeatures(true);
363 * Domain (green) rendered above Metal (red) above background (cyan)
364 * 1) 0.6 * red(255, 0, 0) + 0.4 * cyan(0, 255, 255) = (153, 102, 102)
365 * 2) 0.6* green(0, 255, 0) + 0.4 * (153, 102, 102) = (61, 194, 41) rounded
367 fr.setTransparency(0.6f);
368 Color c = finder.findFeatureColour(Color.cyan, seq, 10);
369 assertEquals(c, new Color(61, 194, 41));
372 * now promote Metal above Domain
373 * - currently no way other than mimicking reordering of
374 * table in Feature Settings
375 * Metal (red) rendered above Domain (green) above background (cyan)
376 * 1) 0.6 * green(0, 255, 0) + 0.4 * cyan(0, 255, 255) = (0, 255, 102)
377 * 2) 0.6* red(255, 0, 0) + 0.4 * (0, 255, 102) = (153, 102, 41) rounded
379 Object[][] data = new Object[2][];
380 data[0] = new Object[] { "Metal", red, true };
381 data[1] = new Object[] { "Domain", green, true };
382 fr.setFeaturePriority(data);
383 c = finder.findFeatureColour(Color.cyan, seq, 10);
384 assertEquals(c, new Color(153, 102, 41));
387 * ..and turn off display of Metal
388 * Domain (green) above background (pink)
389 * 0.6 * green(0, 255, 0) + 0.4 * pink(255, 175, 175) = (102, 223, 70)
392 fr.setFeaturePriority(data);
393 c = finder.findFeatureColour(Color.pink, seq, 10);
394 assertEquals(c, new Color(102, 223, 70));
397 @Test(groups = "Functional")
398 public void testNoFeaturesDisplayed()
401 * no features on alignment to render
403 assertTrue(finder.noFeaturesDisplayed());
407 * it will be automatically set visible but we leave
408 * the viewport configured not to show features
410 av.setShowSequenceFeatures(false);
411 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
412 Float.NaN, "MetalGroup"));
413 FeatureColour red = new FeatureColour(Color.red);
414 fr.setColour("Metal", red);
416 assertTrue(finder.noFeaturesDisplayed());
419 * turn on feature display
421 av.setShowSequenceFeatures(true);
422 assertFalse(finder.noFeaturesDisplayed());
425 * turn off display of Metal
427 Object[][] data = new Object[1][];
428 data[0] = new Object[] { "Metal", red, false };
429 fr.setFeaturePriority(data);
430 assertTrue(finder.noFeaturesDisplayed());
433 * turn display of Metal back on
435 fr.setVisible("Metal");
436 assertFalse(finder.noFeaturesDisplayed());
439 * turn off MetalGroup - has no effect here since the group of a
440 * sequence feature instance is independent of its type
442 fr.setGroupVisibility("MetalGroup", false);
443 assertFalse(finder.noFeaturesDisplayed());
446 * a finder with no feature renderer
448 FeatureColourFinder finder2 = new FeatureColourFinder(null);
449 assertTrue(finder2.noFeaturesDisplayed());
452 @Test(groups = "Functional")
453 public void testFindFeatureColour_graduatedWithThreshold()
455 String kdFeature = "kd";
456 String metalFeature = "Metal";
457 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 2,
459 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 4,
461 seq.addSequenceFeature(new SequenceFeature(metalFeature, "Fe", 4, 4,
463 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 7,
467 * kd feature has graduated colour from 0 to 10
468 * above threshold value of 5
470 Color min = new Color(100, 50, 150);
471 Color max = new Color(200, 0, 100);
472 FeatureColourI fc = new FeatureColour(min, max, 0, 10);
473 fc.setAboveThreshold(true);
475 fr.setColour(kdFeature, fc);
476 FeatureColour green = new FeatureColour(Color.green);
477 fr.setColour(metalFeature, green);
481 * render order is kd above Metal
483 Object[][] data = new Object[2][];
484 data[0] = new Object[] { kdFeature, fc, true };
485 data[1] = new Object[] { metalFeature, green, true };
486 fr.setFeaturePriority(data);
488 av.setShowSequenceFeatures(true);
491 * position 2, column 1, score 0 - below threshold - default colour
493 Color c = finder.findFeatureColour(Color.blue, seq, 1);
494 assertEquals(c, Color.blue);
497 * position 4, column 3, score 5 - at threshold
498 * should return Green (colour of Metal feature)
500 c = finder.findFeatureColour(Color.blue, seq, 3);
501 assertEquals(c, Color.green);
504 * position 7, column 9, score 10 - maximum colour in range
506 c = finder.findFeatureColour(Color.blue, seq, 9);
507 assertEquals(c, max);
510 * now colour below threshold of 5
512 fc.setBelowThreshold(true);
515 * position 2, column 1, score 0 - min colour
517 c = finder.findFeatureColour(Color.blue, seq, 1);
518 assertEquals(c, min);
521 * position 4, column 3, score 5 - at threshold
522 * should return Green (colour of Metal feature)
524 c = finder.findFeatureColour(Color.blue, seq, 3);
525 assertEquals(c, Color.green);
528 * position 7, column 9, score 10 - above threshold - default colour
530 c = finder.findFeatureColour(Color.blue, seq, 9);
531 assertEquals(c, Color.blue);