Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package jalview.renderer.seqfeatures

File FeatureRendererTest.java

 

Code metrics

0
263
4
1
538
344
4
0.02
65.75
4
1

Classes

Class Line # Actions
FeatureRendererTest 51 263 4 0
1.0100%
 

Contributing tests

This file is covered by 4 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.assertNull;
26    import static org.testng.Assert.assertTrue;
27   
28    import jalview.api.AlignViewportI;
29    import jalview.api.FeatureColourI;
30    import jalview.datamodel.SequenceFeature;
31    import jalview.datamodel.SequenceI;
32    import jalview.datamodel.features.FeatureMatcher;
33    import jalview.datamodel.features.FeatureMatcherSet;
34    import jalview.datamodel.features.FeatureMatcherSetI;
35    import jalview.gui.AlignFrame;
36    import jalview.io.DataSourceType;
37    import jalview.io.FileLoader;
38    import jalview.schemes.FeatureColour;
39    import jalview.util.matcher.Condition;
40    import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
41   
42    import java.awt.Color;
43    import java.util.ArrayList;
44    import java.util.Arrays;
45    import java.util.HashMap;
46    import java.util.List;
47    import java.util.Map;
48   
49    import org.testng.annotations.Test;
50   
 
51    public class FeatureRendererTest
52    {
53   
 
54  1 toggle @Test(groups = "Functional")
55    public void testFindAllFeatures()
56    {
57  1 String seqData = ">s1\nabcdef\n>s2\nabcdef\n>s3\nabcdef\n>s4\nabcdef\n";
58  1 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
59    DataSourceType.PASTE);
60  1 AlignViewportI av = af.getViewport();
61  1 FeatureRenderer fr = new FeatureRenderer(av);
62   
63    /*
64    * with no features
65    */
66  1 fr.findAllFeatures(true);
67  1 assertTrue(fr.getRenderOrder().isEmpty());
68  1 assertTrue(fr.getFeatureGroups().isEmpty());
69   
70  1 List<SequenceI> seqs = av.getAlignment().getSequences();
71   
72    // add a non-positional feature - should be ignored by FeatureRenderer
73  1 SequenceFeature sf1 = new SequenceFeature("Type", "Desc", 0, 0, 1f,
74    "Group");
75  1 seqs.get(0).addSequenceFeature(sf1);
76  1 fr.findAllFeatures(true);
77    // ? bug - types and groups added for non-positional features
78  1 List<String> types = fr.getRenderOrder();
79  1 List<String> groups = fr.getFeatureGroups();
80  1 assertEquals(types.size(), 0);
81  1 assertFalse(types.contains("Type"));
82  1 assertEquals(groups.size(), 0);
83  1 assertFalse(groups.contains("Group"));
84   
85    // add some positional features
86  1 seqs.get(1).addSequenceFeature(
87    new SequenceFeature("Pfam", "Desc", 5, 9, 1f, "PfamGroup"));
88  1 seqs.get(2).addSequenceFeature(
89    new SequenceFeature("Pfam", "Desc", 14, 22, 2f, "RfamGroup"));
90    // bug in findAllFeatures - group not checked for a known feature type
91  1 seqs.get(2).addSequenceFeature(new SequenceFeature("Rfam", "Desc", 5, 9,
92    Float.NaN, "RfamGroup"));
93    // existing feature type with null group
94  1 seqs.get(3).addSequenceFeature(
95    new SequenceFeature("Rfam", "Desc", 5, 9, Float.NaN, null));
96    // new feature type with null group
97  1 seqs.get(3).addSequenceFeature(
98    new SequenceFeature("Scop", "Desc", 5, 9, Float.NaN, null));
99    // null value for type produces NullPointerException
100  1 fr.findAllFeatures(true);
101  1 types = fr.getRenderOrder();
102  1 groups = fr.getFeatureGroups();
103  1 assertEquals(types.size(), 3);
104  1 assertFalse(types.contains("Type"));
105  1 assertTrue(types.contains("Pfam"));
106  1 assertTrue(types.contains("Rfam"));
107  1 assertTrue(types.contains("Scop"));
108  1 assertEquals(groups.size(), 2);
109  1 assertFalse(groups.contains("Group"));
110  1 assertTrue(groups.contains("PfamGroup"));
111  1 assertTrue(groups.contains("RfamGroup"));
112  1 assertFalse(groups.contains(null)); // null group is ignored
113   
114    /*
115    * check min-max values
116    */
117  1 Map<String, float[][]> minMax = fr.getMinMax();
118  1 assertEquals(minMax.size(), 1); // non-positional and NaN not stored
119  1 assertEquals(minMax.get("Pfam")[0][0], 1f); // positional min
120  1 assertEquals(minMax.get("Pfam")[0][1], 2f); // positional max
121   
122    // increase max for Pfam, add scores for Rfam
123  1 seqs.get(0).addSequenceFeature(
124    new SequenceFeature("Pfam", "Desc", 14, 22, 8f, "RfamGroup"));
125  1 seqs.get(1).addSequenceFeature(
126    new SequenceFeature("Rfam", "Desc", 5, 9, 6f, "RfamGroup"));
127  1 fr.findAllFeatures(true);
128    // note minMax is not a defensive copy, shouldn't expose this
129  1 assertEquals(minMax.size(), 2);
130  1 assertEquals(minMax.get("Pfam")[0][0], 1f);
131  1 assertEquals(minMax.get("Pfam")[0][1], 8f);
132  1 assertEquals(minMax.get("Rfam")[0][0], 6f);
133  1 assertEquals(minMax.get("Rfam")[0][1], 6f);
134   
135    /*
136    * check render order (last is on top)
137    */
138  1 List<String> renderOrder = fr.getRenderOrder();
139  1 assertEquals(renderOrder, Arrays.asList("Scop", "Rfam", "Pfam"));
140   
141    /*
142    * change render order (todo: an easier way)
143    * nb here last comes first in the data array
144    */
145  1 FeatureSettingsBean[] data = new FeatureSettingsBean[3];
146  1 FeatureColourI colour = new FeatureColour(Color.RED);
147  1 data[0] = new FeatureSettingsBean("Rfam", colour, null, true);
148  1 data[1] = new FeatureSettingsBean("Pfam", colour, null, false);
149  1 data[2] = new FeatureSettingsBean("Scop", colour, null, false);
150  1 fr.setFeaturePriority(data);
151  1 assertEquals(fr.getRenderOrder(),
152    Arrays.asList("Scop", "Pfam", "Rfam"));
153  1 assertEquals(fr.getDisplayedFeatureTypes(), Arrays.asList("Rfam"));
154   
155    /*
156    * add a new feature type: should go on top of render order as visible,
157    * other feature ordering and visibility should be unchanged
158    */
159  1 seqs.get(2).addSequenceFeature(
160    new SequenceFeature("Metal", "Desc", 14, 22, 8f, "MetalGroup"));
161  1 fr.findAllFeatures(true);
162  1 assertEquals(fr.getRenderOrder(),
163    Arrays.asList("Scop", "Pfam", "Rfam", "Metal"));
164  1 assertEquals(fr.getDisplayedFeatureTypes(),
165    Arrays.asList("Rfam", "Metal"));
166    }
167   
 
