Clover icon

Coverage Report

  1. Project Clover database Thu Aug 13 2020 12:04:21 BST
  2. Package jalview.renderer.seqfeatures

File FeatureRendererTest.java

 

Code metrics

4
333
6
1
679
442
8
0.02
55.5
6
1.33

Classes

Class Line # Actions
FeatureRendererTest 58 333 8
0.994169199.4%
 

Contributing tests

This file is covered by 6 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.renderer.seqfeatures;
22   
23    import static org.testng.Assert.assertEquals;
24    import static org.testng.Assert.assertFalse;
25    import static org.testng.Assert.assertNotNull;
26    import static org.testng.Assert.assertNull;
27    import static org.testng.Assert.assertSame;
28    import static org.testng.Assert.assertTrue;
29   
30    import jalview.analysis.GeneticCodes;
31    import jalview.api.AlignViewportI;
32    import jalview.api.FeatureColourI;
33    import jalview.bin.Jalview;
34    import jalview.datamodel.MappedFeatures;
35    import jalview.datamodel.SequenceFeature;
36    import jalview.datamodel.SequenceI;
37    import jalview.datamodel.features.FeatureMatcher;
38    import jalview.datamodel.features.FeatureMatcherSet;
39    import jalview.datamodel.features.FeatureMatcherSetI;
40    import jalview.gui.AlignFrame;
41    import jalview.gui.AlignViewport;
42    import jalview.gui.Desktop;
43    import jalview.io.DataSourceType;
44    import jalview.io.FileLoader;
45    import jalview.schemes.FeatureColour;
46    import jalview.util.matcher.Condition;
47    import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
48   
49    import java.awt.Color;
50    import java.util.ArrayList;
51    import java.util.Arrays;
52    import java.util.HashMap;
53    import java.util.List;
54    import java.util.Map;
55   
56    import org.testng.annotations.Test;
57   
 
