Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 14:43:25 GMT
  2. Package jalview.renderer.seqfeatures

File FeatureRendererTest.java

 

Code metrics

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