168  1 toggle @Test(groups = "Functional")
169    public void testFindFeaturesAtColumn()
170    {
171  1 String seqData = ">s1/4-29\n-ab--cdefghijklmnopqrstuvwxyz\n";
172  1 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
173    DataSourceType.PASTE);
174  1 AlignViewportI av = af.getViewport();
175  1 FeatureRenderer fr = new FeatureRenderer(av);
176  1 SequenceI seq = av.getAlignment().getSequenceAt(0);
177   
178    /*
179    * with no features
180    */
181  1 List<SequenceFeature> features = fr.findFeaturesAtColumn(seq, 3);
182  1 assertTrue(features.isEmpty());
183   
184    /*
185    * add features
186    */
187  1 SequenceFeature sf1 = new SequenceFeature("Type1", "Desc", 0, 0, 1f,
188    "Group"); // non-positional
189  1 seq.addSequenceFeature(sf1);
190  1 SequenceFeature sf2 = new SequenceFeature("Type2", "Desc", 8, 18, 1f,
191    "Group1");
192  1 seq.addSequenceFeature(sf2);
193  1 SequenceFeature sf3 = new SequenceFeature("Type3", "Desc", 8, 18, 1f,
194    "Group2");
195  1 seq.addSequenceFeature(sf3);
196  1 SequenceFeature sf4 = new SequenceFeature("Type3", "Desc", 8, 18, 1f,
197    null); // null group is always treated as visible
198  1 seq.addSequenceFeature(sf4);
199   
200    /*
201    * add contact features
202    */
203  1 SequenceFeature sf5 = new SequenceFeature("Disulphide Bond", "Desc", 7,
204    15, 1f, "Group1");
205  1 seq.addSequenceFeature(sf5);
206  1 SequenceFeature sf6 = new SequenceFeature("Disulphide Bond", "Desc", 7,
207    15, 1f, "Group2");
208  1 seq.addSequenceFeature(sf6);
209  1 SequenceFeature sf7 = new SequenceFeature("Disulphide Bond", "Desc", 7,
210    15, 1f, null);
211  1 seq.addSequenceFeature(sf7);
212   
213    // feature spanning B--C
214  1 SequenceFeature sf8 = new SequenceFeature("Type1", "Desc", 5, 6, 1f,
215    "Group");
216  1 seq.addSequenceFeature(sf8);
217    // contact feature B/C
218  1 SequenceFeature sf9 = new SequenceFeature("Disulphide Bond", "Desc", 5,
219    6, 1f, "Group");
220  1 seq.addSequenceFeature(sf9);
221   
222    /*
223    * let feature renderer discover features (and make visible)
224    */
225  1 fr.findAllFeatures(true);
226  1 features = fr.findFeaturesAtColumn(seq, 15); // all positional
227  1 assertEquals(features.size(), 6);
228  1 assertTrue(features.contains(sf2));
229  1 assertTrue(features.contains(sf3));
230  1 assertTrue(features.contains(sf4));
231  1 assertTrue(features.contains(sf5));
232  1 assertTrue(features.contains(sf6));
233  1 assertTrue(features.contains(sf7));
234   
235    /*
236    * at a non-contact position
237    */
238  1 features = fr.findFeaturesAtColumn(seq, 14);
239  1 assertEquals(features.size(), 3);
240  1 assertTrue(features.contains(sf2));
241  1 assertTrue(features.contains(sf3));
242  1 assertTrue(features.contains(sf4));
243   
244    /*
245    * make "Type2" not displayed
246    */
247  1 FeatureColourI colour = new FeatureColour(Color.RED);
248  1 FeatureSettingsBean[] data = new FeatureSettingsBean[4];
249  1 data[0] = new FeatureSettingsBean("Type1", colour, null, true);
250  1 data[1] = new FeatureSettingsBean("Type2", colour, null, false);
251  1 data[2] = new FeatureSettingsBean("Type3", colour, null, true);
252  1 data[3] = new FeatureSettingsBean("Disulphide Bond", colour, null,
253    true);
254  1 fr.setFeaturePriority(data);
255   
256  1 features = fr.findFeaturesAtColumn(seq, 15);
257  1 assertEquals(features.size(), 5); // no sf2
258  1 assertTrue(features.contains(sf3));
259  1 assertTrue(features.contains(sf4));
260  1 assertTrue(features.contains(sf5));
261  1 assertTrue(features.contains(sf6));
262  1 assertTrue(features.contains(sf7));
263   
264    /*
265    * make "Group2" not displayed
266    */
267  1 fr.setGroupVisibility("Group2", false);
268   
269  1 features = fr.findFeaturesAtColumn(seq, 15);
270  1 assertEquals(features.size(), 3); // no sf2, sf3, sf6
271  1 assertTrue(features.contains(sf4));
272  1 assertTrue(features.contains(sf5));
273  1 assertTrue(features.contains(sf7));
274   
275    // features 'at' a gap between b and c
276    // - returns enclosing feature BC but not contact feature B/C
277  1 features = fr.findFeaturesAtColumn(seq, 4);
278  1 assertEquals(features.size(), 1);
279  1 assertTrue(features.contains(sf8));
280  1 features = fr.findFeaturesAtColumn(seq, 5);
281  1 assertEquals(features.size(), 1);
282  1 assertTrue(features.contains(sf8));
283   
284    /*
285    * give "Type3" features a graduated colour scheme
286    * - first with no threshold
287    */
288  1 FeatureColourI gc = new FeatureColour(Color.yellow, Color.red, null, 0f,
289    10f);
290  1 fr.getFeatureColours().put("Type3", gc);
291  1 features = fr.findFeaturesAtColumn(seq, 8);
292  1 assertTrue(features.contains(sf4));
293    // now with threshold > 2f - feature score of 1f is excluded
294  1 gc.setAboveThreshold(true);
295  1 gc.setThreshold(2f);
296  1 features = fr.findFeaturesAtColumn(seq, 8);
297  1 assertFalse(features.contains(sf4));
298   
299    /*
300    * make "Type3" graduated colour by attribute "AF"
301    * - first with no attribute held - feature should be excluded
302    */
303  1 gc.setAttributeName("AF");
304  1 features = fr.findFeaturesAtColumn(seq, 8);
305  1 assertFalse(features.contains(sf4));
306    // now with the attribute above threshold - should be included
307  1 sf4.setValue("AF", "2.4");
308  1 features = fr.findFeaturesAtColumn(seq, 8);
309  1 assertTrue(features.contains(sf4));
310    // now with the attribute below threshold - should be excluded
311  1 sf4.setValue("AF", "1.4");
312  1 features = fr.findFeaturesAtColumn(seq, 8);
313  1 assertFalse(features.contains(sf4));
314    }
315   
 