58    public class FeatureRendererTest
59    {
60   
 
61  1 toggle @Test(groups = "Functional")
62    public void testFindAllFeatures()
63    {
64  1 String seqData = ">s1\nabcdef\n>s2\nabcdef\n>s3\nabcdef\n>s4\nabcdef\n";
65  1 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
66    DataSourceType.PASTE);
67  1 AlignViewportI av = af.getViewport();
68  1 FeatureRenderer fr = new FeatureRenderer(av);
69   
70    /*
71    * with no features
72    */
73  1 fr.findAllFeatures(true);
74  1 assertTrue(fr.getRenderOrder().isEmpty());
75  1 assertTrue(fr.getFeatureGroups().isEmpty());
76   
77  1 List<SequenceI> seqs = av.getAlignment().getSequences();
78   
79    // add a non-positional feature - should be ignored by FeatureRenderer
80  1 SequenceFeature sf1 = new SequenceFeature("Type", "Desc", 0, 0, 1f,
81    "Group");
82  1 seqs.get(0).addSequenceFeature(sf1);
83  1 fr.findAllFeatures(true);
84    // ? bug - types and groups added for non-positional features
85  1 List<String> types = fr.getRenderOrder();
86  1 List<String> groups = fr.getFeatureGroups();
87  1 assertEquals(types.size(), 0);
88  1 assertFalse(types.contains("Type"));
89  1 assertEquals(groups.size(), 0);
90  1 assertFalse(groups.contains("Group"));
91   
92    // add some positional features
93  1 seqs.get(1).addSequenceFeature(
94    new SequenceFeature("Pfam", "Desc", 5, 9, 1f, "PfamGroup"));
95  1 seqs.get(2).addSequenceFeature(
96    new SequenceFeature("Pfam", "Desc", 14, 22, 2f, "RfamGroup"));
97    // bug in findAllFeatures - group not checked for a known feature type
98  1 seqs.get(2).addSequenceFeature(new SequenceFeature("Rfam", "Desc", 5, 9,
99    Float.NaN, "RfamGroup"));
100    // existing feature type with null group
101  1 seqs.get(3).addSequenceFeature(
102    new SequenceFeature("Rfam", "Desc", 5, 9, Float.NaN, null));
103    // new feature type with null group
104  1 seqs.get(3).addSequenceFeature(
105    new SequenceFeature("Scop", "Desc", 5, 9, Float.NaN, null));
106    // null value for type produces NullPointerException
107  1 fr.findAllFeatures(true);
108  1 types = fr.getRenderOrder();
109  1 groups = fr.getFeatureGroups();
110  1 assertEquals(types.size(), 3);
111  1 assertFalse(types.contains("Type"));
112  1 assertTrue(types.contains("Pfam"));
113  1 assertTrue(types.contains("Rfam"));
114  1 assertTrue(types.contains("Scop"));
115  1 assertEquals(groups.size(), 2);
116  1 assertFalse(groups.contains("Group"));
117  1 assertTrue(groups.contains("PfamGroup"));
118  1 assertTrue(groups.contains("RfamGroup"));
119  1 assertFalse(groups.contains(null)); // null group is ignored
120   
121    /*
122    * check min-max values
123    */
124  1 Map<String, float[][]> minMax = fr.getMinMax();
125  1 assertEquals(minMax.size(), 1); // non-positional and NaN not stored
126  1 assertEquals(minMax.get("Pfam")[0][0], 1f); // positional min
127  1 assertEquals(minMax.get("Pfam")[0][1], 2f); // positional max
128   
129    // increase max for Pfam, add scores for Rfam
130  1 seqs.get(0).addSequenceFeature(
131    new SequenceFeature("Pfam", "Desc", 14, 22, 8f, "RfamGroup"));
132  1 seqs.get(1).addSequenceFeature(
133    new SequenceFeature("Rfam", "Desc", 5, 9, 6f, "RfamGroup"));
134  1 fr.findAllFeatures(true);
135    // note minMax is not a defensive copy, shouldn't expose this
136  1 assertEquals(minMax.size(), 2);
137  1 assertEquals(minMax.get("Pfam")[0][0], 1f);
138  1 assertEquals(minMax.get("Pfam")[0][1], 8f);
139  1 assertEquals(minMax.get("Rfam")[0][0], 6f);
140  1 assertEquals(minMax.get("Rfam")[0][1], 6f);
141   
142    /*
143    * check render order (last is on top)
144    */
145  1 List<String> renderOrder = fr.getRenderOrder();
146  1 assertEquals(renderOrder, Arrays.asList("Scop", "Rfam", "Pfam"));
147   
148    /*
149    * change render order (todo: an easier way)
150    * nb here last comes first in the data array
151    */
152  1 FeatureSettingsBean[] data = new FeatureSettingsBean[3];
153  1 FeatureColourI colour = new FeatureColour(Color.RED);
154  1 data[0] = new FeatureSettingsBean("Rfam", colour, null, true);
155  1 data[1] = new FeatureSettingsBean("Pfam", colour, null, false);
156  1 data[2] = new FeatureSettingsBean("Scop", colour, null, false);
157  1 fr.setFeaturePriority(data);
158  1 assertEquals(fr.getRenderOrder(),
159    Arrays.asList("Scop", "Pfam", "Rfam"));
160  1 assertEquals(fr.getDisplayedFeatureTypes(), Arrays.asList("Rfam"));
161   
162    /*
163    * add a new feature type: should go on top of render order as visible,
164    * other feature ordering and visibility should be unchanged
165    */
166  1 seqs.get(2).addSequenceFeature(
167    new SequenceFeature("Metal", "Desc", 14, 22, 8f, "MetalGroup"));
168  1 fr.findAllFeatures(true);
169  1 assertEquals(fr.getRenderOrder(),
170    Arrays.asList("Scop", "Pfam", "Rfam", "Metal"));
171  1 assertEquals(fr.getDisplayedFeatureTypes(),
172    Arrays.asList("Rfam", "Metal"));
173    }
174   
 
