2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
21 package jalview.renderer.seqfeatures;
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;
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;
37 import org.testng.annotations.AfterMethod;
38 import org.testng.annotations.Test;
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;
59 public class FeatureRendererTest
61 @AfterMethod(alwaysRun = true)
62 public void tearDown()
64 Desktop.getInstance().closeAll_actionPerformed(null);
67 @Test(groups = "Functional")
68 public void testFindAllFeatures()
70 String seqData = ">s1\nabcdef\n>s2\nabcdef\n>s3\nabcdef\n>s4\nabcdef\n";
71 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
72 DataSourceType.PASTE);
73 AlignViewportI av = af.getViewport();
74 FeatureRenderer fr = new FeatureRenderer(av);
79 fr.findAllFeatures(true);
80 assertTrue(fr.getRenderOrder().isEmpty());
81 assertTrue(fr.getFeatureGroups().isEmpty());
83 List<SequenceI> seqs = av.getAlignment().getSequences();
85 // add a non-positional feature - should be ignored by FeatureRenderer
86 SequenceFeature sf1 = new SequenceFeature("Type", "Desc", 0, 0, 1f,
88 seqs.get(0).addSequenceFeature(sf1);
89 fr.findAllFeatures(true);
90 // ? bug - types and groups added for non-positional features
91 List<String> types = fr.getRenderOrder();
92 List<String> groups = fr.getFeatureGroups();
93 assertEquals(types.size(), 0);
94 assertFalse(types.contains("Type"));
95 assertEquals(groups.size(), 0);
96 assertFalse(groups.contains("Group"));
98 // add some positional features
99 seqs.get(1).addSequenceFeature(
100 new SequenceFeature("Pfam", "Desc", 5, 9, 1f, "PfamGroup"));
101 seqs.get(2).addSequenceFeature(
102 new SequenceFeature("Pfam", "Desc", 14, 22, 2f, "RfamGroup"));
103 // bug in findAllFeatures - group not checked for a known feature type
104 seqs.get(2).addSequenceFeature(new SequenceFeature("Rfam", "Desc", 5, 9,
105 Float.NaN, "RfamGroup"));
106 // existing feature type with null group
107 seqs.get(3).addSequenceFeature(
108 new SequenceFeature("Rfam", "Desc", 5, 9, Float.NaN, null));
109 // new feature type with null group
110 seqs.get(3).addSequenceFeature(
111 new SequenceFeature("Scop", "Desc", 5, 9, Float.NaN, null));
112 // null value for type produces NullPointerException
113 fr.findAllFeatures(true);
114 types = fr.getRenderOrder();
115 groups = fr.getFeatureGroups();
116 assertEquals(types.size(), 3);
117 assertFalse(types.contains("Type"));
118 assertTrue(types.contains("Pfam"));
119 assertTrue(types.contains("Rfam"));
120 assertTrue(types.contains("Scop"));
121 assertEquals(groups.size(), 2);
122 assertFalse(groups.contains("Group"));
123 assertTrue(groups.contains("PfamGroup"));
124 assertTrue(groups.contains("RfamGroup"));
125 assertFalse(groups.contains(null)); // null group is ignored
128 * check min-max values
130 Map<String, float[][]> minMax = fr.getMinMax();
131 assertEquals(minMax.size(), 1); // non-positional and NaN not stored
132 assertEquals(minMax.get("Pfam")[0][0], 1f); // positional min
133 assertEquals(minMax.get("Pfam")[0][1], 2f); // positional max
135 // increase max for Pfam, add scores for Rfam
136 seqs.get(0).addSequenceFeature(
137 new SequenceFeature("Pfam", "Desc", 14, 22, 8f, "RfamGroup"));
138 seqs.get(1).addSequenceFeature(
139 new SequenceFeature("Rfam", "Desc", 5, 9, 6f, "RfamGroup"));
140 fr.findAllFeatures(true);
141 // note minMax is not a defensive copy, shouldn't expose this
142 assertEquals(minMax.size(), 2);
143 assertEquals(minMax.get("Pfam")[0][0], 1f);
144 assertEquals(minMax.get("Pfam")[0][1], 8f);
145 assertEquals(minMax.get("Rfam")[0][0], 6f);
146 assertEquals(minMax.get("Rfam")[0][1], 6f);
149 * check render order (last is on top)
151 List<String> renderOrder = fr.getRenderOrder();
152 assertEquals(renderOrder, Arrays.asList("Scop", "Rfam", "Pfam"));
155 * change render order (todo: an easier way)
156 * nb here last comes first in the data array
158 FeatureSettingsBean[] data = new FeatureSettingsBean[3];
159 FeatureColourI colour = new FeatureColour(Color.RED);
160 data[0] = new FeatureSettingsBean("Rfam", colour, null, true);
161 data[1] = new FeatureSettingsBean("Pfam", colour, null, false);
162 data[2] = new FeatureSettingsBean("Scop", colour, null, false);
163 fr.setFeaturePriority(data);
164 assertEquals(fr.getRenderOrder(),
165 Arrays.asList("Scop", "Pfam", "Rfam"));
166 assertEquals(fr.getDisplayedFeatureTypes(), Arrays.asList("Rfam"));
169 * add a new feature type: should go on top of render order as visible,
170 * other feature ordering and visibility should be unchanged
172 seqs.get(2).addSequenceFeature(
173 new SequenceFeature("Metal", "Desc", 14, 22, 8f, "MetalGroup"));
174 fr.findAllFeatures(true);
175 assertEquals(fr.getRenderOrder(),
176 Arrays.asList("Scop", "Pfam", "Rfam", "Metal"));
177 assertEquals(fr.getDisplayedFeatureTypes(),
178 Arrays.asList("Rfam", "Metal"));
181 @Test(groups = "Functional")
182 public void testFindFeaturesAtColumn()
184 String seqData = ">s1/4-29\n-ab--cdefghijklmnopqrstuvwxyz\n";
185 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
186 DataSourceType.PASTE);
187 AlignViewportI av = af.getViewport();
188 FeatureRenderer fr = new FeatureRenderer(av);
189 SequenceI seq = av.getAlignment().getSequenceAt(0);
194 List<SequenceFeature> features = fr.findFeaturesAtColumn(seq, 3);
195 assertTrue(features.isEmpty());
200 SequenceFeature sf1 = new SequenceFeature("Type1", "Desc", 0, 0, 1f,
201 "Group"); // non-positional
202 seq.addSequenceFeature(sf1);
203 SequenceFeature sf2 = new SequenceFeature("Type2", "Desc", 8, 18, 1f,
205 seq.addSequenceFeature(sf2);
206 SequenceFeature sf3 = new SequenceFeature("Type3", "Desc", 8, 18, 1f,
208 seq.addSequenceFeature(sf3);
209 SequenceFeature sf4 = new SequenceFeature("Type3", "Desc", 8, 18, 1f,
210 null); // null group is always treated as visible
211 seq.addSequenceFeature(sf4);
214 * add contact features
216 SequenceFeature sf5 = new SequenceFeature("Disulphide Bond", "Desc", 7,
218 seq.addSequenceFeature(sf5);
219 SequenceFeature sf6 = new SequenceFeature("Disulphide Bond", "Desc", 7,
221 seq.addSequenceFeature(sf6);
222 SequenceFeature sf7 = new SequenceFeature("Disulphide Bond", "Desc", 7,
224 seq.addSequenceFeature(sf7);
226 // feature spanning B--C
227 SequenceFeature sf8 = new SequenceFeature("Type1", "Desc", 5, 6, 1f,
229 seq.addSequenceFeature(sf8);
230 // contact feature B/C
231 SequenceFeature sf9 = new SequenceFeature("Disulphide Bond", "Desc", 5,
233 seq.addSequenceFeature(sf9);
236 * let feature renderer discover features (and make visible)
238 fr.findAllFeatures(true);
239 features = fr.findFeaturesAtColumn(seq, 15); // all positional
240 assertEquals(features.size(), 6);
241 assertTrue(features.contains(sf2));
242 assertTrue(features.contains(sf3));
243 assertTrue(features.contains(sf4));
244 assertTrue(features.contains(sf5));
245 assertTrue(features.contains(sf6));
246 assertTrue(features.contains(sf7));
249 * at a non-contact position
251 features = fr.findFeaturesAtColumn(seq, 14);
252 assertEquals(features.size(), 3);
253 assertTrue(features.contains(sf2));
254 assertTrue(features.contains(sf3));
255 assertTrue(features.contains(sf4));
258 * make "Type2" not displayed
260 FeatureColourI colour = new FeatureColour(Color.RED);
261 FeatureSettingsBean[] data = new FeatureSettingsBean[4];
262 data[0] = new FeatureSettingsBean("Type1", colour, null, true);
263 data[1] = new FeatureSettingsBean("Type2", colour, null, false);
264 data[2] = new FeatureSettingsBean("Type3", colour, null, true);
265 data[3] = new FeatureSettingsBean("Disulphide Bond", colour, null,
267 fr.setFeaturePriority(data);
269 features = fr.findFeaturesAtColumn(seq, 15);
270 assertEquals(features.size(), 5); // no sf2
271 assertTrue(features.contains(sf3));
272 assertTrue(features.contains(sf4));
273 assertTrue(features.contains(sf5));
274 assertTrue(features.contains(sf6));
275 assertTrue(features.contains(sf7));
278 * make "Group2" not displayed
280 fr.setGroupVisibility("Group2", false);
282 features = fr.findFeaturesAtColumn(seq, 15);
283 assertEquals(features.size(), 3); // no sf2, sf3, sf6
284 assertTrue(features.contains(sf4));
285 assertTrue(features.contains(sf5));
286 assertTrue(features.contains(sf7));
288 // features 'at' a gap between b and c
289 // - returns enclosing feature BC but not contact feature B/C
290 features = fr.findFeaturesAtColumn(seq, 4);
291 assertEquals(features.size(), 1);
292 assertTrue(features.contains(sf8));
293 features = fr.findFeaturesAtColumn(seq, 5);
294 assertEquals(features.size(), 1);
295 assertTrue(features.contains(sf8));
298 * give "Type3" features a graduated colour scheme
299 * - first with no threshold
301 FeatureColourI gc = new FeatureColour(Color.green, Color.yellow,
302 Color.red, null, 0f, 10f);
303 fr.getFeatureColours().put("Type3", gc);
304 features = fr.findFeaturesAtColumn(seq, 8);
305 assertTrue(features.contains(sf4));
306 // now with threshold > 2f - feature score of 1f is excluded
307 gc.setAboveThreshold(true);
309 features = fr.findFeaturesAtColumn(seq, 8);
310 assertFalse(features.contains(sf4));
313 * make "Type3" graduated colour by attribute "AF"
314 * - first with no attribute held - feature should be excluded
316 gc.setAttributeName("AF");
317 features = fr.findFeaturesAtColumn(seq, 8);
318 assertFalse(features.contains(sf4));
319 // now with the attribute above threshold - should be included
320 sf4.setValue("AF", "2.4");
321 features = fr.findFeaturesAtColumn(seq, 8);
322 assertTrue(features.contains(sf4));
323 // now with the attribute below threshold - should be excluded
324 sf4.setValue("AF", "1.4");
325 features = fr.findFeaturesAtColumn(seq, 8);
326 assertFalse(features.contains(sf4));
329 @Test(groups = "Functional")
330 public void testFilterFeaturesForDisplay()
332 String seqData = ">s1\nabcdef\n";
333 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
334 DataSourceType.PASTE);
335 AlignViewportI av = af.getViewport();
336 FeatureRenderer fr = new FeatureRenderer(av);
338 List<SequenceFeature> features = new ArrayList<>();
339 fr.filterFeaturesForDisplay(features); // empty list, does nothing
341 SequenceI seq = av.getAlignment().getSequenceAt(0);
342 SequenceFeature sf1 = new SequenceFeature("Cath", "", 6, 8, Float.NaN,
344 SequenceFeature sf2 = new SequenceFeature("Cath", "", 5, 11, 2f,
346 SequenceFeature sf3 = new SequenceFeature("Cath", "", 5, 11, 3f,
348 SequenceFeature sf4 = new SequenceFeature("Cath", "", 6, 8, 4f,
350 SequenceFeature sf5 = new SequenceFeature("Cath", "", 6, 9, 5f,
352 seq.addSequenceFeature(sf1);
353 seq.addSequenceFeature(sf2);
354 seq.addSequenceFeature(sf3);
355 seq.addSequenceFeature(sf4);
356 seq.addSequenceFeature(sf5);
358 fr.findAllFeatures(true);
360 features = seq.getSequenceFeatures();
361 assertEquals(features.size(), 5);
362 assertTrue(features.contains(sf1));
363 assertTrue(features.contains(sf2));
364 assertTrue(features.contains(sf3));
365 assertTrue(features.contains(sf4));
366 assertTrue(features.contains(sf5));
369 * filter out duplicate (co-located) features
370 * note: which gets removed is not guaranteed
372 fr.filterFeaturesForDisplay(features);
373 assertEquals(features.size(), 3);
374 assertTrue(features.contains(sf1) || features.contains(sf4));
375 assertFalse(features.contains(sf1) && features.contains(sf4));
376 assertTrue(features.contains(sf2) || features.contains(sf3));
377 assertFalse(features.contains(sf2) && features.contains(sf3));
378 assertTrue(features.contains(sf5));
381 * features in hidden groups are removed
383 fr.setGroupVisibility("group2", false);
384 fr.setGroupVisibility("group3", false);
385 features = seq.getSequenceFeatures();
386 fr.filterFeaturesForDisplay(features);
387 assertEquals(features.size(), 2);
388 assertTrue(features.contains(sf1) || features.contains(sf4));
389 assertFalse(features.contains(sf1) && features.contains(sf4));
390 assertFalse(features.contains(sf2));
391 assertFalse(features.contains(sf3));
392 assertTrue(features.contains(sf5));
395 * no filtering if transparency is applied
397 fr.setTransparency(0.5f);
398 features = seq.getSequenceFeatures();
399 fr.filterFeaturesForDisplay(features);
400 assertEquals(features.size(), 5);
403 @Test(groups = "Functional")
404 public void testGetColour()
406 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(">s1\nABCD\n",
407 DataSourceType.PASTE);
408 AlignViewportI av = af.getViewport();
409 FeatureRenderer fr = new FeatureRenderer(av);
412 * simple colour, feature type and group displayed
414 FeatureColourI fc = new FeatureColour(Color.red);
415 fr.getFeatureColours().put("Cath", fc);
416 SequenceFeature sf1 = new SequenceFeature("Cath", "", 6, 8, Float.NaN,
418 assertEquals(fr.getColour(sf1), Color.red);
421 * hide feature type, then unhide
422 * - feature type visibility should not affect the result
424 FeatureSettingsBean[] data = new FeatureSettingsBean[1];
425 data[0] = new FeatureSettingsBean("Cath", fc, null, false);
426 fr.setFeaturePriority(data);
427 assertEquals(fr.getColour(sf1), Color.red);
428 data[0] = new FeatureSettingsBean("Cath", fc, null, true);
429 fr.setFeaturePriority(data);
430 assertEquals(fr.getColour(sf1), Color.red);
433 * hide feature group, then unhide
435 fr.setGroupVisibility("group1", false);
436 assertNull(fr.getColour(sf1));
437 fr.setGroupVisibility("group1", true);
438 assertEquals(fr.getColour(sf1), Color.red);
441 * graduated colour by score, no threshold, no score
444 FeatureColourI gc = new FeatureColour(Color.red, Color.yellow,
445 Color.red, Color.green, 1f, 11f);
446 fr.getFeatureColours().put("Cath", gc);
447 assertEquals(fr.getColour(sf1), Color.green);
450 * graduated colour by score, no threshold, with score value
452 SequenceFeature sf2 = new SequenceFeature("Cath", "", 6, 8, 6f,
454 // score 6 is half way from yellow(255, 255, 0) to red(255, 0, 0)
455 Color expected = new Color(255, 128, 0);
456 assertEquals(fr.getColour(sf2), expected);
459 * above threshold, score is above threshold - no change
461 gc.setAboveThreshold(true);
463 assertEquals(fr.getColour(sf2), expected);
466 * threshold is min-max; now score 6 is 1/6 of the way from 5 to 11
467 * or from yellow(255, 255, 0) to red(255, 0, 0)
469 gc = new FeatureColour(Color.red, Color.yellow, Color.red, Color.green,
471 fr.getFeatureColours().put("Cath", gc);
472 gc.setAutoScaled(false); // this does little other than save a checkbox
474 assertEquals(fr.getColour(sf2), new Color(255, 213, 0));
477 * feature score is below threshold - no colour
479 gc.setAboveThreshold(true);
481 assertNull(fr.getColour(sf2));
484 * feature score is above threshold - no colour
486 gc.setBelowThreshold(true);
488 assertNull(fr.getColour(sf2));
491 * colour by feature attribute value
492 * first with no value held
494 gc = new FeatureColour(Color.red, Color.yellow, Color.red, Color.green,
496 fr.getFeatureColours().put("Cath", gc);
497 gc.setAttributeName("AF");
498 assertEquals(fr.getColour(sf2), Color.green);
500 // with non-numeric attribute value
501 sf2.setValue("AF", "Five");
502 assertEquals(fr.getColour(sf2), Color.green);
504 // with numeric attribute value
505 sf2.setValue("AF", "6");
506 assertEquals(fr.getColour(sf2), expected);
508 // with numeric value outwith threshold
509 gc.setAboveThreshold(true);
510 gc.setThreshold(10f);
511 assertNull(fr.getColour(sf2));
513 // with filter on AF < 4
514 gc.setAboveThreshold(false);
515 assertEquals(fr.getColour(sf2), expected);
516 FeatureMatcherSetI filter = new FeatureMatcherSet();
517 filter.and(FeatureMatcher.byAttribute(Condition.LT, "4.0", "AF"));
518 fr.setFeatureFilter("Cath", filter);
519 assertNull(fr.getColour(sf2));
521 // with filter on 'Consequence contains missense'
522 filter = new FeatureMatcherSet();
523 filter.and(FeatureMatcher.byAttribute(Condition.Contains, "missense",
525 fr.setFeatureFilter("Cath", filter);
526 // if feature has no Consequence attribute, no colour
527 assertNull(fr.getColour(sf2));
528 // if attribute does not match filter, no colour
529 sf2.setValue("Consequence", "Synonymous");
530 assertNull(fr.getColour(sf2));
531 // attribute matches filter
532 sf2.setValue("Consequence", "Missense variant");
533 assertEquals(fr.getColour(sf2), expected);
535 // with filter on CSQ:Feature contains "ENST01234"
536 filter = new FeatureMatcherSet();
537 filter.and(FeatureMatcher.byAttribute(Condition.Matches, "ENST01234",
539 fr.setFeatureFilter("Cath", filter);
540 // if feature has no CSQ data, no colour
541 assertNull(fr.getColour(sf2));
542 // if CSQ data does not include Feature, no colour
543 Map<String, String> csqData = new HashMap<>();
544 csqData.put("BIOTYPE", "Transcript");
545 sf2.setValue("CSQ", csqData);
546 assertNull(fr.getColour(sf2));
547 // if attribute does not match filter, no colour
548 csqData.put("Feature", "ENST9876");
549 assertNull(fr.getColour(sf2));
550 // attribute matches filter
551 csqData.put("Feature", "ENST01234");
552 assertEquals(fr.getColour(sf2), expected);
555 @Test(groups = "Functional")
556 public void testIsVisible()
558 String seqData = ">s1\nMLQGIFPRS\n";
559 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
560 DataSourceType.PASTE);
561 AlignViewportI av = af.getViewport();
562 FeatureRenderer fr = new FeatureRenderer(av);
563 SequenceI seq = av.getAlignment().getSequenceAt(0);
564 SequenceFeature sf = new SequenceFeature("METAL", "Desc", 10, 10, 1f,
566 sf.setValue("AC", "11");
567 sf.setValue("CLIN_SIG", "Likely Pathogenic");
568 seq.addSequenceFeature(sf);
570 assertFalse(fr.isVisible(null));
573 * initial state FeatureRenderer hasn't 'found' feature
574 * and so its feature type has not yet been set visible
576 assertFalse(fr.getDisplayedFeatureCols().containsKey("METAL"));
577 assertFalse(fr.isVisible(sf));
579 fr.findAllFeatures(true);
580 assertTrue(fr.isVisible(sf));
583 * feature group not visible
585 fr.setGroupVisibility("Group", false);
586 assertFalse(fr.isVisible(sf));
587 fr.setGroupVisibility("Group", true);
588 assertTrue(fr.isVisible(sf));
591 * feature score outwith colour threshold (score > 2)
593 FeatureColourI fc = new FeatureColour(null, Color.white, Color.black,
595 fc.setAboveThreshold(true);
597 fr.setColour("METAL", fc);
598 assertFalse(fr.isVisible(sf)); // score 1 is not above threshold 2
599 fc.setBelowThreshold(true);
600 assertTrue(fr.isVisible(sf)); // score 1 is below threshold 2
603 * colour with threshold on attribute AC (value is 11)
605 fc.setAttributeName("AC");
606 assertFalse(fr.isVisible(sf)); // value 11 is not below threshold 2
607 fc.setAboveThreshold(true);
608 assertTrue(fr.isVisible(sf)); // value 11 is above threshold 2
610 fc.setAttributeName("AF"); // attribute AF is absent in sf
611 assertTrue(fr.isVisible(sf)); // feature is not excluded by threshold
613 FeatureMatcherSetI filter = new FeatureMatcherSet();
614 filter.and(FeatureMatcher.byAttribute(Condition.Contains, "pathogenic",
616 fr.setFeatureFilter("METAL", filter);
617 assertTrue(fr.isVisible(sf)); // feature matches filter
618 filter.and(FeatureMatcher.byScore(Condition.LE, "0.4"));
619 assertFalse(fr.isVisible(sf)); // feature doesn't match filter
622 @Test(groups = "Functional")
623 public void testFindComplementFeaturesAtResidue()
627 { "-nonews", "-props", "test/jalview/testProps.jvprops" });
630 String cdsSeq = ">cds\nATGtgtTGGcacTCAgaa";
631 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(cdsSeq,
632 DataSourceType.PASTE);
633 af.showTranslation_actionPerformed(
634 GeneticCodes.getInstance().getStandardCodeTable());
635 af.closeMenuItem_actionPerformed(true);
638 * find the complement frames (ugly)
640 AlignFrame[] frames = Desktop.getAlignFrames();
641 assertEquals(frames.length, 2);
642 AlignViewport av1 = frames[0].getViewport();
643 AlignViewport av2 = frames[1].getViewport();
644 AlignViewport cds = av1.getAlignment().isNucleotide() ? av1 : av2;
645 AlignViewport peptide = cds == av1 ? av2 : av1;
647 assertNotNull(peptide);
650 * add features to CDS at first codon, positions 2-3
652 SequenceI seq1 = cds.getAlignment().getSequenceAt(0);
653 SequenceFeature sf1 = new SequenceFeature("sequence_variant", "G,GT", 2,
655 seq1.addSequenceFeature(sf1);
656 SequenceFeature sf2 = new SequenceFeature("sequence_variant", "C, CA",
658 seq1.addSequenceFeature(sf2);
661 * 'find' mapped features from the peptide position
662 * - first with CDS features _not_ shown on peptide alignment
664 SequenceI seq2 = peptide.getAlignment().getSequenceAt(0);
665 FeatureRenderer frC = new FeatureRenderer(cds);
667 MappedFeatures mf = frC.findComplementFeaturesAtResidue(seq2, 1);
669 assertEquals(mf.features.size(), 2);
670 assertSame(mf.features.get(0), sf1);
671 assertSame(mf.features.get(1), sf2);
674 * add exon feature and verify it is only returned once for a
675 * peptide position, even though it is on all 3 codon positions
677 SequenceFeature sf3 = new SequenceFeature("exon", "exon1", 4, 12,
679 seq1.addSequenceFeature(sf3);
681 mf = frC.findComplementFeaturesAtResidue(seq2, 3);
683 assertEquals(mf.features.size(), 1);
684 assertSame(mf.features.get(0), sf3);