316  1 toggle @Test(groups = "Functional")
317    public void testFilterFeaturesForDisplay()
318    {
319  1 String seqData = ">s1\nabcdef\n";
320  1 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
321    DataSourceType.PASTE);
322  1 AlignViewportI av = af.getViewport();
323  1 FeatureRenderer fr = new FeatureRenderer(av);
324   
325  1 List<SequenceFeature> features = new ArrayList<>();
326  1 fr.filterFeaturesForDisplay(features); // empty list, does nothing
327   
328  1 SequenceI seq = av.getAlignment().getSequenceAt(0);
329  1 SequenceFeature sf1 = new SequenceFeature("Cath", "", 6, 8, Float.NaN,
330    "group1");
331  1 seq.addSequenceFeature(sf1);
332  1 SequenceFeature sf2 = new SequenceFeature("Cath", "", 5, 11, 2f,
333    "group2");
334  1 seq.addSequenceFeature(sf2);
335  1 SequenceFeature sf3 = new SequenceFeature("Cath", "", 5, 11, 3f,
336    "group3");
337  1 seq.addSequenceFeature(sf3);
338  1 SequenceFeature sf4 = new SequenceFeature("Cath", "", 6, 8, 4f,
339    "group4");
340  1 seq.addSequenceFeature(sf4);
341  1 SequenceFeature sf5 = new SequenceFeature("Cath", "", 6, 9, 5f,
342    "group4");
343  1 seq.addSequenceFeature(sf5);
344   
345  1 fr.findAllFeatures(true);
346   
347  1 features = seq.getSequenceFeatures();
348  1 assertEquals(features.size(), 5);
349  1 assertTrue(features.contains(sf1));
350  1 assertTrue(features.contains(sf2));
351  1 assertTrue(features.contains(sf3));
352  1 assertTrue(features.contains(sf4));
353  1 assertTrue(features.contains(sf5));
354   
355    /*
356    * filter out duplicate (co-located) features
357    * note: which gets removed is not guaranteed
358    */
359  1 fr.filterFeaturesForDisplay(features);
360  1 assertEquals(features.size(), 3);
361  1 assertTrue(features.contains(sf1) || features.contains(sf4));
362  1 assertFalse(features.contains(sf1) && features.contains(sf4));
363  1 assertTrue(features.contains(sf2) || features.contains(sf3));
364  1 assertFalse(features.contains(sf2) && features.contains(sf3));
365  1 assertTrue(features.contains(sf5));
366   
367    /*
368    * hide groups 2 and 3 makes no difference to this method
369    */
370  1 fr.setGroupVisibility("group2", false);
371  1 fr.setGroupVisibility("group3", false);
372  1 features = seq.getSequenceFeatures();
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    * no filtering if transparency is applied
383    */
384  1 fr.setTransparency(0.5f);
385  1 features = seq.getSequenceFeatures();
386  1 fr.filterFeaturesForDisplay(features);
387  1 assertEquals(features.size(), 5);
388    }
389   
 
