Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
FeaturesFileTest | 64 | 402 | 19 |
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.io; | |
22 | ||
23 | import static org.testng.AssertJUnit.assertEquals; | |
24 | import static org.testng.AssertJUnit.assertFalse; | |
25 | import static org.testng.AssertJUnit.assertNotNull; | |
26 | import static org.testng.AssertJUnit.assertSame; | |
27 | import static org.testng.AssertJUnit.assertTrue; | |
28 | import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; | |
29 | ||
30 | import java.awt.Color; | |
31 | import java.io.File; | |
32 | import java.io.IOException; | |
33 | import java.util.HashMap; | |
34 | import java.util.Iterator; | |
35 | import java.util.List; | |
36 | import java.util.Map; | |
37 | ||
38 | import org.testng.annotations.AfterClass; | |
39 | import org.testng.annotations.BeforeClass; | |
40 | import org.testng.annotations.Test; | |
41 | ||
42 | import jalview.api.FeatureColourI; | |
43 | import jalview.api.FeatureRenderer; | |
44 | import jalview.datamodel.Alignment; | |
45 | import jalview.datamodel.AlignmentI; | |
46 | import jalview.datamodel.SequenceDummy; | |
47 | import jalview.datamodel.SequenceFeature; | |
48 | import jalview.datamodel.SequenceI; | |
49 | import jalview.datamodel.features.FeatureMatcher; | |
50 | import jalview.datamodel.features.FeatureMatcherI; | |
51 | import jalview.datamodel.features.FeatureMatcherSet; | |
52 | import jalview.datamodel.features.FeatureMatcherSetI; | |
53 | import jalview.datamodel.features.SequenceFeatures; | |
54 | import jalview.gui.AlignFrame; | |
55 | import jalview.gui.Desktop; | |
56 | import jalview.gui.JvOptionPane; | |
57 | import jalview.schemes.FeatureColour; | |
58 | import jalview.structure.StructureSelectionManager; | |
59 | import jalview.util.matcher.Condition; | |
60 | import jalview.viewmodel.seqfeatures.FeatureRendererModel; | |
61 | import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean; | |
62 | import junit.extensions.PA; | |
63 | ||
64 | public class FeaturesFileTest | |
65 | { | |
66 | private static String simpleGffFile = "examples/testdata/simpleGff3.gff"; | |
67 | ||
68 | 1 | @AfterClass(alwaysRun = true) |
69 | public void tearDownAfterClass() | |
70 | { | |
71 | /* | |
72 | * remove any sequence mappings created so they don't pollute other tests | |
73 | */ | |
74 | 1 | StructureSelectionManager ssm = StructureSelectionManager |
75 | .getStructureSelectionManager(Desktop.instance); | |
76 | 1 | ssm.resetAll(); |
77 | } | |
78 | ||
79 | 1 | @BeforeClass(alwaysRun = true) |
80 | public void setUpJvOptionPane() | |
81 | { | |
82 | 1 | JvOptionPane.setInteractiveMode(false); |
83 | 1 | JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); |
84 | } | |
85 | ||
86 | 1 | @Test(groups = { "Functional" }) |
87 | public void testParse() throws Exception | |
88 | { | |
89 | 1 | File f = new File("examples/uniref50.fa"); |
90 | 1 | AlignmentI al = readAlignmentFile(f); |
91 | 1 | AlignFrame af = new AlignFrame(al, 500, 500); |
92 | 1 | Map<String, FeatureColourI> colours = af.getFeatureRenderer() |
93 | .getFeatureColours(); | |
94 | 1 | FeaturesFile featuresFile = new FeaturesFile( |
95 | "examples/exampleFeatures.txt", DataSourceType.FILE); | |
96 | 1 | assertTrue( |
97 | "Test " + "Features file test" | |
98 | + "\nFailed to parse features file.", | |
99 | featuresFile.parse(al.getDataset(), colours, true)); | |
100 | ||
101 | /* | |
102 | * Refetch the colour map from the FeatureRenderer (to confirm it has been | |
103 | * updated - JAL-1904), and verify (some) feature group colours | |
104 | */ | |
105 | 1 | colours = af.getFeatureRenderer().getFeatureColours(); |
106 | 1 | assertEquals("27 feature group colours not found", 27, colours.size()); |
107 | 1 | assertEquals(colours.get("Cath").getColour(), new Color(0x93b1d1)); |
108 | 1 | assertEquals(colours.get("ASX-MOTIF").getColour(), new Color(0x6addbb)); |
109 | 1 | FeatureColourI kdColour = colours.get("kdHydrophobicity"); |
110 | 1 | assertTrue(kdColour.isGraduatedColour()); |
111 | 1 | assertTrue(kdColour.isAboveThreshold()); |
112 | 1 | assertEquals(-2f, kdColour.getThreshold()); |
113 | ||
114 | /* | |
115 | * verify (some) features on sequences | |
116 | */ | |
117 | 1 | List<SequenceFeature> sfs = al.getSequenceAt(0).getDatasetSequence() |
118 | .getSequenceFeatures(); // FER_CAPAA | |
119 | 1 | SequenceFeatures.sortFeatures(sfs, true); |
120 | 1 | assertEquals(8, sfs.size()); |
121 | ||
122 | /* | |
123 | * verify (in ascending start position order) | |
124 | */ | |
125 | 1 | SequenceFeature sf = sfs.get(0); |
126 | 1 | assertEquals("Pfam family%LINK%", sf.description); |
127 | 1 | assertEquals(0, sf.begin); |
128 | 1 | assertEquals(0, sf.end); |
129 | 1 | assertEquals("uniprot", sf.featureGroup); |
130 | 1 | assertEquals("Pfam", sf.type); |
131 | 1 | assertEquals(1, sf.links.size()); |
132 | 1 | assertEquals("Pfam family|http://pfam.xfam.org/family/PF00111", |
133 | sf.links.get(0)); | |
134 | ||
135 | 1 | sf = sfs.get(1); |
136 | 1 | assertEquals("Ferredoxin_fold Status: True Positive ", sf.description); |
137 | 1 | assertEquals(3, sf.begin); |
138 | 1 | assertEquals(93, sf.end); |
139 | 1 | assertEquals("uniprot", sf.featureGroup); |
140 | 1 | assertEquals("Cath", sf.type); |
141 | ||
142 | 1 | sf = sfs.get(2); |
143 | 1 | assertEquals("Fer2 Status: True Positive Pfam 8_8%LINK%", |
144 | sf.description); | |
145 | 1 | assertEquals("Pfam 8_8|http://pfam.xfam.org/family/PF00111", |
146 | sf.links.get(0)); | |
147 | 1 | assertEquals(8, sf.begin); |
148 | 1 | assertEquals(83, sf.end); |
149 | 1 | assertEquals("uniprot", sf.featureGroup); |
150 | 1 | assertEquals("Pfam", sf.type); |
151 | ||
152 | 1 | sf = sfs.get(3); |
153 | 1 | assertEquals("Iron-sulfur (2Fe-2S)", sf.description); |
154 | 1 | assertEquals(39, sf.begin); |
155 | 1 | assertEquals(39, sf.end); |
156 | 1 | assertEquals("uniprot", sf.featureGroup); |
157 | 1 | assertEquals("METAL", sf.type); |
158 | ||
159 | 1 | sf = sfs.get(4); |
160 | 1 | assertEquals("Iron-sulfur (2Fe-2S)", sf.description); |
161 | 1 | assertEquals(44, sf.begin); |
162 | 1 | assertEquals(44, sf.end); |
163 | 1 | assertEquals("uniprot", sf.featureGroup); |
164 | 1 | assertEquals("METAL", sf.type); |
165 | ||
166 | 1 | sf = sfs.get(5); |
167 | 1 | assertEquals("Iron-sulfur (2Fe-2S)", sf.description); |
168 | 1 | assertEquals(47, sf.begin); |
169 | 1 | assertEquals(47, sf.end); |
170 | 1 | assertEquals("uniprot", sf.featureGroup); |
171 | 1 | assertEquals("METAL", sf.type); |
172 | ||
173 | 1 | sf = sfs.get(6); |
174 | 1 | assertEquals("Iron-sulfur (2Fe-2S)", sf.description); |
175 | 1 | assertEquals(77, sf.begin); |
176 | 1 | assertEquals(77, sf.end); |
177 | 1 | assertEquals("uniprot", sf.featureGroup); |
178 | 1 | assertEquals("METAL", sf.type); |
179 | ||
180 | 1 | sf = sfs.get(7); |
181 | 1 | assertEquals( |
182 | "High confidence server. Only hits with scores over 0.8 are reported. PHOSPHORYLATION (T) 89_8%LINK%", | |
183 | sf.description); | |
184 | 1 | assertEquals( |
185 | "PHOSPHORYLATION (T) 89_8|http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=P83527&service=NetPhos-2.0", | |
186 | sf.links.get(0)); | |
187 | 1 | assertEquals(89, sf.begin); |
188 | 1 | assertEquals(89, sf.end); |
189 | 1 | assertEquals("netphos", sf.featureGroup); |
190 | 1 | assertEquals("PHOSPHORYLATION (T)", sf.type); |
191 | } | |
192 | ||
193 | /** | |
194 | * Test parsing a features file with a mix of Jalview and GFF formatted | |
195 | * content | |
196 | * | |
197 | * @throws Exception | |
198 | */ | |
199 | 1 | @Test(groups = { "Functional" }) |
200 | public void testParse_mixedJalviewGff() throws Exception | |
201 | { | |
202 | 1 | File f = new File("examples/uniref50.fa"); |
203 | 1 | AlignmentI al = readAlignmentFile(f); |
204 | 1 | AlignFrame af = new AlignFrame(al, 500, 500); |
205 | 1 | Map<String, FeatureColourI> colours = af.getFeatureRenderer() |
206 | .getFeatureColours(); | |
207 | // GFF2 uses space as name/value separator in column 9 | |
208 | 1 | String gffData = "METAL\tcc9900\n" + "GFF\n" |
209 | + "FER_CAPAA\tuniprot\tMETAL\t44\t45\t4.0\t.\t.\tNote Iron-sulfur; Note 2Fe-2S\n" | |
210 | + "FER1_SOLLC\tuniprot\tPfam\t55\t130\t2.0\t.\t."; | |
211 | 1 | FeaturesFile featuresFile = new FeaturesFile(gffData, |
212 | DataSourceType.PASTE); | |
213 | 1 | assertTrue("Failed to parse features file", |
214 | featuresFile.parse(al.getDataset(), colours, true)); | |
215 | ||
216 | // verify colours read or synthesized | |
217 | 1 | colours = af.getFeatureRenderer().getFeatureColours(); |
218 | 1 | assertEquals("1 feature group colours not found", 1, colours.size()); |
219 | 1 | assertEquals(colours.get("METAL").getColour(), new Color(0xcc9900)); |
220 | ||
221 | // verify feature on FER_CAPAA | |
222 | 1 | List<SequenceFeature> sfs = al.getSequenceAt(0).getDatasetSequence() |
223 | .getSequenceFeatures(); | |
224 | 1 | assertEquals(1, sfs.size()); |
225 | 1 | SequenceFeature sf = sfs.get(0); |
226 | 1 | assertEquals("Iron-sulfur,2Fe-2S", sf.description); |
227 | 1 | assertEquals(44, sf.begin); |
228 | 1 | assertEquals(45, sf.end); |
229 | 1 | assertEquals("uniprot", sf.featureGroup); |
230 | 1 | assertEquals("METAL", sf.type); |
231 | 1 | assertEquals(4f, sf.getScore(), 0.001f); |
232 | ||
233 | // verify feature on FER1_SOLLC | |
234 | 1 | sfs = al.getSequenceAt(2).getDatasetSequence().getSequenceFeatures(); |
235 | 1 | assertEquals(1, sfs.size()); |
236 | 1 | sf = sfs.get(0); |
237 | 1 | assertEquals("uniprot", sf.description); |
238 | 1 | assertEquals(55, sf.begin); |
239 | 1 | assertEquals(130, sf.end); |
240 | 1 | assertEquals("uniprot", sf.featureGroup); |
241 | 1 | assertEquals("Pfam", sf.type); |
242 | 1 | assertEquals(2f, sf.getScore(), 0.001f); |
243 | } | |
244 | ||
245 | 8 | public static AlignmentI readAlignmentFile(File f) throws IOException |
246 | { | |
247 | 8 | System.out.println("Reading file: " + f); |
248 | 8 | String ff = f.getPath(); |
249 | 8 | FormatAdapter rf = new FormatAdapter(); |
250 | ||
251 | 8 | AlignmentI al = rf.readFile(ff, DataSourceType.FILE, |
252 | new IdentifyFile().identify(ff, DataSourceType.FILE)); | |
253 | ||
254 | 8 | al.setDataset(null); // creates dataset sequences |
255 | 8 | assertNotNull("Couldn't read supplied alignment data.", al); |
256 | 8 | return al; |
257 | } | |
258 | ||
259 | /** | |
260 | * Test parsing a features file with GFF formatted content only | |
261 | * | |
262 | * @throws Exception | |
263 | */ | |
264 | 1 | @Test(groups = { "Functional" }) |
265 | public void testParse_pureGff3() throws Exception | |
266 | { | |
267 | 1 | File f = new File("examples/uniref50.fa"); |
268 | 1 | AlignmentI al = readAlignmentFile(f); |
269 | 1 | AlignFrame af = new AlignFrame(al, 500, 500); |
270 | 1 | Map<String, FeatureColourI> colours = af.getFeatureRenderer() |
271 | .getFeatureColours(); | |
272 | // GFF3 uses '=' separator for name/value pairs in column 9 | |
273 | // comma (%2C) equals (%3D) or semi-colon (%3B) should be url-escaped in | |
274 | // values | |
275 | 1 | String gffData = "##gff-version 3\n" |
276 | + "FER_CAPAA\tuniprot\tMETAL\t39\t39\t0.0\t.\t.\t" | |
277 | + "Note=Iron-sulfur (2Fe-2S);Note=another note,and another;evidence=ECO%3B0000255%2CPROSITE%3DProRule:PRU00465;" | |
278 | + "CSQ=AF=21,POLYPHEN=benign,possibly_damaging,clin_sig=Benign%3Dgood\n" | |
279 | + "FER1_SOLLC\tuniprot\tPfam\t55\t130\t3.0\t.\t.\tID=$23"; | |
280 | 1 | FeaturesFile featuresFile = new FeaturesFile(gffData, |
281 | DataSourceType.PASTE); | |
282 | 1 | assertTrue("Failed to parse features file", |
283 | featuresFile.parse(al.getDataset(), colours, true)); | |
284 | ||
285 | // verify feature on FER_CAPAA | |
286 | 1 | List<SequenceFeature> sfs = al.getSequenceAt(0).getDatasetSequence() |
287 | .getSequenceFeatures(); | |
288 | 1 | assertEquals(1, sfs.size()); |
289 | 1 | SequenceFeature sf = sfs.get(0); |
290 | // description parsed from Note attribute | |
291 | 1 | assertEquals("Iron-sulfur (2Fe-2S),another note,and another", |
292 | sf.description); | |
293 | 1 | assertEquals(39, sf.begin); |
294 | 1 | assertEquals(39, sf.end); |
295 | 1 | assertEquals("uniprot", sf.featureGroup); |
296 | 1 | assertEquals("METAL", sf.type); |
297 | 1 | assertEquals(5, sf.otherDetails.size()); |
298 | 1 | assertEquals("ECO;0000255,PROSITE=ProRule:PRU00465", // url decoded |
299 | sf.getValue("evidence")); | |
300 | 1 | assertEquals("Iron-sulfur (2Fe-2S),another note,and another", |
301 | sf.getValue("Note")); | |
302 | 1 | assertEquals("21", sf.getValueAsString("CSQ", "AF")); |
303 | 1 | assertEquals("benign,possibly_damaging", |
304 | sf.getValueAsString("CSQ", "POLYPHEN")); | |
305 | 1 | assertEquals("Benign=good", sf.getValueAsString("CSQ", "clin_sig")); // url |
306 | // decoded | |
307 | // todo change STRAND and !Phase into fields of SequenceFeature instead | |
308 | 1 | assertEquals(".", sf.otherDetails.get("STRAND")); |
309 | 1 | assertEquals(0, sf.getStrand()); |
310 | 1 | assertEquals(".", sf.getPhase()); |
311 | ||
312 | // verify feature on FER1_SOLLC1 | |
313 | 1 | sfs = al.getSequenceAt(2).getDatasetSequence().getSequenceFeatures(); |
314 | 1 | assertEquals(1, sfs.size()); |
315 | 1 | sf = sfs.get(0); |
316 | // ID used for description if available | |
317 | 1 | assertEquals("$23", sf.description); |
318 | 1 | assertEquals(55, sf.begin); |
319 | 1 | assertEquals(130, sf.end); |
320 | 1 | assertEquals("uniprot", sf.featureGroup); |
321 | 1 | assertEquals("Pfam", sf.type); |
322 | 1 | assertEquals(3f, sf.getScore(), 0.001f); |
323 | } | |
324 | ||
325 | /** | |
326 | * Test parsing a features file with Jalview format features (but no colour | |
327 | * descriptors or startgroup to give the hint not to parse as GFF) | |
328 | * | |
329 | * @throws Exception | |
330 | */ | |
331 | 1 | @Test(groups = { "Functional" }) |
332 | public void testParse_jalviewFeaturesOnly() throws Exception | |
333 | { | |
334 | 1 | File f = new File("examples/uniref50.fa"); |
335 | 1 | AlignmentI al = readAlignmentFile(f); |
336 | 1 | AlignFrame af = new AlignFrame(al, 500, 500); |
337 | 1 | Map<String, FeatureColourI> colours = af.getFeatureRenderer() |
338 | .getFeatureColours(); | |
339 | ||
340 | /* | |
341 | * one feature on FER_CAPAA and one on sequence 3 (index 2) FER1_SOLLC | |
342 | */ | |
343 | 1 | String featureData = "Iron-sulfur (2Fe-2S)\tFER_CAPAA\t-1\t39\t39\tMETAL\n" |
344 | + "Iron-phosphorus (2Fe-P)\tID_NOT_SPECIFIED\t2\t86\t87\tMETALLIC\n"; | |
345 | 1 | FeaturesFile featuresFile = new FeaturesFile(featureData, |
346 | DataSourceType.PASTE); | |
347 | 1 | assertTrue("Failed to parse features file", |
348 | featuresFile.parse(al.getDataset(), colours, true)); | |
349 | ||
350 | // verify FER_CAPAA feature | |
351 | 1 | List<SequenceFeature> sfs = al.getSequenceAt(0).getDatasetSequence() |
352 | .getSequenceFeatures(); | |
353 | 1 | assertEquals(1, sfs.size()); |
354 | 1 | SequenceFeature sf = sfs.get(0); |
355 | 1 | assertEquals("Iron-sulfur (2Fe-2S)", sf.description); |
356 | 1 | assertEquals(39, sf.begin); |
357 | 1 | assertEquals(39, sf.end); |
358 | 1 | assertEquals("METAL", sf.type); |
359 | ||
360 | // verify FER1_SOLLC feature | |
361 | 1 | sfs = al.getSequenceAt(2).getDatasetSequence().getSequenceFeatures(); |
362 | 1 | assertEquals(1, sfs.size()); |
363 | 1 | sf = sfs.get(0); |
364 | 1 | assertEquals("Iron-phosphorus (2Fe-P)", sf.description); |
365 | 1 | assertEquals(86, sf.begin); |
366 | 1 | assertEquals(87, sf.end); |
367 | 1 | assertEquals("METALLIC", sf.type); |
368 | } | |
369 | ||
370 | 4 | private void checkDatasetfromSimpleGff3(AlignmentI dataset) |
371 | { | |
372 | 4 | assertEquals("no sequences extracted from GFF3 file", 2, |
373 | dataset.getHeight()); | |
374 | ||
375 | 4 | SequenceI seq1 = dataset.findName("seq1"); |
376 | 4 | SequenceI seq2 = dataset.findName("seq2"); |
377 | 4 | assertNotNull(seq1); |
378 | 4 | assertNotNull(seq2); |
379 | 4 | assertFalse("Failed to replace dummy seq1 with real sequence", |
380 | seq1 instanceof SequenceDummy | |
381 | && ((SequenceDummy) seq1).isDummy()); | |
382 | 4 | assertFalse("Failed to replace dummy seq2 with real sequence", |
383 | seq2 instanceof SequenceDummy | |
384 | && ((SequenceDummy) seq2).isDummy()); | |
385 | 4 | String placeholderseq = new SequenceDummy("foo").getSequenceAsString(); |
386 | 4 | assertFalse("dummy replacement buggy for seq1", |
387 | placeholderseq.equals(seq1.getSequenceAsString())); | |
388 | 4 | assertFalse("dummy replacement buggy for seq2", |
389 | placeholderseq.equals(seq2.getSequenceAsString())); | |
390 | 4 | assertNotNull("No features added to seq1", seq1.getSequenceFeatures()); |
391 | 4 | assertEquals("Wrong number of features", 3, |
392 | seq1.getSequenceFeatures().size()); | |
393 | 4 | assertTrue(seq2.getSequenceFeatures().isEmpty()); |
394 | 4 | assertEquals("Wrong number of features", 0, |
395 | 4 | seq2.getSequenceFeatures() == null ? 0 |
396 | : seq2.getSequenceFeatures().size()); | |
397 | 4 | assertTrue("Expected at least one CDNA/Protein mapping for seq1", |
398 | dataset.getCodonFrame(seq1) != null | |
399 | && dataset.getCodonFrame(seq1).size() > 0); | |
400 | ||
401 | } | |
402 | ||
403 | 1 | @Test(groups = { "Functional" }) |
404 | public void readGff3File() throws IOException | |
405 | { | |
406 | 1 | FeaturesFile gffreader = new FeaturesFile(true, simpleGffFile, |
407 | DataSourceType.FILE); | |
408 | 1 | Alignment dataset = new Alignment(gffreader.getSeqsAsArray()); |
409 | 1 | gffreader.addProperties(dataset); |
410 | 1 | checkDatasetfromSimpleGff3(dataset); |
411 | } | |
412 | ||
413 | 1 | @Test(groups = { "Functional" }) |
414 | public void simpleGff3FileClass() throws IOException | |
415 | { | |
416 | 1 | AlignmentI dataset = new Alignment(new SequenceI[] {}); |
417 | 1 | FeaturesFile ffile = new FeaturesFile(simpleGffFile, |
418 | DataSourceType.FILE); | |
419 | ||
420 | 1 | boolean parseResult = ffile.parse(dataset, null, false, false); |
421 | 1 | assertTrue("return result should be true", parseResult); |
422 | 1 | checkDatasetfromSimpleGff3(dataset); |
423 | } | |
424 | ||
425 | 1 | @Test(groups = { "Functional" }) |
426 | public void simpleGff3FileLoader() throws IOException | |
427 | { | |
428 | 1 | AlignFrame af = new FileLoader(false) |
429 | .LoadFileWaitTillLoaded(simpleGffFile, DataSourceType.FILE); | |
430 | 1 | assertTrue( |
431 | "Didn't read the alignment into an alignframe from Gff3 File", | |
432 | af != null); | |
433 | 1 | checkDatasetfromSimpleGff3(af.getViewport().getAlignment()); |
434 | } | |
435 | ||
436 | 1 | @Test(groups = { "Functional" }) |
437 | public void simpleGff3RelaxedIdMatching() throws IOException | |
438 | { | |
439 | 1 | AlignmentI dataset = new Alignment(new SequenceI[] {}); |
440 | 1 | FeaturesFile ffile = new FeaturesFile(simpleGffFile, |
441 | DataSourceType.FILE); | |
442 | ||
443 | 1 | boolean parseResult = ffile.parse(dataset, null, false, true); |
444 | 1 | assertTrue("return result (relaxedID matching) should be true", |
445 | parseResult); | |
446 | 1 | checkDatasetfromSimpleGff3(dataset); |
447 | } | |
448 | ||
449 | 1 | @Test(groups = { "Functional" }) |
450 | public void testPrintJalviewFormat() throws Exception | |
451 | { | |
452 | 1 | File f = new File("examples/uniref50.fa"); |
453 | 1 | AlignmentI al = readAlignmentFile(f); |
454 | 1 | AlignFrame af = new AlignFrame(al, 500, 500); |
455 | 1 | Map<String, FeatureColourI> colours = af.getFeatureRenderer() |
456 | .getFeatureColours(); | |
457 | 1 | String features = "METAL\tcc9900\n" |
458 | + "GAMMA-TURN\tred|0,255,255|20.0|95.0|below|66.0\n" | |
459 | + "Pfam\tred\n" + "STARTGROUP\tuniprot\n" | |
460 | + "Cath\tFER_CAPAA\t-1\t0\t0\tDomain\n" // non-positional feature | |
461 | + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\n" | |
462 | + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\n" | |
463 | + "<html>Pfam domain<a href=\"http://pfam.xfam.org/family/PF00111\">Pfam_3_4</a></html>\tFER_CAPAA\t-1\t20\t20\tPfam\n" | |
464 | + "ENDGROUP\tuniprot\n"; | |
465 | 1 | FeaturesFile featuresFile = new FeaturesFile(features, |
466 | DataSourceType.PASTE); | |
467 | 1 | featuresFile.parse(al.getDataset(), colours, false); |
468 | ||
469 | /* | |
470 | * add positional and non-positional features with null and | |
471 | * empty feature group to check handled correctly | |
472 | */ | |
473 | 1 | SequenceI seq = al.getSequenceAt(1); // FER_CAPAN |
474 | 1 | seq.addSequenceFeature( |
475 | new SequenceFeature("Pfam", "desc1", 0, 0, 1.3f, null)); | |
476 | 1 | seq.addSequenceFeature( |
477 | new SequenceFeature("Pfam", "desc2", 4, 9, Float.NaN, null)); | |
478 | 1 | seq = al.getSequenceAt(2); // FER1_SOLLC |
479 | 1 | seq.addSequenceFeature( |
480 | new SequenceFeature("Pfam", "desc3", 0, 0, Float.NaN, "")); | |
481 | 1 | seq.addSequenceFeature( |
482 | new SequenceFeature("Pfam", "desc4", 5, 8, -2.6f, "")); | |
483 | ||
484 | /* | |
485 | * first with no features displayed, exclude non-positional features | |
486 | */ | |
487 | 1 | FeatureRenderer fr = af.alignPanel.getFeatureRenderer(); |
488 | 1 | String exported = featuresFile |
489 | .printJalviewFormat(al.getSequencesArray(), fr, false, false); | |
490 | 1 | String expected = "No Features Visible"; |
491 | 1 | assertEquals(expected, exported); |
492 | ||
493 | /* | |
494 | * include non-positional features, but still no positional features | |
495 | */ | |
496 | 1 | fr.setGroupVisibility("uniprot", true); |
497 | 1 | exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr, |
498 | true, false); | |
499 | 1 | expected = "\nSTARTGROUP\tuniprot\n" |
500 | + "Cath\tFER_CAPAA\t-1\t0\t0\tDomain\t0.0\n" | |
501 | + "ENDGROUP\tuniprot\n\n" | |
502 | + "desc1\tFER_CAPAN\t-1\t0\t0\tPfam\t1.3\n\n" | |
503 | + "desc3\tFER1_SOLLC\t-1\t0\t0\tPfam\n"; // NaN is not output | |
504 | 1 | assertEquals(expected, exported); |
505 | ||
506 | /* | |
507 | * set METAL (in uniprot group) and GAMMA-TURN visible, but not Pfam | |
508 | */ | |
509 | 1 | fr.setVisible("METAL"); |
510 | 1 | fr.setVisible("GAMMA-TURN"); |
511 | 1 | exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr, |
512 | false, false); | |
513 | 1 | expected = "METAL\tcc9900\n" |
514 | + "GAMMA-TURN\tscore|ff0000|00ffff|noValueMin|20.0|95.0|below|66.0\n" | |
515 | + "\nSTARTGROUP\tuniprot\n" | |
516 | + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n" | |
517 | + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n" | |
518 | + "ENDGROUP\tuniprot\n"; | |
519 | 1 | assertEquals(expected, exported); |
520 | ||
521 | /* | |
522 | * now set Pfam visible | |
523 | */ | |
524 | 1 | fr.setVisible("Pfam"); |
525 | 1 | exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr, |
526 | false, false); | |
527 | /* | |
528 | * features are output within group, ordered by sequence and type | |
529 | */ | |
530 | 1 | expected = "METAL\tcc9900\n" + "Pfam\tff0000\n" |
531 | + "GAMMA-TURN\tscore|ff0000|00ffff|noValueMin|20.0|95.0|below|66.0\n" | |
532 | + "\nSTARTGROUP\tuniprot\n" | |
533 | + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n" | |
534 | + "<html>Pfam domain<a href=\"http://pfam.xfam.org/family/PF00111\">Pfam_3_4</a></html>\tFER_CAPAA\t-1\t20\t20\tPfam\t0.0\n" | |
535 | + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n" | |
536 | + "ENDGROUP\tuniprot\n" | |
537 | // null / empty group features are output after named groups | |
538 | + "\ndesc2\tFER_CAPAN\t-1\t4\t9\tPfam\n" | |
539 | + "\ndesc4\tFER1_SOLLC\t-1\t5\t8\tPfam\t-2.6\n"; | |
540 | 1 | assertEquals(expected, exported); |
541 | ||
542 | /* | |
543 | * hide uniprot group | |
544 | */ | |
545 | 1 | fr.setGroupVisibility("uniprot", false); |
546 | 1 | expected = "METAL\tcc9900\n" + "Pfam\tff0000\n" |
547 | + "GAMMA-TURN\tscore|ff0000|00ffff|noValueMin|20.0|95.0|below|66.0\n" | |
548 | + "\ndesc2\tFER_CAPAN\t-1\t4\t9\tPfam\n" | |
549 | + "\ndesc4\tFER1_SOLLC\t-1\t5\t8\tPfam\t-2.6\n"; | |
550 | 1 | exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr, |
551 | false, false); | |
552 | 1 | assertEquals(expected, exported); |
553 | ||
554 | /* | |
555 | * include non-positional (overrides group not shown) | |
556 | */ | |
557 | 1 | exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr, |
558 | true, false); | |
559 | 1 | expected = "METAL\tcc9900\n" + "Pfam\tff0000\n" |
560 | + "GAMMA-TURN\tscore|ff0000|00ffff|noValueMin|20.0|95.0|below|66.0\n" | |
561 | + "\nSTARTGROUP\tuniprot\n" | |
562 | + "Cath\tFER_CAPAA\t-1\t0\t0\tDomain\t0.0\n" | |
563 | + "ENDGROUP\tuniprot\n" | |
564 | + "\ndesc1\tFER_CAPAN\t-1\t0\t0\tPfam\t1.3\n" | |
565 | + "desc2\tFER_CAPAN\t-1\t4\t9\tPfam\n" | |
566 | + "\ndesc3\tFER1_SOLLC\t-1\t0\t0\tPfam\n" | |
567 | + "desc4\tFER1_SOLLC\t-1\t5\t8\tPfam\t-2.6\n"; | |
568 | 1 | assertEquals(expected, exported); |
569 | } | |
570 | ||
571 | 1 | @Test(groups = { "Functional" }) |
572 | public void testPrintGffFormat() throws Exception | |
573 | { | |
574 | 1 | File f = new File("examples/uniref50.fa"); |
575 | 1 | AlignmentI al = readAlignmentFile(f); |
576 | 1 | AlignFrame af = new AlignFrame(al, 500, 500); |
577 | ||
578 | /* | |
579 | * no features | |
580 | */ | |
581 | 1 | FeaturesFile featuresFile = new FeaturesFile(); |
582 | 1 | FeatureRendererModel fr = (FeatureRendererModel) af.alignPanel |
583 | .getFeatureRenderer(); | |
584 | 1 | String exported = featuresFile.printGffFormat(al.getSequencesArray(), |
585 | fr, false, false); | |
586 | 1 | String gffHeader = "##gff-version 2\n"; |
587 | 1 | assertEquals(gffHeader, exported); |
588 | 1 | exported = featuresFile.printGffFormat(al.getSequencesArray(), fr, true, |
589 | false); | |
590 | 1 | assertEquals(gffHeader, exported); |
591 | ||
592 | /* | |
593 | * add some features | |
594 | */ | |
595 | 1 | al.getSequenceAt(0).addSequenceFeature( |
596 | new SequenceFeature("Domain", "Cath", 0, 0, 0f, "Uniprot")); | |
597 | 1 | al.getSequenceAt(0).addSequenceFeature( |
598 | new SequenceFeature("METAL", "Cath", 39, 39, 1.2f, null)); | |
599 | 1 | al.getSequenceAt(1).addSequenceFeature(new SequenceFeature("GAMMA-TURN", |
600 | "Turn", 36, 38, 2.1f, "s3dm")); | |
601 | 1 | SequenceFeature sf = new SequenceFeature("Pfam", "", 20, 20, 0f, |
602 | "Uniprot"); | |
603 | 1 | sf.setStrand("+"); |
604 | 1 | sf.setPhase("2"); |
605 | 1 | sf.setValue("x", "y"); |
606 | 1 | sf.setValue("black", "white"); |
607 | 1 | Map<String, String> csq = new HashMap<>(); |
608 | 1 | csq.put("SIFT", "benign,mostly benign,cloudy, with meatballs"); |
609 | 1 | csq.put("consequence", "missense_variant"); |
610 | 1 | sf.setValue("CSQ", csq); |
611 | 1 | al.getSequenceAt(1).addSequenceFeature(sf); |
612 | ||
613 | /* | |
614 | * 'discover' features then hide all feature types | |
615 | */ | |
616 | 1 | fr.findAllFeatures(true); |
617 | 1 | FeatureSettingsBean[] data = new FeatureSettingsBean[4]; |
618 | 1 | FeatureColourI fc = new FeatureColour(Color.PINK); |
619 | 1 | data[0] = new FeatureSettingsBean("Domain", fc, null, false); |
620 | 1 | data[1] = new FeatureSettingsBean("METAL", fc, null, false); |
621 | 1 | data[2] = new FeatureSettingsBean("GAMMA-TURN", fc, null, false); |
622 | 1 | data[3] = new FeatureSettingsBean("Pfam", fc, null, false); |
623 | 1 | fr.setFeaturePriority(data); |
624 | ||
625 | /* | |
626 | * with no features displayed, exclude non-positional features | |
627 | */ | |
628 | 1 | exported = featuresFile.printGffFormat(al.getSequencesArray(), fr, |
629 | false, false); | |
630 | 1 | assertEquals(gffHeader, exported); |
631 | ||
632 | /* | |
633 | * include non-positional features | |
634 | */ | |
635 | 1 | fr.setGroupVisibility("Uniprot", true); |
636 | 1 | fr.setGroupVisibility("s3dm", false); |
637 | 1 | exported = featuresFile.printGffFormat(al.getSequencesArray(), fr, true, |
638 | false); | |
639 | 1 | String expected = gffHeader |
640 | + "FER_CAPAA\tUniprot\tDomain\t0\t0\t0.0\t.\t.\n"; | |
641 | 1 | assertEquals(expected, exported); |
642 | ||
643 | /* | |
644 | * set METAL (in uniprot group) and GAMMA-TURN visible, but not Pfam | |
645 | * only Uniprot group visible here... | |
646 | */ | |
647 | 1 | fr.setVisible("METAL"); |
648 | 1 | fr.setVisible("GAMMA-TURN"); |
649 | 1 | exported = featuresFile.printGffFormat(al.getSequencesArray(), fr, |
650 | false, false); | |
651 | // METAL feature has null group: description used for column 2 | |
652 | 1 | expected = gffHeader + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n"; |
653 | 1 | assertEquals(expected, exported); |
654 | ||
655 | /* | |
656 | * set s3dm group visible | |
657 | */ | |
658 | 1 | fr.setGroupVisibility("s3dm", true); |
659 | 1 | exported = featuresFile.printGffFormat(al.getSequencesArray(), fr, |
660 | false, false); | |
661 | // METAL feature has null group: description used for column 2 | |
662 | 1 | expected = gffHeader + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n" |
663 | + "FER_CAPAN\ts3dm\tGAMMA-TURN\t36\t38\t2.1\t.\t.\n"; | |
664 | 1 | assertEquals(expected, exported); |
665 | ||
666 | /* | |
667 | * now set Pfam visible | |
668 | */ | |
669 | 1 | fr.setVisible("Pfam"); |
670 | 1 | exported = featuresFile.printGffFormat(al.getSequencesArray(), fr, |
671 | false, false); | |
672 | // Pfam feature columns include strand(+), phase(2), attributes | |
673 | 1 | expected = gffHeader + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n" |
674 | // CSQ output as CSQ=att1=value1,att2=value2 | |
675 | // note all commas are encoded here which is wrong - it should be | |
676 | // SIFT=benign,mostly benign,cloudy%2C with meatballs | |
677 | + "FER_CAPAN\tUniprot\tPfam\t20\t20\t0.0\t+\t2\tx=y;black=white;" | |
678 | + "CSQ=SIFT=benign%2Cmostly benign%2Ccloudy%2C with meatballs,consequence=missense_variant\n" | |
679 | + "FER_CAPAN\ts3dm\tGAMMA-TURN\t36\t38\t2.1\t.\t.\n"; | |
680 | 1 | assertEquals(expected, exported); |
681 | } | |
682 | ||
683 | /** | |
684 | * Test for parsing of feature filters as represented in a Jalview features | |
685 | * file | |
686 | * | |
687 | * @throws Exception | |
688 | */ | |
689 | 1 | @Test(groups = { "Functional" }) |
690 | public void testParseFilters() throws Exception | |
691 | { | |
692 | 1 | Map<String, FeatureMatcherSetI> filters = new HashMap<>(); |
693 | 1 | String text = "sequence_variant\tCSQ:PolyPhen NotContains 'damaging'\n" |
694 | + "missense_variant\t(label contains foobar) and (Score lt 1.3)"; | |
695 | 1 | FeaturesFile featuresFile = new FeaturesFile(text, |
696 | DataSourceType.PASTE); | |
697 | 1 | featuresFile.parseFilters(filters); |
698 | 1 | assertEquals(filters.size(), 2); |
699 | ||
700 | 1 | FeatureMatcherSetI fm = filters.get("sequence_variant"); |
701 | 1 | assertNotNull(fm); |
702 | 1 | Iterator<FeatureMatcherI> matchers = fm.getMatchers().iterator(); |
703 | 1 | FeatureMatcherI matcher = matchers.next(); |
704 | 1 | assertFalse(matchers.hasNext()); |
705 | 1 | String[] attributes = matcher.getAttribute(); |
706 | 1 | assertArrayEquals(attributes, new String[] { "CSQ", "PolyPhen" }); |
707 | 1 | assertSame(matcher.getMatcher().getCondition(), Condition.NotContains); |
708 | 1 | assertEquals(matcher.getMatcher().getPattern(), "damaging"); |
709 | ||
710 | 1 | fm = filters.get("missense_variant"); |
711 | 1 | assertNotNull(fm); |
712 | 1 | matchers = fm.getMatchers().iterator(); |
713 | 1 | matcher = matchers.next(); |
714 | 1 | assertTrue(matcher.isByLabel()); |
715 | 1 | assertSame(matcher.getMatcher().getCondition(), Condition.Contains); |
716 | 1 | assertEquals(matcher.getMatcher().getPattern(), "foobar"); |
717 | 1 | matcher = matchers.next(); |
718 | 1 | assertTrue(matcher.isByScore()); |
719 | 1 | assertSame(matcher.getMatcher().getCondition(), Condition.LT); |
720 | 1 | assertEquals(matcher.getMatcher().getPattern(), "1.3"); |
721 | 1 | assertEquals(PA.getValue(matcher.getMatcher(), "floatValue"), 1.3f); |
722 | ||
723 | 1 | assertFalse(matchers.hasNext()); |
724 | } | |
725 | ||
726 | 1 | @Test(groups = { "Functional" }) |
727 | public void testOutputFeatureFilters() | |
728 | { | |
729 | 1 | FeaturesFile ff = new FeaturesFile(); |
730 | 1 | StringBuilder sb = new StringBuilder(); |
731 | 1 | Map<String, FeatureColourI> visible = new HashMap<>(); |
732 | 1 | visible.put("pfam", new FeatureColour(Color.red)); |
733 | 1 | Map<String, FeatureMatcherSetI> featureFilters = new HashMap<>(); |
734 | ||
735 | // with no filters, nothing is output | |
736 | 1 | ff.outputFeatureFilters(sb, visible, featureFilters); |
737 | 1 | assertEquals("", sb.toString()); |
738 | ||
739 | // with filter for not visible features only, nothing is output | |
740 | 1 | FeatureMatcherSet filter = new FeatureMatcherSet(); |
741 | 1 | filter.and(FeatureMatcher.byLabel(Condition.Present, null)); |
742 | 1 | featureFilters.put("foobar", filter); |
743 | 1 | ff.outputFeatureFilters(sb, visible, featureFilters); |
744 | 1 | assertEquals("", sb.toString()); |
745 | ||
746 | // with filters for visible feature types | |
747 | 1 | FeatureMatcherSet filter2 = new FeatureMatcherSet(); |
748 | 1 | filter2.and(FeatureMatcher.byAttribute(Condition.Present, null, "CSQ", |
749 | "PolyPhen")); | |
750 | 1 | filter2.and(FeatureMatcher.byScore(Condition.LE, "-2.4")); |
751 | 1 | featureFilters.put("pfam", filter2); |
752 | 1 | visible.put("foobar", new FeatureColour(Color.blue)); |
753 | 1 | ff.outputFeatureFilters(sb, visible, featureFilters); |
754 | 1 | String expected = "\nSTARTFILTERS\nfoobar\tLabel Present\npfam\t(CSQ:PolyPhen Present) AND (Score LE -2.4)\nENDFILTERS\n"; |
755 | 1 | assertEquals(expected, sb.toString()); |
756 | } | |
757 | ||
758 | /** | |
759 | * Output as GFF should not include features which are not visible due to | |
760 | * colour threshold or feature filter settings | |
761 | * | |
762 | * @throws Exception | |
763 | */ | |
764 | 1 | @Test(groups = { "Functional" }) |
765 | public void testPrintGffFormat_withFilters() throws Exception | |
766 | { | |
767 | 1 | File f = new File("examples/uniref50.fa"); |
768 | 1 | AlignmentI al = readAlignmentFile(f); |
769 | 1 | AlignFrame af = new AlignFrame(al, 500, 500); |
770 | 1 | SequenceFeature sf1 = new SequenceFeature("METAL", "Cath", 39, 39, 1.2f, |
771 | null); | |
772 | 1 | sf1.setValue("clin_sig", "Likely Pathogenic"); |
773 | 1 | sf1.setValue("AF", "24"); |
774 | 1 | al.getSequenceAt(0).addSequenceFeature(sf1); |
775 | 1 | SequenceFeature sf2 = new SequenceFeature("METAL", "Cath", 41, 41, 0.6f, |
776 | null); | |
777 | 1 | sf2.setValue("clin_sig", "Benign"); |
778 | 1 | sf2.setValue("AF", "46"); |
779 | 1 | al.getSequenceAt(0).addSequenceFeature(sf2); |
780 | ||
781 | 1 | FeaturesFile featuresFile = new FeaturesFile(); |
782 | 1 | FeatureRenderer fr = af.alignPanel.getFeatureRenderer(); |
783 | 1 | final String gffHeader = "##gff-version 2\n"; |
784 | ||
785 | 1 | fr.setVisible("METAL"); |
786 | 1 | fr.setColour("METAL", new FeatureColour(Color.PINK)); |
787 | 1 | String exported = featuresFile.printGffFormat(al.getSequencesArray(), |
788 | fr, false, false); | |
789 | 1 | String expected = gffHeader |
790 | + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\tclin_sig=Likely Pathogenic;AF=24\n" | |
791 | + "FER_CAPAA\tCath\tMETAL\t41\t41\t0.6\t.\t.\tclin_sig=Benign;AF=46\n"; | |
792 | 1 | assertEquals(expected, exported); |
793 | ||
794 | /* | |
795 | * now threshold to Score > 1.1 - should exclude sf2 | |
796 | */ | |
797 | 1 | FeatureColourI fc = new FeatureColour(null, Color.white, Color.BLACK, |
798 | Color.white, 0f, 2f); | |
799 | 1 | fc.setAboveThreshold(true); |
800 | 1 | fc.setThreshold(1.1f); |
801 | 1 | fr.setColour("METAL", fc); |
802 | 1 | exported = featuresFile.printGffFormat(al.getSequencesArray(), fr, |
803 | false, false); | |
804 | 1 | expected = gffHeader |
805 | + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\tclin_sig=Likely Pathogenic;AF=24\n"; | |
806 | 1 | assertEquals(expected, exported); |
807 | ||
808 | /* | |
809 | * remove threshold and check sf2 is exported | |
810 | */ | |
811 | 1 | fc.setAboveThreshold(false); |
812 | 1 | exported = featuresFile.printGffFormat(al.getSequencesArray(), fr, |
813 | false, false); | |
814 | 1 | expected = gffHeader |
815 | + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\tclin_sig=Likely Pathogenic;AF=24\n" | |
816 | + "FER_CAPAA\tCath\tMETAL\t41\t41\t0.6\t.\t.\tclin_sig=Benign;AF=46\n"; | |
817 | 1 | assertEquals(expected, exported); |
818 | ||
819 | /* | |
820 | * filter on (clin_sig contains Benign) - should include sf2 and exclude sf1 | |
821 | */ | |
822 | 1 | FeatureMatcherSetI filter = new FeatureMatcherSet(); |
823 | 1 | filter.and(FeatureMatcher.byAttribute(Condition.Contains, "benign", |
824 | "clin_sig")); | |
825 | 1 | fr.setFeatureFilter("METAL", filter); |
826 | 1 | exported = featuresFile.printGffFormat(al.getSequencesArray(), fr, |
827 | false, false); | |
828 | 1 | expected = gffHeader |
829 | + "FER_CAPAA\tCath\tMETAL\t41\t41\t0.6\t.\t.\tclin_sig=Benign;AF=46\n"; | |
830 | 1 | assertEquals(expected, exported); |
831 | } | |
832 | ||
833 | /** | |
834 | * Output as Jalview should not include features which are not visible due to | |
835 | * colour threshold or feature filter settings | |
836 | * | |
837 | * @throws Exception | |
838 | */ | |
839 | 1 | @Test(groups = { "Functional" }) |
840 | public void testPrintJalviewFormat_withFilters() throws Exception | |
841 | { | |
842 | 1 | File f = new File("examples/uniref50.fa"); |
843 | 1 | AlignmentI al = readAlignmentFile(f); |
844 | 1 | AlignFrame af = new AlignFrame(al, 500, 500); |
845 | 1 | SequenceFeature sf1 = new SequenceFeature("METAL", "Cath", 39, 39, 1.2f, |
846 | "grp1"); | |
847 | 1 | sf1.setValue("clin_sig", "Likely Pathogenic"); |
848 | 1 | sf1.setValue("AF", "24"); |
849 | 1 | al.getSequenceAt(0).addSequenceFeature(sf1); |
850 | 1 | SequenceFeature sf2 = new SequenceFeature("METAL", "Cath", 41, 41, 0.6f, |
851 | "grp2"); | |
852 | 1 | sf2.setValue("clin_sig", "Benign"); |
853 | 1 | sf2.setValue("AF", "46"); |
854 | 1 | al.getSequenceAt(0).addSequenceFeature(sf2); |
855 | ||
856 | 1 | FeaturesFile featuresFile = new FeaturesFile(); |
857 | 1 | FeatureRenderer fr = af.alignPanel.getFeatureRenderer(); |
858 | 1 | fr.findAllFeatures(true); |
859 | ||
860 | 1 | fr.setVisible("METAL"); |
861 | 1 | fr.setColour("METAL", new FeatureColour(Color.PINK)); |
862 | 1 | String exported = featuresFile |
863 | .printJalviewFormat(al.getSequencesArray(), fr, false, false); | |
864 | 1 | String expected = "METAL\tffafaf\n\nSTARTGROUP\tgrp1\n" |
865 | + "Cath\tFER_CAPAA\t-1\t39\t39\tMETAL\t1.2\n" | |
866 | + "ENDGROUP\tgrp1\n\nSTARTGROUP\tgrp2\n" | |
867 | + "Cath\tFER_CAPAA\t-1\t41\t41\tMETAL\t0.6\n" | |
868 | + "ENDGROUP\tgrp2\n"; | |
869 | 1 | assertEquals(expected, exported); |
870 | ||
871 | /* | |
872 | * now threshold to Score > 1.1 - should exclude sf2 | |
873 | * (and there should be no empty STARTGROUP/ENDGROUP output) | |
874 | */ | |
875 | 1 | FeatureColourI fc = new FeatureColour(null, Color.white, Color.BLACK, |
876 | Color.white, 0f, 2f); | |
877 | 1 | fc.setAboveThreshold(true); |
878 | 1 | fc.setThreshold(1.1f); |
879 | 1 | fr.setColour("METAL", fc); |
880 | 1 | exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr, |
881 | false, false); | |
882 | 1 | expected = "METAL\tscore|ffffff|000000|noValueMin|abso|0.0|2.0|above|1.1\n\n" |
883 | + "STARTGROUP\tgrp1\n" | |
884 | + "Cath\tFER_CAPAA\t-1\t39\t39\tMETAL\t1.2\n" | |
885 | + "ENDGROUP\tgrp1\n"; | |
886 | 1 | assertEquals(expected, exported); |
887 | ||
888 | /* | |
889 | * remove threshold and check sf2 is exported | |
890 | */ | |
891 | 1 | fc.setAboveThreshold(false); |
892 | 1 | exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr, |
893 | false, false); | |
894 | 1 | expected = "METAL\tscore|ffffff|000000|noValueMin|abso|0.0|2.0|none\n\n" |
895 | + "STARTGROUP\tgrp1\n" | |
896 | + "Cath\tFER_CAPAA\t-1\t39\t39\tMETAL\t1.2\n" | |
897 | + "ENDGROUP\tgrp1\n\nSTARTGROUP\tgrp2\n" | |
898 | + "Cath\tFER_CAPAA\t-1\t41\t41\tMETAL\t0.6\n" | |
899 | + "ENDGROUP\tgrp2\n"; | |
900 | 1 | assertEquals(expected, exported); |
901 | ||
902 | /* | |
903 | * filter on (clin_sig contains Benign) - should include sf2 and exclude sf1 | |
904 | */ | |
905 | 1 | FeatureMatcherSetI filter = new FeatureMatcherSet(); |
906 | 1 | filter.and(FeatureMatcher.byAttribute(Condition.Contains, "benign", |
907 | "clin_sig")); | |
908 | 1 | fr.setFeatureFilter("METAL", filter); |
909 | 1 | exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr, |
910 | false, false); | |
911 | 1 | expected = "FER_CAPAA\tCath\tMETAL\t41\t41\t0.6\t.\t.\n"; |
912 | 1 | expected = "METAL\tscore|ffffff|000000|noValueMin|abso|0.0|2.0|none\n\n" |
913 | + "STARTFILTERS\nMETAL\tclin_sig Contains benign\nENDFILTERS\n\n" | |
914 | + "STARTGROUP\tgrp2\n" | |
915 | + "Cath\tFER_CAPAA\t-1\t41\t41\tMETAL\t0.6\n" | |
916 | + "ENDGROUP\tgrp2\n"; | |
917 | 1 | assertEquals(expected, exported); |
918 | } | |
919 | } |