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 fr.setColour("Metal", new FeatureColour(Color.red));
116 * global show features flag is _not_ checked by findFeatureColour
118 av.setShowSequenceFeatures(false);
119 Color c = finder.findFeatureColour(Color.blue, seq, 10);
120 assertEquals(c, Color.red);
123 @Test(groups = "Functional")
124 public void testFindFeatureColour_singleFeatureAtPosition()
126 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
127 Float.NaN, "MetalGroup"));
128 fr.setColour("Metal", new FeatureColour(Color.red));
130 av.setShowSequenceFeatures(true);
131 Color c = finder.findFeatureColour(Color.blue, seq, 10);
132 assertEquals(c, Color.red);
136 * feature colour at a gap is null (not white) - a user defined colour scheme
137 * can then provide a bespoke gap colour if configured to do so
139 @Test(groups = "Functional")
140 public void testFindFeatureColour_gapPosition()
142 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12, 0f,
144 fr.setColour("Metal", new FeatureColour(Color.red));
146 av.setShowSequenceFeatures(true);
147 Color c = finder.findFeatureColour(null, seq, 6);
151 @Test(groups = "Functional")
152 public void testFindFeatureColour_multipleFeaturesAtPositionNoTransparency()
155 * featuresAdded -> FeatureRendererModel.updateRenderOrder which adds any
156 * new features 'on top' (but reverses the order of any added features)
158 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
159 Float.NaN, "MetalGroup"));
160 FeatureColour red = new FeatureColour(Color.red);
161 fr.setColour("Metal", red);
163 seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
164 Float.NaN, "DomainGroup"));
165 FeatureColour green = new FeatureColour(Color.green);
166 fr.setColour("Domain", green);
168 av.setShowSequenceFeatures(true);
171 * expect Domain (green) to be rendered above Metal (red)
173 Color c = finder.findFeatureColour(Color.blue, seq, 10);
174 assertEquals(c, Color.green);
177 * now promote Metal above Domain
178 * - currently no way other than mimicking reordering of
179 * table in Feature Settings
181 FeatureSettingsBean[] data = new FeatureSettingsBean[2];
182 data[0] = new FeatureSettingsBean("Metal", red, null, true);
183 data[1] = new FeatureSettingsBean("Domain", green, null, true);
184 fr.setFeaturePriority(data);
185 c = finder.findFeatureColour(Color.blue, seq, 10);
186 assertEquals(c, Color.red);
189 * ..and turn off display of Metal
191 data[0] = new FeatureSettingsBean("Metal", red, null, false);
192 fr.setFeaturePriority(data);
193 c = finder.findFeatureColour(Color.blue, seq, 10);
194 assertEquals(c, Color.green);
197 @Test(groups = "Functional")
198 public void testFindFeatureColour_singleFeatureNotAtPosition()
200 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 8, 12,
201 Float.NaN, "MetalGroup"));
202 fr.setColour("Metal", new FeatureColour(Color.red));
204 av.setShowSequenceFeatures(true);
205 // column 2 = sequence position 3
206 Color c = finder.findFeatureColour(Color.blue, seq, 2);
207 assertEquals(c, Color.blue);
210 @Test(groups = "Functional")
211 public void testFindFeatureColour_featureTypeNotDisplayed()
213 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
214 Float.NaN, "MetalGroup"));
215 FeatureColour red = new FeatureColour(Color.red);
216 fr.setColour("Metal", red);
218 av.setShowSequenceFeatures(true);
219 Color c = finder.findFeatureColour(Color.blue, seq, 10);
220 assertEquals(c, Color.red);
223 * turn off display of Metal - is this the easiest way to do it??
225 FeatureSettingsBean[] data = new FeatureSettingsBean[1];
226 data[0] = new FeatureSettingsBean("Metal", red, null, false);
227 fr.setFeaturePriority(data);
228 c = finder.findFeatureColour(Color.blue, seq, 10);
229 assertEquals(c, Color.blue);
232 * turn display of Metal back on
234 data[0] = new FeatureSettingsBean("Metal", red, null, true);
235 fr.setFeaturePriority(data);
236 c = finder.findFeatureColour(Color.blue, seq, 10);
237 assertEquals(c, Color.red);
240 @Test(groups = "Functional")
241 public void testFindFeatureColour_featureGroupNotDisplayed()
243 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
244 Float.NaN, "MetalGroup"));
245 FeatureColour red = new FeatureColour(Color.red);
246 fr.setColour("Metal", red);
248 av.setShowSequenceFeatures(true);
249 Color c = finder.findFeatureColour(Color.blue, seq, 10);
250 assertEquals(c, Color.red);
253 * turn off display of MetalGroup
255 fr.setGroupVisibility("MetalGroup", false);
256 c = finder.findFeatureColour(Color.blue, seq, 10);
257 assertEquals(c, Color.blue);
260 * turn display of MetalGroup back on
262 fr.setGroupVisibility("MetalGroup", true);
263 c = finder.findFeatureColour(Color.blue, seq, 10);
264 assertEquals(c, Color.red);
267 @Test(groups = "Functional")
268 public void testFindFeatureColour_contactFeature()
271 * currently contact feature == type "Disulphide Bond" or "Disulfide Bond" !!
273 seq.addSequenceFeature(new SequenceFeature("Disulphide Bond",
274 "Contact", 2, 12, Float.NaN, "Disulphide"));
275 fr.setColour("Disulphide Bond", new FeatureColour(Color.red));
277 av.setShowSequenceFeatures(true);
280 * Contact positions are residues 2 and 12
281 * which are columns 1 and 14
282 * positions in between don't count for a contact feature!
284 Color c = finder.findFeatureColour(Color.blue, seq, 10);
285 assertEquals(c, Color.blue);
286 c = finder.findFeatureColour(Color.blue, seq, 8);
287 assertEquals(c, Color.blue);
288 c = finder.findFeatureColour(Color.blue, seq, 1);
289 assertEquals(c, Color.red);
290 c = finder.findFeatureColour(Color.blue, seq, 14);
291 assertEquals(c, Color.red);
294 @Test(groups = "Functional")
295 public void testFindFeatureAtEnd()
298 * terminal residue feature
300 seq.addSequenceFeature(new SequenceFeature("PDBRESNUM", "pdb res 1",
301 seq.getEnd(), seq.getEnd(), Float.NaN, "1seq.pdb"));
302 fr.setColour("PDBRESNUM", new FeatureColour(Color.red));
304 av.setShowSequenceFeatures(true);
307 * final column should have PDBRESNUM feature, the others not
309 Color c = finder.findFeatureColour(Color.blue, seq,
310 seq.getLength() - 2);
311 assertNotEquals(c, Color.red);
312 c = finder.findFeatureColour(Color.blue, seq, seq.getLength() - 1);
313 assertEquals(c, Color.red);
316 @Test(groups = "Functional")
317 public void testFindFeatureColour_graduatedFeatureColour()
319 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 2,
321 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 4,
323 seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 7,
327 * graduated colour from 0 to 10
329 Color min = new Color(100, 50, 150);
330 Color max = new Color(200, 0, 100);
331 FeatureColourI fc = new FeatureColour(min, max, 0, 10);
332 fr.setColour("kd", fc);
334 av.setShowSequenceFeatures(true);
337 * position 2, column 1, score 0 - minimum colour in range
339 Color c = finder.findFeatureColour(Color.blue, seq, 1);
340 assertEquals(c, min);
343 * position 7, column 9, score 10 - maximum colour in range
345 c = finder.findFeatureColour(Color.blue, seq, 9);
346 assertEquals(c, max);
349 * position 4, column 3, score 5 - half way from min to max
351 c = finder.findFeatureColour(Color.blue, seq, 3);
352 assertEquals(c, new Color(150, 25, 125));
355 @Test(groups = "Functional")
356 public void testFindFeatureColour_transparencySingleFeature()
358 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
359 Float.NaN, "MetalGroup"));
360 FeatureColour red = new FeatureColour(Color.red);
361 fr.setColour("Metal", red);
363 av.setShowSequenceFeatures(true);
366 * the FeatureSettings transparency slider has range 0-70 which
367 * corresponds to a transparency value of 1 - 0.3
368 * A value of 0.4 gives a combination of
369 * 0.4 * red(255, 0, 0) + 0.6 * cyan(0, 255, 255) = (102, 153, 153)
371 fr.setTransparency(0.4f);
372 Color c = finder.findFeatureColour(Color.cyan, seq, 10);
373 assertEquals(c, new Color(102, 153, 153));
376 @Test(groups = "Functional")
377 public void testFindFeatureColour_transparencyTwoFeatures()
379 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
380 Float.NaN, "MetalGroup"));
381 FeatureColour red = new FeatureColour(Color.red);
382 fr.setColour("Metal", red);
384 seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
385 Float.NaN, "DomainGroup"));
386 FeatureColour green = new FeatureColour(Color.green);
387 fr.setColour("Domain", green);
389 av.setShowSequenceFeatures(true);
392 * Domain (green) rendered above Metal (red) above background (cyan)
393 * 1) 0.6 * red(255, 0, 0) + 0.4 * cyan(0, 255, 255) = (153, 102, 102)
394 * 2) 0.6* green(0, 255, 0) + 0.4 * (153, 102, 102) = (61, 194, 41) rounded
396 fr.setTransparency(0.6f);
397 Color c = finder.findFeatureColour(Color.cyan, seq, 10);
398 assertEquals(c, new Color(61, 194, 41));
401 * now promote Metal above Domain
402 * - currently no way other than mimicking reordering of
403 * table in Feature Settings
404 * Metal (red) rendered above Domain (green) above background (cyan)
405 * 1) 0.6 * green(0, 255, 0) + 0.4 * cyan(0, 255, 255) = (0, 255, 102)
406 * 2) 0.6* red(255, 0, 0) + 0.4 * (0, 255, 102) = (153, 102, 41) rounded
408 FeatureSettingsBean[] data = new FeatureSettingsBean[2];
409 data[0] = new FeatureSettingsBean("Metal", red, null, true);
410 data[1] = new FeatureSettingsBean("Domain", green, null, true);
411 fr.setFeaturePriority(data);
412 c = finder.findFeatureColour(Color.cyan, seq, 10);
413 assertEquals(c, new Color(153, 102, 41));
416 * ..and turn off display of Metal
417 * Domain (green) above background (pink)
418 * 0.6 * green(0, 255, 0) + 0.4 * pink(255, 175, 175) = (102, 223, 70)
420 data[0] = new FeatureSettingsBean("Metal", red, null, false);
421 fr.setFeaturePriority(data);
422 c = finder.findFeatureColour(Color.pink, seq, 10);
423 assertEquals(c, new Color(102, 223, 70));
426 @Test(groups = "Functional")
427 public void testNoFeaturesDisplayed()
430 * no features on alignment to render
432 assertTrue(finder.noFeaturesDisplayed());
436 * it will be automatically set visible but we leave
437 * the viewport configured not to show features
439 av.setShowSequenceFeatures(false);
440 seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
441 Float.NaN, "MetalGroup"));
442 FeatureColour red = new FeatureColour(Color.red);
443 fr.setColour("Metal", red);
445 assertTrue(finder.noFeaturesDisplayed());
448 * turn on feature display
450 av.setShowSequenceFeatures(true);
451 assertFalse(finder.noFeaturesDisplayed());
454 * turn off display of Metal
456 FeatureSettingsBean[] data = new FeatureSettingsBean[1];
457 data[0] = new FeatureSettingsBean("Metal", red, null, false);
458 fr.setFeaturePriority(data);
459 assertTrue(finder.noFeaturesDisplayed());
462 * turn display of Metal back on
464 fr.setVisible("Metal");
465 assertFalse(finder.noFeaturesDisplayed());
468 * turn off MetalGroup - has no effect here since the group of a
469 * sequence feature instance is independent of its type
471 fr.setGroupVisibility("MetalGroup", false);
472 assertFalse(finder.noFeaturesDisplayed());
475 * a finder with no feature renderer
477 FeatureColourFinder finder2 = new FeatureColourFinder(null);
478 assertTrue(finder2.noFeaturesDisplayed());
481 @Test(groups = "Functional")
482 public void testFindFeatureColour_graduatedWithThreshold()
484 String kdFeature = "kd";
485 String metalFeature = "Metal";
486 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 2,
488 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 4,
490 seq.addSequenceFeature(new SequenceFeature(metalFeature, "Fe", 4, 4,
492 seq.addSequenceFeature(new SequenceFeature(kdFeature, "hydrophobicity", 7,
496 * kd feature has graduated colour from 0 to 10
497 * above threshold value of 5
499 Color min = new Color(100, 50, 150);
500 Color max = new Color(200, 0, 100);
501 FeatureColourI fc = new FeatureColour(min, max, 0, 10);
502 fc.setAboveThreshold(true);
504 fr.setColour(kdFeature, fc);
505 FeatureColour green = new FeatureColour(Color.green);
506 fr.setColour(metalFeature, green);
510 * render order is kd above Metal
512 FeatureSettingsBean[] data = new FeatureSettingsBean[2];
513 data[0] = new FeatureSettingsBean(kdFeature, fc, null, true);
514 data[1] = new FeatureSettingsBean(metalFeature, green, null, true);
515 fr.setFeaturePriority(data);
517 av.setShowSequenceFeatures(true);
520 * position 2, column 1, score 0 - below threshold - default colour
522 Color c = finder.findFeatureColour(Color.blue, seq, 1);
523 assertEquals(c, Color.blue);
526 * position 4, column 3, score 5 - at threshold
527 * should return Green (colour of Metal feature)
529 c = finder.findFeatureColour(Color.blue, seq, 3);
530 assertEquals(c, Color.green);
533 * position 7, column 9, score 10 - maximum colour in range
535 c = finder.findFeatureColour(Color.blue, seq, 9);
536 assertEquals(c, max);
539 * now colour below threshold of 5
541 fc.setBelowThreshold(true);
544 * position 2, column 1, score 0 - min colour
546 c = finder.findFeatureColour(Color.blue, seq, 1);
547 assertEquals(c, min);
550 * position 4, column 3, score 5 - at threshold
551 * should return Green (colour of Metal feature)
553 c = finder.findFeatureColour(Color.blue, seq, 3);
554 assertEquals(c, Color.green);
557 * position 7, column 9, score 10 - above threshold - default colour
559 c = finder.findFeatureColour(Color.blue, seq, 9);
560 assertEquals(c, Color.blue);