175  1 toggle @Test(groups = "Functional")
176    public void testFindFeaturesAtColumn()
177    {
178  1 String seqData = ">s1/4-29\n-ab--cdefghijklmnopqrstuvwxyz\n";
179  1 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
180    DataSourceType.PASTE);
181  1 AlignViewportI av = af.getViewport();
182  1 FeatureRenderer fr = new FeatureRenderer(av);
183  1 SequenceI seq = av.getAlignment().getSequenceAt(0);
184   
185    /*
186    * with no features
187    */
188  1 List<SequenceFeature> features = fr.findFeaturesAtColumn(seq, 3);
189  1 assertTrue(features.isEmpty());
190   
191    /*
192    * add features
193    */
194  1 SequenceFeature sf1 = new SequenceFeature("Type1", "Desc", 0, 0, 1f,
195    "Group"); // non-positional
196  1 seq.addSequenceFeature(sf1);
197  1 SequenceFeature sf2 = new SequenceFeature("Type2", "Desc", 8, 18, 1f,
198    "Group1");
199  1 seq.addSequenceFeature(sf2);
200  1 SequenceFeature sf3 = new SequenceFeature("Type3", "Desc", 8, 18, 1f,
201    "Group2");
202  1 seq.addSequenceFeature(sf3);
203  1 SequenceFeature sf4 = new SequenceFeature("Type3", "Desc", 8, 18, 1f,
204    null); // null group is always treated as visible
205  1 seq.addSequenceFeature(sf4);
206   
207    /*
208    * add contact features
209    */
210  1 SequenceFeature sf5 = new SequenceFeature("Disulphide Bond", "Desc", 7,
211    15, 1f, "Group1");
212  1 seq.addSequenceFeature(sf5);
213  1 SequenceFeature sf6 = new SequenceFeature("Disulphide Bond", "Desc", 7,
214    15, 1f, "Group2");
215  1 seq.addSequenceFeature(sf6);
216  1 SequenceFeature sf7 = new SequenceFeature("Disulphide Bond", "Desc", 7,
217    15, 1f, null);
218  1 seq.addSequenceFeature(sf7);
219   
220    // feature spanning B--C
221  1 SequenceFeature sf8 = new SequenceFeature("Type1", "Desc", 5, 6, 1f,
222    "Group");
223  1 seq.addSequenceFeature(sf8);
224    // contact feature B/C
225  1 SequenceFeature sf9 = new SequenceFeature("Disulphide Bond", "Desc", 5,
226    6, 1f, "Group");
227  1 seq.addSequenceFeature(sf9);
228   
229    /*
230    * let feature renderer discover features (and make visible)
231    */
232  1 fr.findAllFeatures(true);
233  1 features = fr.findFeaturesAtColumn(seq, 15); // all positional
234  1 assertEquals(features.size(), 6);
235  1 assertTrue(features.contains(sf2));
236  1 assertTrue(features.contains(sf3));
237  1 assertTrue(features.contains(sf4));
238  1 assertTrue(features.contains(sf5));
239  1 assertTrue(features.contains(sf6));
240  1 assertTrue(features.contains(sf7));
241   
242    /*
243    * at a non-contact position
244    */
245  1 features = fr.findFeaturesAtColumn(seq, 14);
246  1 assertEquals(features.size(), 3);
247  1 assertTrue(features.contains(sf2));
248  1 assertTrue(features.contains(sf3));
249  1 assertTrue(features.contains(sf4));
250   
251    /*
252    * make "Type2" not displayed
253    */
254  1 FeatureColourI colour = new FeatureColour(Color.RED);
255  1 FeatureSettingsBean[] data = new FeatureSettingsBean[4];
256  1 data[0] = new FeatureSettingsBean("Type1", colour, null, true);
257  1 data[1] = new FeatureSettingsBean("Type2", colour, null, false);
258  1 data[2] = new FeatureSettingsBean("Type3", colour, null, true);
259  1 data[3] = new FeatureSettingsBean("Disulphide Bond", colour, null,
260    true);
261  1 fr.setFeaturePriority(data);
262   
263  1 features = fr.findFeaturesAtColumn(seq, 15);
264  1 assertEquals(features.size(), 5); // no sf2
265  1 assertTrue(features.contains(sf3));
266  1 assertTrue(features.contains(sf4));
267  1 assertTrue(features.contains(sf5));
268  1 assertTrue(features.contains(sf6));
269  1 assertTrue(features.contains(sf7));
270   
271    /*
272    * make "Group2" not displayed
273    */
274  1 fr.setGroupVisibility("Group2", false);
275   
276  1 features = fr.findFeaturesAtColumn(seq, 15);
277  1 assertEquals(features.size(), 3); // no sf2, sf3, sf6
278  1 assertTrue(features.contains(sf4));
279  1 assertTrue(features.contains(sf5));
280  1 assertTrue(features.contains(sf7));
281   
282    // features 'at' a gap between b and c
283    // - returns enclosing feature BC but not contact feature B/C
284  1 features = fr.findFeaturesAtColumn(seq, 4);
285  1 assertEquals(features.size(), 1);
286  1 assertTrue(features.contains(sf8));
287  1 features = fr.findFeaturesAtColumn(seq, 5);
288  1 assertEquals(features.size(), 1);
289  1 assertTrue(features.contains(sf8));
290   
291    /*
292    * give "Type3" features a graduated colour scheme
293    * - first with no threshold
294    */
295  1 FeatureColourI gc = new FeatureColour(Color.green, Color.yellow,
296    Color.red, null, 0f, 10f);
297  1 fr.getFeatureColours().put("Type3", gc);
298  1 features = fr.findFeaturesAtColumn(seq, 8);
299  1 assertTrue(features.contains(sf4));
300    // now with threshold > 2f - feature score of 1f is excluded
301  1 gc.setAboveThreshold(true);
302  1 gc.setThreshold(2f);
303  1 features = fr.findFeaturesAtColumn(seq, 8);
304  1 assertFalse(features.contains(sf4));
305   
306    /*
307    * make "Type3" graduated colour by attribute "AF"
308    * - first with no attribute held - feature should be excluded
309    */
310  1 gc.setAttributeName("AF");
311  1 features = fr.findFeaturesAtColumn(seq, 8);
312  1 assertFalse(features.contains(sf4));
313    // now with the attribute above threshold - should be included
314  1 sf4.setValue("AF", "2.4");
315  1 features = fr.findFeaturesAtColumn(seq, 8);
316  1 assertTrue(features.contains(sf4));
317    // now with the attribute below threshold - should be excluded
318  1 sf4.setValue("AF", "1.4");
319  1 features = fr.findFeaturesAtColumn(seq, 8);
320  1 assertFalse(features.contains(sf4));
321    }
322   
 
