Clover icon

Coverage Report

  1. Project Clover database Wed Nov 13 2024 16:12:26 GMT
  2. Package jalview.renderer.seqfeatures

File FeatureRendererTest.java

 

Code metrics

6
335
7
1
687
449
10
0.03
47.86
7
1.43

Classes

Class Line # Actions
FeatureRendererTest 59 335 10
0.991379399.1%
 

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