390  1 toggle @Test(groups = "Functional")
391    public void testGetColour()
392    {
393  1 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(">s1\nABCD\n",
394    DataSourceType.PASTE);
395  1 AlignViewportI av = af.getViewport();
396  1 FeatureRenderer fr = new FeatureRenderer(av);
397   
398    /*
399    * simple colour, feature type and group displayed
400    */
401  1 FeatureColourI fc = new FeatureColour(Color.red);
402  1 fr.getFeatureColours().put("Cath", fc);
403  1 SequenceFeature sf1 = new SequenceFeature("Cath", "", 6, 8, Float.NaN,
404    "group1");
405  1 assertEquals(fr.getColour(sf1), Color.red);
406   
407    /*
408    * hide feature type, then unhide
409    * - feature type visibility should not affect the result
410    */
411  1 FeatureSettingsBean[] data = new FeatureSettingsBean[1];
412  1 data[0] = new FeatureSettingsBean("Cath", fc, null, false);
413  1 fr.setFeaturePriority(data);
414  1 assertEquals(fr.getColour(sf1), Color.red);
415  1 data[0] = new FeatureSettingsBean("Cath", fc, null, true);
416  1 fr.setFeaturePriority(data);
417  1 assertEquals(fr.getColour(sf1), Color.red);
418   
419    /*
420    * hide feature group, then unhide
421    */
422  1 fr.setGroupVisibility("group1", false);
423  1 assertNull(fr.getColour(sf1));
424  1 fr.setGroupVisibility("group1", true);
425  1 assertEquals(fr.getColour(sf1), Color.red);
426   
427    /*
428    * graduated colour by score, no threshold, no score
429    *
430    */
431  1 FeatureColourI gc = new FeatureColour(Color.yellow, Color.red,
432    Color.green, 1f, 11f);
433  1 fr.getFeatureColours().put("Cath", gc);
434  1 assertEquals(fr.getColour(sf1), Color.green);
435   
436    /*
437    * graduated colour by score, no threshold, with score value
438    */
439  1 SequenceFeature sf2 = new SequenceFeature("Cath", "", 6, 8, 6f,
440    "group1");
441    // score 6 is half way from yellow(255, 255, 0) to red(255, 0, 0)
442  1 Color expected = new Color(255, 128, 0);
443  1 assertEquals(fr.getColour(sf2), expected);
444   
445    /*
446    * above threshold, score is above threshold - no change
447    */
448  1 gc.setAboveThreshold(true);
449  1 gc.setThreshold(5f);
450  1 assertEquals(fr.getColour(sf2), expected);
451   
452    /*
453    * threshold is min-max; now score 6 is 1/6 of the way from 5 to 11
454    * or from yellow(255, 255, 0) to red(255, 0, 0)
455    */
456  1 gc = new FeatureColour(Color.yellow, Color.red, Color.green, 5f, 11f);
457  1 fr.getFeatureColours().put("Cath", gc);
458  1 gc.setAutoScaled(false); // this does little other than save a checkbox setting!
459  1 assertEquals(fr.getColour(sf2), new Color(255, 213, 0));
460   
461    /*
462    * feature score is below threshold - no colour
463    */
464  1 gc.setAboveThreshold(true);
465  1 gc.setThreshold(7f);
466  1 assertNull(fr.getColour(sf2));
467   
468    /*
469    * feature score is above threshold - no colour
470    */
471  1 gc.setBelowThreshold(true);
472  1 gc.setThreshold(3f);
473  1 assertNull(fr.getColour(sf2));
474   
475    /*
476    * colour by feature attribute value
477    * first with no value held
478    */
479  1 gc = new FeatureColour(Color.yellow, Color.red, Color.green, 1f, 11f);
480  1 fr.getFeatureColours().put("Cath", gc);
481  1 gc.setAttributeName("AF");
482  1 assertEquals(fr.getColour(sf2), Color.green);
483   
484    // with non-numeric attribute value
485  1 sf2.setValue("AF", "Five");
486  1 assertEquals(fr.getColour(sf2), Color.green);
487   
488    // with numeric attribute value
489  1 sf2.setValue("AF", "6");
490  1 assertEquals(fr.getColour(sf2), expected);
491   
492    // with numeric value outwith threshold
493  1 gc.setAboveThreshold(true);
494  1 gc.setThreshold(10f);
495  1 assertNull(fr.getColour(sf2));
496   
497    // with filter on AF < 4
498  1 gc.setAboveThreshold(false);
499  1 assertEquals(fr.getColour(sf2), expected);
500  1 FeatureMatcherSetI filter = new FeatureMatcherSet();
501  1 filter.and(FeatureMatcher.byAttribute(Condition.LT, "4.0", "AF"));
502  1 fr.setFeatureFilter("Cath", filter);
503  1 assertNull(fr.getColour(sf2));
504   
505    // with filter on 'Consequence contains missense'
506  1 filter = new FeatureMatcherSet();
507  1 filter.and(FeatureMatcher.byAttribute(Condition.Contains, "missense",
508    "Consequence"));
509  1 fr.setFeatureFilter("Cath", filter);
510    // if feature has no Consequence attribute, no colour
511  1 assertNull(fr.getColour(sf2));
512    // if attribute does not match filter, no colour
513  1 sf2.setValue("Consequence", "Synonymous");
514  1 assertNull(fr.getColour(sf2));
515    // attribute matches filter
516  1 sf2.setValue("Consequence", "Missense variant");
517  1 assertEquals(fr.getColour(sf2), expected);
518   
519    // with filter on CSQ:Feature contains "ENST01234"
520  1 filter = new FeatureMatcherSet();
521  1 filter.and(FeatureMatcher.byAttribute(Condition.Matches, "ENST01234",
522    "CSQ", "Feature"));
523  1 fr.setFeatureFilter("Cath", filter);
524    // if feature has no CSQ data, no colour
525  1 assertNull(fr.getColour(sf2));
526    // if CSQ data does not include Feature, no colour
527  1 Map<String, String> csqData = new HashMap<>();
528  1 csqData.put("BIOTYPE", "Transcript");
529  1 sf2.setValue("CSQ", csqData);
530  1 assertNull(fr.getColour(sf2));
531    // if attribute does not match filter, no colour
532  1 csqData.put("Feature", "ENST9876");
533  1 assertNull(fr.getColour(sf2));
534    // attribute matches filter
535  1 csqData.put("Feature", "ENST01234");
536  1 assertEquals(fr.getColour(sf2), expected);
537    }
538    }