323  1 toggle @Test(groups = "Functional")
324    public void testFilterFeaturesForDisplay()
325    {
326  1 String seqData = ">s1\nabcdef\n";
327  1 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
328    DataSourceType.PASTE);
329  1 AlignViewportI av = af.getViewport();
330  1 FeatureRenderer fr = new FeatureRenderer(av);
331   
332  1 List<SequenceFeature> features = new ArrayList<>();
333  1 fr.filterFeaturesForDisplay(features); // empty list, does nothing
334   
335  1 SequenceI seq = av.getAlignment().getSequenceAt(0);
336  1 SequenceFeature sf1 = new SequenceFeature("Cath", "", 6, 8, Float.NaN,
337    "group1");
338  1 SequenceFeature sf2 = new SequenceFeature("Cath", "", 5, 11, 2f,
339    "group2");
340  1 SequenceFeature sf3 = new SequenceFeature("Cath", "", 5, 11, 3f,
341    "group3");
342  1 SequenceFeature sf4 = new SequenceFeature("Cath", "", 6, 8, 4f,
343    "group4");
344  1 SequenceFeature sf5 = new SequenceFeature("Cath", "", 6, 9, 5f,
345    "group4");
346  1 seq.addSequenceFeature(sf1);
347  1 seq.addSequenceFeature(sf2);
348  1 seq.addSequenceFeature(sf3);
349  1 seq.addSequenceFeature(sf4);
350  1 seq.addSequenceFeature(sf5);
351   
352  1 fr.findAllFeatures(true);
353   
354  1 features = seq.getSequenceFeatures();
355  1 assertEquals(features.size(), 5);
356  1 assertTrue(features.contains(sf1));
357  1 assertTrue(features.contains(sf2));
358  1 assertTrue(features.contains(sf3));
359  1 assertTrue(features.contains(sf4));
360  1 assertTrue(features.contains(sf5));
361   
362    /*
363    * filter out duplicate (co-located) features
364    * note: which gets removed is not guaranteed
365    */
366  1 fr.filterFeaturesForDisplay(features);
367  1 assertEquals(features.size(), 3);
368  1 assertTrue(features.contains(sf1) || features.contains(sf4));
369  1 assertFalse(features.contains(sf1) && features.contains(sf4));
370  1 assertTrue(features.contains(sf2) || features.contains(sf3));
371  1 assertFalse(features.contains(sf2) && features.contains(sf3));
372  1 assertTrue(features.contains(sf5));
373   
374    /*
375    * features in hidden groups are removed
376    */
377  1 fr.setGroupVisibility("group2", false);
378  1 fr.setGroupVisibility("group3", false);
379  1 features = seq.getSequenceFeatures();
380  1 fr.filterFeaturesForDisplay(features);
381  1 assertEquals(features.size(), 2);
382  1 assertTrue(features.contains(sf1) || features.contains(sf4));
383  1 assertFalse(features.contains(sf1) && features.contains(sf4));
384  1 assertFalse(features.contains(sf2));
385  1 assertFalse(features.contains(sf3));
386  1 assertTrue(features.contains(sf5));
387   
388    /*
389    * no filtering if transparency is applied
390    */
391  1 fr.setTransparency(0.5f);
392  1 features = seq.getSequenceFeatures();
393  1 fr.filterFeaturesForDisplay(features);
394  1 assertEquals(features.size(), 5);
395    }
396   
 
