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;
18 import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
20 import java.awt.Color;
21 import java.util.List;
23 import org.testng.annotations.BeforeMethod;
24 import org.testng.annotations.BeforeTest;
25 import org.testng.annotations.Test;
28 * Unit tests for feature colour determination, including but not limited to
30 * <li>gap position</li>
31 * <li>no features present</li>
32 * <li>features present but show features turned off</li>
33 * <li>features displayed but selected feature turned off</li>
34 * <li>features displayed but feature group turned off</li>
35 * <li>feature displayed but none at the specified position</li>
36 * <li>multiple features at position, with no transparency</li>
37 * <li>multiple features at position, with transparency</li>
38 * <li>score graduated feature colour</li>
39 * <li>contact feature start at the selected position</li>
40 * <li>contact feature end at the selected position</li>
41 * <li>contact feature straddling the selected position (not shown)</li>
44 public class FeatureColourFinderTest
46 private AlignViewport av;
48 private SequenceI seq;
50 private FeatureColourFinder finder;
52 private AlignFrame af;
54 private FeatureRenderer fr;
56 @BeforeTest(alwaysRun = true)
59 // aligned column 8 is sequence position 6
60 String s = ">s1\nABCDE---FGHIJKLMNOPQRSTUVWXYZ\n";
61 af = new FileLoader().LoadFileWaitTillLoaded(s,
62 DataSourceType.PASTE);
63 av = af.getViewport();
64 seq = av.getAlignment().getSequenceAt(0);
65 fr = af.getFeatureRenderer();
66 finder = new FeatureColourFinder(fr);
70 * Clear down any sequence features before each test (not as easy as it
73 @BeforeMethod(alwaysRun = true)
74 public void setUpBeforeTest()
76 List<SequenceFeature> sfs = seq.getSequenceFeatures();
77 for (SequenceFeature sf : sfs)
79 seq.deleteFeature(sf);
81 fr.findAllFeatures(true);
84 * reset all feature groups to visible
86 for (String group : fr.getGroups(false))
88 fr.setGroupVisibility(group, true);
91 fr.clearRenderOrder();
92 av.setShowSequenceFeatures(true);
95 @Test(groups = "Functional")
96 public void testFindFeatureColour_noFeatures()
98 av.setShowSequenceFeatures(false);
99 Color c = finder.findFeatureColour(Color.blue, seq, 10);
100 assertEquals(c, Color.blue);
102 av.setShowSequenceFeatures(true);
103 c = finder.findFeatureColour(Color.blue, seq, 10);
104 assertEquals(c, Color.blue);
107 @Test(groups = "Functional")
108 public void testFindFeatureColour_noFeaturesShown()
110 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
111 Float.NaN, "MetalGroup"));
113 av.setShowSequenceFeatures(false);
114 Color c = finder.findFeatureColour(Color.blue, seq, 10);
115 assertEquals(c, Color.blue);
118 @Test(groups = "Functional")
119 public void testFindFeatureColour_singleFeatureAtPosition()
121 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
122 Float.NaN, "MetalGroup"));
123 fr.setColour("Metal", new FeatureColour(Color.red));
125 av.setShowSequenceFeatures(true);
126 Color c = finder.findFeatureColour(Color.blue, seq, 10);
127 assertEquals(c, Color.red);
131 * feature colour at a gap is null (not white) - a user defined colour scheme
132 * can then provide a bespoke gap colour if configured to do so
134 @Test(groups = "Functional")
135 public void testFindFeatureColour_gapPosition()
137 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12, 0f,
139 fr.setColour("Metal", new FeatureColour(Color.red));
141 av.setShowSequenceFeatures(true);
142 Color c = finder.findFeatureColour(null, seq, 6);
146 @Test(groups = "Functional")
147 public void testFindFeatureColour_multipleFeaturesAtPositionNoTransparency()
150 * featuresAdded -> FeatureRendererModel.updateRenderOrder which adds any
151 * new features 'on top' (but reverses the order of any added features)
153 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
154 Float.NaN, "MetalGroup"));
155 FeatureColour red = new FeatureColour(Color.red);
156 fr.setColour("Metal", red);
158 seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
159 Float.NaN, "DomainGroup"));
160 FeatureColour green = new FeatureColour(Color.green);
161 fr.setColour("Domain", green);
163 av.setShowSequenceFeatures(true);
166 * expect Domain (green) to be rendered above Metal (red)
168 Color c = finder.findFeatureColour(Color.blue, seq, 10);
169 assertEquals(c, Color.green);
172 * now promote Metal above Domain
173 * - currently no way other than mimicking reordering of
174 * table in Feature Settings
176 FeatureSettingsBean[] data = new FeatureSettingsBean[2];
177 data[0] = new FeatureSettingsBean("Metal", red, null, true);
178 data[1] = new FeatureSettingsBean("Domain", green, null, true);
179 fr.setFeaturePriority(data);
180 c = finder.findFeatureColour(Color.blue, seq, 10);
181 assertEquals(c, Color.red);
184 * ..and turn off display of Metal
186 data[0] = new FeatureSettingsBean("Metal", red, null, false);
187 fr.setFeaturePriority(data);
188 c = finder.findFeatureColour(Color.blue, seq, 10);
189 assertEquals(c, Color.green);
192 @Test(groups = "Functional")
193 public void testFindFeatureColour_singleFeatureNotAtPosition()
195 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 8, 12,
196 Float.NaN, "MetalGroup"));
197 fr.setColour("Metal", new FeatureColour(Color.red));
199 av.setShowSequenceFeatures(true);
200 // column 2 = sequence position 3
201 Color c = finder.findFeatureColour(Color.blue, seq, 2);
202 assertEquals(c, Color.blue);
205 @Test(groups = "Functional")
206 public void testFindFeatureColour_featureTypeNotDisplayed()
208 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
209 Float.NaN, "MetalGroup"));
210 FeatureColour red = new FeatureColour(Color.red);
211 fr.setColour("Metal", red);
213 av.setShowSequenceFeatures(true);
214 Color c = finder.findFeatureColour(Color.blue, seq, 10);
215 assertEquals(c, Color.red);
218 * turn off display of Metal - is this the easiest way to do it??
220 FeatureSettingsBean[] data = new FeatureSettingsBean[1];
221 data[0] = new FeatureSettingsBean("Metal", red, null, false);
222 fr.setFeaturePriority(data);
223 c = finder.findFeatureColour(Color.blue, seq, 10);
224 assertEquals(c, Color.blue);
227 * turn display of Metal back on
229 data[0] = new FeatureSettingsBean("Metal", red, null, true);
230 fr.setFeaturePriority(data);
231 c = finder.findFeatureColour(Color.blue, seq, 10);
232 assertEquals(c, Color.red);
235 @Test(groups = "Functional")
236 public void testFindFeatureColour_featureGroupNotDisplayed()
238 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
239 Float.NaN, "MetalGroup"));
240 FeatureColour red = new FeatureColour(Color.red);
241 fr.setColour("Metal", red);
243 av.setShowSequenceFeatures(true);
244 Color c = finder.findFeatureColour(Color.blue, seq, 10);
245 assertEquals(c, Color.red);
248 * turn off display of MetalGroup
250 fr.setGroupVisibility("MetalGroup", false);
251 c = finder.findFeatureColour(Color.blue, seq, 10);
252 assertEquals(c, Color.blue);
255 * turn display of MetalGroup back on
257 fr.setGroupVisibility("MetalGroup", true);
258 c = finder.findFeatureColour(Color.blue, seq, 10);
259 assertEquals(c, Color.red);
262 @Test(groups = "Functional")
263 public void testFindFeatureColour_contactFeature()
266 * currently contact feature == type "Disulphide Bond" or "Disulfide Bond" !!
268 seq.addSequenceFeature(new SequenceFeature("Disulphide Bond",
269 "Contact", 2, 12, Float.NaN, "Disulphide"));
270 fr.setColour("Disulphide Bond", new FeatureColour(Color.red));
272 av.setShowSequenceFeatures(true);
275 * Contact positions are residues 2 and 12
276 * which are columns 1 and 14
277 * positions in between don't count for a contact feature!
279 Color c = finder.findFeatureColour(Color.blue, seq, 10);
280 assertEquals(c, Color.blue);
281 c = finder.findFeatureColour(Color.blue, seq, 8);
282 assertEquals(c, Color.blue);
283 c = finder.findFeatureColour(Color.blue, seq, 1);
284 assertEquals(c, Color.red);
285 c = finder.findFeatureColour(Color.blue, seq, 14);
286 assertEquals(c, Color.red);
289 @Test(groups = "Functional")
290 public void testFindFeatureAtEnd()
293 * terminal residue feature
295 seq.addSequenceFeature(new SequenceFeature("PDBRESNUM", "pdb res 1",
296 seq.getEnd(), seq.getEnd(), Float.NaN, "1seq.pdb"));
297 fr.setColour("PDBRESNUM", new FeatureColour(Color.red));
299 av.setShowSequenceFeatures(true);
302 * final column should have PDBRESNUM feature, the others not
304 Color c = finder.findFeatureColour(Color.blue, seq,
305 seq.getLength() - 2);
306 assertNotEquals(c, Color.red);
307 c = finder.findFeatureColour(Color.blue, seq, seq.getLength() - 1);
308 assertEquals(c, Color.red);
311 @Test(groups = "Functional")
312 public void testFindFeatureColour_graduatedFeatureColour()
314 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 2,
316 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 4,
318 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 7,
322 * graduated colour from 0 to 10
324 Color min = new Color(100, 50, 150);
325 Color max = new Color(200, 0, 100);
326 FeatureColourI fc = new FeatureColour(min, max, 0, 10);
327 fr.setColour("kd", fc);
329 av.setShowSequenceFeatures(true);
332 * position 2, column 1, score 0 - minimum colour in range
334 Color c = finder.findFeatureColour(Color.blue, seq, 1);
335 assertEquals(c, min);
338 * position 7, column 9, score 10 - maximum colour in range
340 c = finder.findFeatureColour(Color.blue, seq, 9);
341 assertEquals(c, max);
344 * position 4, column 3, score 5 - half way from min to max
346 c = finder.findFeatureColour(Color.blue, seq, 3);
347 assertEquals(c, new Color(150, 25, 125));
350 @Test(groups = "Functional")
351 public void testFindFeatureColour_transparencySingleFeature()
353 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
354 Float.NaN, "MetalGroup"));
355 FeatureColour red = new FeatureColour(Color.red);
356 fr.setColour("Metal", red);
358 av.setShowSequenceFeatures(true);
361 * the FeatureSettings transparency slider has range 0-70 which
362 * corresponds to a transparency value of 1 - 0.3
363 * A value of 0.4 gives a combination of
364 * 0.4 * red(255, 0, 0) + 0.6 * cyan(0, 255, 255) = (102, 153, 153)
366 fr.setTransparency(0.4f);
367 Color c = finder.findFeatureColour(Color.cyan, seq, 10);
368 assertEquals(c, new Color(102, 153, 153));
371 @Test(groups = "Functional")
372 public void testFindFeatureColour_transparencyTwoFeatures()
374 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
375 Float.NaN, "MetalGroup"));
376 FeatureColour red = new FeatureColour(Color.red);
377 fr.setColour("Metal", red);
379 seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
380 Float.NaN, "DomainGroup"));
381 FeatureColour green = new FeatureColour(Color.green);
382 fr.setColour("Domain", green);
384 av.setShowSequenceFeatures(true);
387 * Domain (green) rendered above Metal (red) above background (cyan)
388 * 1) 0.6 * red(255, 0, 0) + 0.4 * cyan(0, 255, 255) = (153, 102, 102)
389 * 2) 0.6* green(0, 255, 0) + 0.4 * (153, 102, 102) = (61, 194, 41) rounded
391 fr.setTransparency(0.6f);
392 Color c = finder.findFeatureColour(Color.cyan, seq, 10);
393 assertEquals(c, new Color(61, 194, 41));
396 * now promote Metal above Domain
397 * - currently no way other than mimicking reordering of
398 * table in Feature Settings
399 * Metal (red) rendered above Domain (green) above background (cyan)
400 * 1) 0.6 * green(0, 255, 0) + 0.4 * cyan(0, 255, 255) = (0, 255, 102)
401 * 2) 0.6* red(255, 0, 0) + 0.4 * (0, 255, 102) = (153, 102, 41) rounded
403 FeatureSettingsBean[] data = new FeatureSettingsBean[2];
404 data[0] = new FeatureSettingsBean("Metal", red, null, true);
405 data[1] = new FeatureSettingsBean("Domain", green, null, true);
406 fr.setFeaturePriority(data);
407 c = finder.findFeatureColour(Color.cyan, seq, 10);
408 assertEquals(c, new Color(153, 102, 41));
411 * ..and turn off display of Metal
412 * Domain (green) above background (pink)
413 * 0.6 * green(0, 255, 0) + 0.4 * pink(255, 175, 175) = (102, 223, 70)
415 data[0] = new FeatureSettingsBean("Metal", red, null, false);
416 fr.setFeaturePriority(data);
417 c = finder.findFeatureColour(Color.pink, seq, 10);
418 assertEquals(c, new Color(102, 223, 70));
421 @Test(groups = "Functional")
422 public void testNoFeaturesDisplayed()
425 * no features on alignment to render
427 assertTrue(finder.noFeaturesDisplayed());
431 * it will be automatically set visible but we leave
432 * the viewport configured not to show features
434 av.setShowSequenceFeatures(false);
435 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
436 Float.NaN, "MetalGroup"));
437 FeatureColour red = new FeatureColour(Color.red);
438 fr.setColour("Metal", red);
440 assertTrue(finder.noFeaturesDisplayed());
443 * turn on feature display
445 av.setShowSequenceFeatures(true);
446 assertFalse(finder.noFeaturesDisplayed());
449 * turn off display of Metal
451 FeatureSettingsBean[] data = new FeatureSettingsBean[1];
452 data[0] = new FeatureSettingsBean("Metal", red, null, false);
453 fr.setFeaturePriority(data);
454 assertTrue(finder.noFeaturesDisplayed());
457 * turn display of Metal back on
459 fr.setVisible("Metal");
460 assertFalse(finder.noFeaturesDisplayed());
463 * turn off MetalGroup - has no effect here since the group of a
464 * sequence feature instance is independent of its type
466 fr.setGroupVisibility("MetalGroup", false);
467 assertFalse(finder.noFeaturesDisplayed());
470 * a finder with no feature renderer
472 FeatureColourFinder finder2 = new FeatureColourFinder(null);
473 assertTrue(finder2.noFeaturesDisplayed());
476 @Test(groups = "Functional")
477 public void testFindFeatureColour_graduatedWithThreshold()
479 String kdFeature = "kd";
480 String metalFeature = "Metal";
481 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 2,
483 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 4,
485 seq.addSequenceFeature(new SequenceFeature(metalFeature, "Fe", 4, 4,
487 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 7,
491 * kd feature has graduated colour from 0 to 10
492 * above threshold value of 5
494 Color min = new Color(100, 50, 150);
495 Color max = new Color(200, 0, 100);
496 FeatureColourI fc = new FeatureColour(min, max, 0, 10);
497 fc.setAboveThreshold(true);
499 fr.setColour(kdFeature, fc);
500 FeatureColour green = new FeatureColour(Color.green);
501 fr.setColour(metalFeature, green);
505 * render order is kd above Metal
507 FeatureSettingsBean[] data = new FeatureSettingsBean[2];
508 data[0] = new FeatureSettingsBean(kdFeature, fc, null, true);
509 data[1] = new FeatureSettingsBean(metalFeature, green, null, true);
510 fr.setFeaturePriority(data);
512 av.setShowSequenceFeatures(true);
515 * position 2, column 1, score 0 - below threshold - default colour
517 Color c = finder.findFeatureColour(Color.blue, seq, 1);
518 assertEquals(c, Color.blue);
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 - maximum colour in range
530 c = finder.findFeatureColour(Color.blue, seq, 9);
531 assertEquals(c, max);
534 * now colour below threshold of 5
536 fc.setBelowThreshold(true);
539 * position 2, column 1, score 0 - min colour
541 c = finder.findFeatureColour(Color.blue, seq, 1);
542 assertEquals(c, min);
545 * position 4, column 3, score 5 - at threshold
546 * should return Green (colour of Metal feature)
548 c = finder.findFeatureColour(Color.blue, seq, 3);
549 assertEquals(c, Color.green);
552 * position 7, column 9, score 10 - above threshold - default colour
554 c = finder.findFeatureColour(Color.blue, seq, 9);
555 assertEquals(c, Color.blue);