JAL-2754 Sequence.findFeatures(fromCol, toCol)
[jalview.git] / test / jalview / renderer / seqfeatures / FeatureRendererTest.java
1 package jalview.renderer.seqfeatures;
2
3 import static org.testng.Assert.assertEquals;
4 import static org.testng.Assert.assertFalse;
5 import static org.testng.Assert.assertTrue;
6
7 import jalview.api.AlignViewportI;
8 import jalview.api.FeatureColourI;
9 import jalview.datamodel.SequenceFeature;
10 import jalview.datamodel.SequenceI;
11 import jalview.gui.AlignFrame;
12 import jalview.io.DataSourceType;
13 import jalview.io.FileLoader;
14 import jalview.schemes.FeatureColour;
15
16 import java.awt.Color;
17 import java.util.Arrays;
18 import java.util.List;
19 import java.util.Map;
20
21 import org.testng.annotations.Test;
22
23 public class FeatureRendererTest
24 {
25
26   @Test(groups = "Functional")
27   public void testFindAllFeatures()
28   {
29     String seqData = ">s1\nabcdef\n>s2\nabcdef\n>s3\nabcdef\n>s4\nabcdef\n";
30     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
31             DataSourceType.PASTE);
32     AlignViewportI av = af.getViewport();
33     FeatureRenderer fr = new FeatureRenderer(av);
34
35     /*
36      * with no features
37      */
38     fr.findAllFeatures(true);
39     assertTrue(fr.getRenderOrder().isEmpty());
40     assertTrue(fr.getFeatureGroups().isEmpty());
41
42     List<SequenceI> seqs = av.getAlignment().getSequences();
43
44     // add a non-positional feature - should be ignored by FeatureRenderer
45     SequenceFeature sf1 = new SequenceFeature("Type", "Desc", 0, 0, 1f,
46             "Group");
47     seqs.get(0).addSequenceFeature(sf1);
48     fr.findAllFeatures(true);
49     // ? bug - types and groups added for non-positional features
50     List<String> types = fr.getRenderOrder();
51     List<String> groups = fr.getFeatureGroups();
52     assertEquals(types.size(), 0);
53     assertFalse(types.contains("Type"));
54     assertEquals(groups.size(), 0);
55     assertFalse(groups.contains("Group"));
56
57     // add some positional features
58     seqs.get(1).addSequenceFeature(
59             new SequenceFeature("Pfam", "Desc", 5, 9, 1f, "PfamGroup"));
60     seqs.get(2).addSequenceFeature(
61             new SequenceFeature("Pfam", "Desc", 14, 22, 2f, "RfamGroup"));
62     // bug in findAllFeatures - group not checked for a known feature type
63     seqs.get(2).addSequenceFeature(
64             new SequenceFeature("Rfam", "Desc", 5, 9, Float.NaN,
65                     "RfamGroup"));
66     // existing feature type with null group
67     seqs.get(3).addSequenceFeature(
68             new SequenceFeature("Rfam", "Desc", 5, 9, Float.NaN, null));
69     // new feature type with null group
70     seqs.get(3).addSequenceFeature(
71             new SequenceFeature("Scop", "Desc", 5, 9, Float.NaN, null));
72     // null value for type produces NullPointerException
73     fr.findAllFeatures(true);
74     types = fr.getRenderOrder();
75     groups = fr.getFeatureGroups();
76     assertEquals(types.size(), 3);
77     assertFalse(types.contains("Type"));
78     assertTrue(types.contains("Pfam"));
79     assertTrue(types.contains("Rfam"));
80     assertTrue(types.contains("Scop"));
81     assertEquals(groups.size(), 2);
82     assertFalse(groups.contains("Group"));
83     assertTrue(groups.contains("PfamGroup"));
84     assertTrue(groups.contains("RfamGroup"));
85     assertFalse(groups.contains(null)); // null group is ignored
86
87     /*
88      * check min-max values
89      */
90     Map<String, float[][]> minMax = fr.getMinMax();
91     assertEquals(minMax.size(), 1); // non-positional and NaN not stored
92     assertEquals(minMax.get("Pfam")[0][0], 1f); // positional min
93     assertEquals(minMax.get("Pfam")[0][1], 2f); // positional max
94
95     // increase max for Pfam, add scores for Rfam
96     seqs.get(0).addSequenceFeature(
97             new SequenceFeature("Pfam", "Desc", 14, 22, 8f, "RfamGroup"));
98     seqs.get(1).addSequenceFeature(
99             new SequenceFeature("Rfam", "Desc", 5, 9, 6f, "RfamGroup"));
100     fr.findAllFeatures(true);
101     // note minMax is not a defensive copy, shouldn't expose this
102     assertEquals(minMax.size(), 2);
103     assertEquals(minMax.get("Pfam")[0][0], 1f);
104     assertEquals(minMax.get("Pfam")[0][1], 8f);
105     assertEquals(minMax.get("Rfam")[0][0], 6f);
106     assertEquals(minMax.get("Rfam")[0][1], 6f);
107
108     /*
109      * check render order (last is on top)
110      */
111     List<String> renderOrder = fr.getRenderOrder();
112     assertEquals(renderOrder, Arrays.asList("Scop", "Rfam", "Pfam"));
113
114     /*
115      * change render order (todo: an easier way)
116      * nb here last comes first in the data array
117      */
118     Object[][] data = new Object[3][];
119     FeatureColourI colour = new FeatureColour(Color.RED);
120     data[0] = new Object[] { "Rfam", colour, true };
121     data[1] = new Object[] { "Pfam", colour, false };
122     data[2] = new Object[] { "Scop", colour, false };
123     fr.setFeaturePriority(data);
124     assertEquals(fr.getRenderOrder(), Arrays.asList("Scop", "Pfam", "Rfam"));
125     assertEquals(fr.getDisplayedFeatureTypes(), Arrays.asList("Rfam"));
126
127     /*
128      * add a new feature type: should go on top of render order as visible,
129      * other feature ordering and visibility should be unchanged
130      */
131     seqs.get(2).addSequenceFeature(
132             new SequenceFeature("Metal", "Desc", 14, 22, 8f, "MetalGroup"));
133     fr.findAllFeatures(true);
134     assertEquals(fr.getRenderOrder(),
135             Arrays.asList("Scop", "Pfam", "Rfam", "Metal"));
136     assertEquals(fr.getDisplayedFeatureTypes(),
137             Arrays.asList("Rfam", "Metal"));
138   }
139
140   @Test(groups = "Functional")
141   public void testFindFeaturesAtColumn()
142   {
143     String seqData = ">s1/4-29\n-ab--cdefghijklmnopqrstuvwxyz\n";
144     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
145             DataSourceType.PASTE);
146     AlignViewportI av = af.getViewport();
147     FeatureRenderer fr = new FeatureRenderer(av);
148     SequenceI seq = av.getAlignment().getSequenceAt(0);
149
150     /*
151      * with no features
152      */
153     List<SequenceFeature> features = fr.findFeaturesAtColumn(seq, 3);
154     assertTrue(features.isEmpty());
155
156     /*
157      * add features
158      */
159     SequenceFeature sf1 = new SequenceFeature("Type1", "Desc", 0, 0, 1f,
160             "Group"); // non-positional
161     seq.addSequenceFeature(sf1);
162     SequenceFeature sf2 = new SequenceFeature("Type2", "Desc", 8, 18, 1f,
163             "Group1");
164     seq.addSequenceFeature(sf2);
165     SequenceFeature sf3 = new SequenceFeature("Type3", "Desc", 8, 18, 1f,
166             "Group2");
167     seq.addSequenceFeature(sf3);
168     SequenceFeature sf4 = new SequenceFeature("Type3", "Desc", 8, 18, 1f,
169             null); // null group is always treated as visible
170     seq.addSequenceFeature(sf4);
171
172     /*
173      * add contact features
174      */
175     SequenceFeature sf5 = new SequenceFeature("Disulphide Bond", "Desc", 7,
176             15, 1f, "Group1");
177     seq.addSequenceFeature(sf5);
178     SequenceFeature sf6 = new SequenceFeature("Disulphide Bond", "Desc", 7,
179             15, 1f, "Group2");
180     seq.addSequenceFeature(sf6);
181     SequenceFeature sf7 = new SequenceFeature("Disulphide Bond", "Desc", 7,
182             15, 1f, null);
183     seq.addSequenceFeature(sf7);
184
185     // feature spanning B--C
186     SequenceFeature sf8 = new SequenceFeature("Type1", "Desc", 5, 6, 1f,
187             "Group");
188     seq.addSequenceFeature(sf8);
189     // contact feature B/C
190     SequenceFeature sf9 = new SequenceFeature("Disulphide Bond", "Desc", 5,
191             6, 1f, "Group");
192     seq.addSequenceFeature(sf9);
193
194     /*
195      * let feature renderer discover features (and make visible)
196      */
197     fr.findAllFeatures(true);
198     features = fr.findFeaturesAtColumn(seq, 15); // all positional
199     assertEquals(features.size(), 6);
200     assertTrue(features.contains(sf2));
201     assertTrue(features.contains(sf3));
202     assertTrue(features.contains(sf4));
203     assertTrue(features.contains(sf5));
204     assertTrue(features.contains(sf6));
205     assertTrue(features.contains(sf7));
206
207     /*
208      * at a non-contact position
209      */
210     features = fr.findFeaturesAtColumn(seq, 14);
211     assertEquals(features.size(), 3);
212     assertTrue(features.contains(sf2));
213     assertTrue(features.contains(sf3));
214     assertTrue(features.contains(sf4));
215
216     /*
217      * make "Type2" not displayed
218      */
219     Object[][] data = new Object[4][];
220     FeatureColourI colour = new FeatureColour(Color.RED);
221     data[0] = new Object[] { "Type1", colour, true };
222     data[1] = new Object[] { "Type2", colour, false };
223     data[2] = new Object[] { "Type3", colour, true };
224     data[3] = new Object[] { "Disulphide Bond", colour, true };
225     fr.setFeaturePriority(data);
226
227     features = fr.findFeaturesAtColumn(seq, 15);
228     assertEquals(features.size(), 5); // no sf2
229     assertTrue(features.contains(sf3));
230     assertTrue(features.contains(sf4));
231     assertTrue(features.contains(sf5));
232     assertTrue(features.contains(sf6));
233     assertTrue(features.contains(sf7));
234
235     /*
236      * make "Group2" not displayed
237      */
238     fr.setGroupVisibility("Group2", false);
239
240     features = fr.findFeaturesAtColumn(seq, 15);
241     assertEquals(features.size(), 3); // no sf2, sf3, sf6
242     assertTrue(features.contains(sf4));
243     assertTrue(features.contains(sf5));
244     assertTrue(features.contains(sf7));
245
246     // features 'at' a gap between b and c
247     // - returns enclosing feature BC but not contact feature B/C
248     features = fr.findFeaturesAtColumn(seq, 4);
249     assertEquals(features.size(), 1);
250     assertTrue(features.contains(sf8));
251     features = fr.findFeaturesAtColumn(seq, 5);
252     assertEquals(features.size(), 1);
253     assertTrue(features.contains(sf8));
254   }
255 }