397  1 toggle @Test(groups = "Functional")
398    public void testGetColour()
399    {
400  1 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(">s1\nABCD\n",
401    DataSourceType.PASTE);
402  1 AlignViewportI av = af.getViewport();
403  1 FeatureRenderer fr = new FeatureRenderer(av);
404   
405    /*
406    * simple colour, feature type and group displayed
407    */
408  1 FeatureColourI fc = new FeatureColour(Color.red);
409  1 fr.getFeatureColours().put("Cath", fc);
410  1 SequenceFeature sf1 = new SequenceFeature("Cath", "", 6, 8, Float.NaN,
411    "group1");
412  1 assertEquals(fr.getColour(sf1), Color.red);
413   
414    /*
415    * hide feature type, then unhide
416    * - feature type visibility should not affect the result
417    */
418  1 FeatureSettingsBean[] data = new FeatureSettingsBean[1];
419  1 data[0] = new FeatureSettingsBean("Cath", fc, null, false);
420  1 fr.setFeaturePriority(data);
421  1 assertEquals(fr.getColour(sf1), Color.red);
422  1 data[0] = new FeatureSettingsBean("Cath", fc, null, true);
423  1 fr.setFeaturePriority(data);
424  1 assertEquals(fr.getColour(sf1), Color.red);
425   
426    /*
427    * hide feature group, then unhide
428    */
429  1 fr.setGroupVisibility("group1", false);
430  1 assertNull(fr.getColour(sf1));
431  1 fr.setGroupVisibility("group1", true);
432  1 assertEquals(fr.getColour(sf1), Color.red);
433   
434    /*
435    * graduated colour by score, no threshold, no score
436    *
437    */
438  1 FeatureColourI gc = new FeatureColour(Color.red, Color.yellow,
439    Color.red, Color.green, 1f, 11f);
440  1 fr.getFeatureColours().put("Cath", gc);
441  1 assertEquals(fr.getColour(sf1), Color.green);
442   
443    /*
444    * graduated colour by score, no threshold, with score value
445    */
446  1 SequenceFeature sf2 = new SequenceFeature("Cath", "", 6, 8, 6f,
447    "group1");
448    // score 6 is half way from yellow(255, 255, 0) to red(255, 0, 0)
449  1 Color expected = new Color(255, 128, 0);
450  1 assertEquals(fr.getColour(sf2), expected);
451   
452    /*
453    * above threshold, score is above threshold - no change
454    */
455  1 gc.setAboveThreshold(true);
456  1 gc.setThreshold(5f);
457  1 assertEquals(fr.getColour(sf2), expected);
458   
459    /*
460    * threshold is min-max; now score 6 is 1/6 of the way from 5 to 11
461    * or from yellow(255, 255, 0) to red(255, 0, 0)
462    */
463  1 gc = new FeatureColour(Color.red, Color.yellow, Color.red, Color.green,
464    5f, 11f);
465  1 fr.getFeatureColours().put("Cath", gc);
466  1 gc.setAutoScaled(false); // this does little other than save a checkbox setting!
467  1 assertEquals(fr.getColour(sf2), new Color(255, 213, 0));
468   
469    /*
470    * feature score is below threshold - no colour
471    */
472  1 gc.setAboveThreshold(true);
473  1 gc.setThreshold(7f);
474  1 assertNull(fr.getColour(sf2));
475   
476    /*
477    * feature score is above threshold - no colour
478    */
479  1 gc.setBelowThreshold(true);
480  1 gc.setThreshold(3f);
481  1 assertNull(fr.getColour(sf2));
482   
483    /*
484    * colour by feature attribute value
485    * first with no value held
486    */
487  1 gc = new FeatureColour(Color.red, Color.yellow, Color.red, Color.green,
488    1f, 11f);
489  1 fr.getFeatureColours().put("Cath", gc);
490  1 gc.setAttributeName("AF");
491  1 assertEquals(fr.getColour(sf2), Color.green);
492   
493    // with non-numeric attribute value
494  1 sf2.setValue("AF", "Five");
495  1 assertEquals(fr.getColour(sf2), Color.green);
496   
497    // with numeric attribute value
498  1 sf2.setValue("AF", "6");
499  1 assertEquals(fr.getColour(sf2), expected);
500   
501    // with numeric value outwith threshold
502  1 gc.setAboveThreshold(true);
503  1 gc.setThreshold(10f);
504  1 assertNull(fr.getColour(sf2));
505   
506    // with filter on AF < 4
507  1 gc.setAboveThreshold(false);
508  1 assertEquals(fr.getColour(sf2), expected);
509  1 FeatureMatcherSetI filter = new FeatureMatcherSet();
510  1 filter.and(FeatureMatcher.byAttribute(Condition.LT, "4.0", "AF"));
511  1 fr.setFeatureFilter("Cath", filter);
512  1 assertNull(fr.getColour(sf2));
513   
514    // with filter on 'Consequence contains missense'
515  1 filter = new FeatureMatcherSet();
516  1 filter.and(FeatureMatcher.byAttribute(Condition.Contains, "missense",
517    "Consequence"));
518  1 fr.setFeatureFilter("Cath", filter);
519    // if feature has no Consequence attribute, no colour
520  1 assertNull(fr.getColour(sf2));
521    // if attribute does not match filter, no colour
522  1 sf2.setValue("Consequence", "Synonymous");
523  1 assertNull(fr.getColour(sf2));
524    // attribute matches filter
525  1 sf2.setValue("Consequence", "Missense variant");
526  1 assertEquals(fr.getColour(sf2), expected);
527   
528    // with filter on CSQ:Feature contains "ENST01234"
529  1 filter = new FeatureMatcherSet();
530  1 filter.and(FeatureMatcher.byAttribute(Condition.Matches, "ENST01234",
531    "CSQ", "Feature"));
532  1 fr.setFeatureFilter("Cath", filter);
533    // if feature has no CSQ data, no colour
534  1 assertNull(fr.getColour(sf2));
535    // if CSQ data does not include Feature, no colour
536  1 Map<String, String> csqData = new HashMap<>();
537  1 csqData.put("BIOTYPE", "Transcript");
538  1 sf2.setValue("CSQ", csqData);
539  1 assertNull(fr.getColour(sf2));
540    // if attribute does not match filter, no colour
541  1 csqData.put("Feature", "ENST9876");
542  1 assertNull(fr.getColour(sf2));
543    // attribute matches filter
544  1 csqData.put("Feature", "ENST01234");
545  1 assertEquals(fr.getColour(sf2), expected);
546    }
547   
 
548  1 toggle @Test(groups = "Functional")
549    public void testIsVisible()
550    {
551  1 String seqData = ">s1\nMLQGIFPRS\n";
552  1 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
553    DataSourceType.PASTE);
554  1 AlignViewportI av = af.getViewport();
555  1 FeatureRenderer fr = new FeatureRenderer(av);
556  1 SequenceI seq = av.getAlignment().getSequenceAt(0);
557  1 SequenceFeature sf = new SequenceFeature("METAL", "Desc", 10, 10, 1f,
558    "Group");
559  1 sf.setValue("AC", "11");
560  1 sf.setValue("CLIN_SIG", "Likely Pathogenic");
561  1 seq.addSequenceFeature(sf);
562   
563  1 assertFalse(fr.isVisible(null));
564   
565    /*
566    * initial state FeatureRenderer hasn't 'found' feature
567    * and so its feature type has not yet been set visible
568    */
569  1 assertFalse(fr.getDisplayedFeatureCols().containsKey("METAL"));
570  1 assertFalse(fr.isVisible(sf));
571   
572  1 fr.findAllFeatures(true);
573  1 assertTrue(fr.isVisible(sf));
574   
575    /*
576    * feature group not visible
577    */
578  1 fr.setGroupVisibility("Group", false);
579  1 assertFalse(fr.isVisible(sf));
580  1 fr.setGroupVisibility("Group", true);
581  1 assertTrue(fr.isVisible(sf));
582   
583    /*
584    * feature score outwith colour threshold (score > 2)
585    */
586  1 FeatureColourI fc = new FeatureColour(null, Color.white, Color.black,
587    Color.white, 0, 10);
588  1 fc.setAboveThreshold(true);
589  1 fc.setThreshold(2f);
590  1 fr.setColour("METAL", fc);
591  1 assertFalse(fr.isVisible(sf)); // score 1 is not above threshold 2
592  1 fc.setBelowThreshold(true);
593  1 assertTrue(fr.isVisible(sf)); // score 1 is below threshold 2
594   
595    /*
596    * colour with threshold on attribute AC (value is 11)
597    */
598  1 fc.setAttributeName("AC");
599  1 assertFalse(fr.isVisible(sf)); // value 11 is not below threshold 2
600  1 fc.setAboveThreshold(true);
601  1 assertTrue(fr.isVisible(sf)); // value 11 is above threshold 2
602   
603  1 fc.setAttributeName("AF"); // attribute AF is absent in sf
604  1 assertTrue(fr.isVisible(sf)); // feature is not excluded by threshold
605   
606  1 FeatureMatcherSetI filter = new FeatureMatcherSet();
607  1 filter.and(FeatureMatcher.byAttribute(Condition.Contains, "pathogenic",
608    "CLIN_SIG"));
609  1 fr.setFeatureFilter("METAL", filter);
610  1 assertTrue(fr.isVisible(sf)); // feature matches filter
611  1 filter.and(FeatureMatcher.byScore(Condition.LE, "0.4"));
612  1 assertFalse(fr.isVisible(sf)); // feature doesn't match filter
613    }
614   
 
615  1 toggle @Test(groups = "Functional")
616    public void testFindComplementFeaturesAtResidue()
617    {
618  1 Jalview.main(
619    new String[]
620    { "-nonews", "-props", "test/jalview/testProps.jvprops" });
621   
622    // codons for MCWHSE
623  1 String cdsSeq = ">cds\nATGtgtTGGcacTCAgaa";
624  1 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(cdsSeq,
625    DataSourceType.PASTE);
626  1 af.showTranslation_actionPerformed(
627    GeneticCodes.getInstance().getStandardCodeTable());
628  1 af.closeMenuItem_actionPerformed(true);
629   
630    /*
631    * find the complement frames (ugly)
632    */
633  1 AlignFrame[] frames = Desktop.getAlignFrames();
634  1 assertEquals(frames.length, 2);
635  1 AlignViewport av1 = frames[0].getViewport();
636  1 AlignViewport av2 = frames[1].getViewport();
637  1 AlignViewport cds = av1.getAlignment().isNucleotide() ? av1 : av2;
638  1 AlignViewport peptide = cds == av1 ? av2 : av1;
639  1 assertNotNull(cds);
640  1 assertNotNull(peptide);
641   
642    /*
643    * add features to CDS at first codon, positions 2-3
644    */
645  1 SequenceI seq1 = cds.getAlignment().getSequenceAt(0);
646  1 SequenceFeature sf1 = new SequenceFeature("sequence_variant", "G,GT", 2,
647    2, "ensembl");
648  1 seq1.addSequenceFeature(sf1);
649  1 SequenceFeature sf2 = new SequenceFeature("sequence_variant", "C, CA",
650    3, 3, "ensembl");
651  1 seq1.addSequenceFeature(sf2);
652   
653    /*
654    * 'find' mapped features from the peptide position
655    * - first with CDS features _not_ shown on peptide alignment
656    */
657  1 SequenceI seq2 = peptide.getAlignment().getSequenceAt(0);
658  1 FeatureRenderer frC = new FeatureRenderer(cds);
659  1 frC.featuresAdded();
660  1 MappedFeatures mf = frC.findComplementFeaturesAtResidue(seq2, 1);
661  1 assertNotNull(mf);
662  1 assertEquals(mf.features.size(), 2);
663  1 assertSame(mf.features.get(0), sf1);
664  1 assertSame(mf.features.get(1), sf2);
665   
666    /*
667    * add exon feature and verify it is only returned once for a
668    * peptide position, even though it is on all 3 codon positions
669    */
670  1 SequenceFeature sf3 = new SequenceFeature("exon", "exon1", 4, 12,
671    "ensembl");
672  1 seq1.addSequenceFeature(sf3);
673  1 frC.featuresAdded();
674  1 mf = frC.findComplementFeaturesAtResidue(seq2, 3);
675  1 assertNotNull(mf);
676  1 assertEquals(mf.features.size(), 1);
677  1 assertSame(mf.features.get(0), sf3);
678    }
679    }