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.datamodel;
23 import jalview.analysis.AlignSeq;
24 import jalview.gui.JvOptionPane;
25 import jalview.io.AppletFormatAdapter;
26 import jalview.io.FileFormat;
27 import org.testng.Assert;
28 import org.testng.annotations.BeforeClass;
29 import org.testng.annotations.Test;
31 import static jalview.datamodel.Annotation.EMPTY_ANNOTATION;
32 import static jalview.testutils.Matchers.matchesAnnotations;
33 import static org.hamcrest.MatcherAssert.assertThat;
34 import static org.hamcrest.Matchers.is;
35 import static org.hamcrest.Matchers.nullValue;
36 import static org.testng.Assert.assertNull;
37 import static org.testng.AssertJUnit.assertEquals;
39 public class AlignmentAnnotationTests
42 @BeforeClass(alwaysRun = true)
43 public void setUpJvOptionPane()
45 JvOptionPane.setInteractiveMode(false);
46 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
49 @Test(groups = { "Functional" })
50 public void testCopyConstructor()
52 SequenceI sq = new Sequence("Foo", "ARAARARARAWEAWEAWRAWEAWE");
54 AlignmentAnnotation alc, alo = sq.getAnnotation()[0];
55 alc = new AlignmentAnnotation(alo);
57 // TODO: this only tests string equals (which is unreliable), should use
58 // refactored tests from StockholmFileTest
59 Assert.assertEquals(alc.toString(), alo.toString());
61 for (String key : alo.getProperties())
63 assertEquals("Property mismatch", alo.getProperty(key),
64 alc.getProperty(key));
69 * create some dummy annotation derived from the sequence
73 public static void createAnnotation(SequenceI sq)
75 Annotation[] al = new Annotation[sq.getLength()];
76 for (int i = 0; i < al.length; i++)
78 al[i] = new Annotation(new Annotation("" + sq.getCharAt(i), "", (char) 0,
81 AlignmentAnnotation alan = new AlignmentAnnotation("For " + sq.getName(),
82 "Fake alignment annot", al);
83 // create a sequence mapping for the annotation vector in its current state
84 alan.createSequenceMapping(sq, sq.getStart(), false);
85 alan.setProperty("CreatedBy", "createAnnotation");
86 sq.addAlignmentAnnotation(alan);
90 * use this to test annotation derived from method above as it is transferred
91 * across different sequences derived from same dataset coordinate frame
95 public static void testAnnotTransfer(AlignmentAnnotation ala)
97 assertEquals("Failed - need annotation created by createAnnotation method",
98 ala.description, "Fake alignment annot");
99 ala.adjustForAlignment();
100 for (int p = 0; p < ala.annotations.length; p++)
102 if (ala.annotations[p] != null)
105 "Mismatch at position " + p
106 + " between annotation position value and sequence"
107 + ala.annotations[p],
108 (int) ala.annotations[p].value, ala.sequenceRef.findPosition(p));
114 * Tests the liftOver method and also exercises the functions for remapping
115 * annotation across different reference sequences. Here, the test is between
116 * different dataset frames (annotation transferred by mapping between
119 @Test(groups = { "Functional" })
120 public void testLiftOver()
122 SequenceI sqFrom = new Sequence("fromLong", "QQQCDEWGH");
124 sqFrom.setEnd(sqFrom.findPosition(sqFrom.getLength() - 1));
125 SequenceI sqTo = new Sequence("toShort", "RCDEW");
127 sqTo.setEnd(sqTo.findPosition(sqTo.getLength() - 1));
128 createAnnotation(sqTo);
129 AlignmentAnnotation origTo = sqTo.getAnnotation()[0];
130 createAnnotation(sqFrom);
131 AlignmentAnnotation origFrom = sqFrom.getAnnotation()[0];
132 AlignSeq align = AlignSeq.doGlobalNWAlignment(sqFrom, sqTo, AlignSeq.PEP);
133 SequenceI alSeq1 = new Sequence(sqFrom.getName(), align.getAStr1());
134 alSeq1.setStart(sqFrom.getStart() + align.getSeq1Start() - 1);
135 alSeq1.setEnd(sqFrom.getStart() + align.getSeq1End() - 1);
136 alSeq1.setDatasetSequence(sqFrom);
137 SequenceI alSeq2 = new Sequence(sqTo.getName(), align.getAStr2());
138 alSeq2.setStart(sqTo.getStart() + align.getSeq2Start() - 1);
139 alSeq2.setEnd(sqTo.getStart() + align.getSeq2End() - 1);
140 alSeq2.setDatasetSequence(sqTo);
142 .println(new AppletFormatAdapter()
143 .formatSequences(FileFormat.Stockholm,
144 new Alignment(new SequenceI[] { sqFrom, alSeq1, sqTo, alSeq2 }),
147 Mapping mp = align.getMappingFromS1(false);
149 AlignmentAnnotation almap1 = new AlignmentAnnotation(
150 sqTo.getAnnotation()[0]);
151 almap1.liftOver(sqFrom, mp);
152 assertEquals(almap1.sequenceRef, sqFrom);
153 alSeq1.addAlignmentAnnotation(almap1);
154 almap1.setSequenceRef(alSeq1);
155 almap1.adjustForAlignment();
156 AlignmentAnnotation almap2 = new AlignmentAnnotation(
157 sqFrom.getAnnotation()[0]);
158 almap2.liftOver(sqTo, mp);
159 assertEquals(almap2.sequenceRef, sqTo);
161 alSeq2.addAlignmentAnnotation(almap2);
162 almap2.setSequenceRef(alSeq2);
163 almap2.adjustForAlignment();
165 AlignmentI all = new Alignment(new SequenceI[] { alSeq1, alSeq2 });
166 all.addAnnotation(almap1);
167 all.addAnnotation(almap2);
169 .println(new AppletFormatAdapter()
170 .formatSequences(FileFormat.Stockholm, all, true));
172 for (int p = 0; p < alSeq1.getLength(); p++)
174 Annotation orig1, trans1, orig2, trans2;
175 trans2 = almap2.annotations[p];
176 orig2 = origFrom.annotations[alSeq1.findPosition(p) - sqFrom.getStart()];
177 orig1 = origTo.annotations[alSeq2.findPosition(p) - sqTo.getStart()];
178 trans1 = almap1.annotations[p];
179 if (trans1 == trans2)
181 System.out.println("Pos " + p + " mismatch");
184 assertEquals("Mismatch on Original From and transferred annotation on 2",
185 (orig2 != null) ? orig2.toString() : null,
186 (trans2 != null) ? trans2.toString() : null);
187 assertEquals("Mismatch on Original To and transferred annotation on 1",
188 (orig1 != null) ? orig1.toString() : null,
189 (trans1 != null) ? trans1.toString() : null);
190 String alm1 = "" + (almap1.annotations.length > p
191 ? almap1.annotations[p].displayCharacter
193 String alm2 = "" + (almap2.annotations.length > p
194 ? almap2.annotations[p].displayCharacter
196 assertEquals("Position " + p + " " + alm1 + " " + alm2, alm1, alm2);
200 @Test(groups = { "Functional" })
201 public void testAdjustForAlignment()
203 SequenceI seq = new Sequence("TestSeq", "ABCDEFG");
204 seq.createDatasetSequence();
207 * Annotate positions 3/4/5 (CDE) with values 1/2/3
209 Annotation[] anns = new Annotation[] {
210 null, null, new Annotation(1), new Annotation(2), new Annotation(3) };
211 AlignmentAnnotation ann = new AlignmentAnnotation("SS",
212 "secondary structure", anns);
213 seq.addAlignmentAnnotation(ann);
216 * Check annotation map before modifying aligned sequence
218 assertNull(ann.getAnnotationForPosition(1));
219 assertNull(ann.getAnnotationForPosition(2));
220 assertNull(ann.getAnnotationForPosition(6));
221 assertNull(ann.getAnnotationForPosition(7));
222 assertEquals(1, ann.getAnnotationForPosition(3).value, 0.001d);
223 assertEquals(2, ann.getAnnotationForPosition(4).value, 0.001d);
224 assertEquals(3, ann.getAnnotationForPosition(5).value, 0.001d);
227 * Trim the displayed sequence to BCD and adjust annotations
229 seq.setSequence("BCD");
232 ann.adjustForAlignment();
235 * Should now have annotations for aligned positions 2, 3Q (CD) only
237 assertEquals(3, ann.annotations.length);
238 assertNull(ann.annotations[0]);
239 assertEquals(1, ann.annotations[1].value, 0.001);
240 assertEquals(2, ann.annotations[2].value, 0.001);
244 * Test the method that defaults rna symbol to the one matching the preceding
245 * unmatched opening bracket (if any)
247 @Test(groups = { "Functional" })
248 public void testGetDefaultRnaHelixSymbol()
250 AlignmentAnnotation ann = new AlignmentAnnotation("SS",
251 "secondary structure", null);
252 assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
254 Annotation[] anns = new Annotation[20];
255 ann.annotations = anns;
256 assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
258 anns[1] = new Annotation("(", "S", '(', 0f);
259 assertEquals("(", ann.getDefaultRnaHelixSymbol(0));
260 assertEquals("(", ann.getDefaultRnaHelixSymbol(1));
261 assertEquals(")", ann.getDefaultRnaHelixSymbol(2));
262 assertEquals(")", ann.getDefaultRnaHelixSymbol(3));
267 anns[1] = new Annotation("(", "S", '(', 0f);
268 anns[3] = new Annotation("[", "S", '[', 0f);
269 anns[5] = new Annotation("{", "S", '{', 0f);
270 anns[7] = new Annotation("<", "S", '<', 0f);
271 anns[9] = new Annotation("}", "S", '}', 0f);
272 anns[11] = new Annotation(">", "S", '>', 0f);
273 anns[13] = new Annotation(")", "S", ')', 0f);
274 anns[15] = new Annotation("]", "S", ']', 0f);
276 String expected = "(())]]}}>>>>]]]](";
277 for (int i = 0; i < expected.length(); i++)
279 assertEquals("column " + i, String.valueOf(expected.charAt(i)),
280 ann.getDefaultRnaHelixSymbol(i));
284 * .(.[.(.).{.}.<.].D.
286 anns[1] = new Annotation("(", "S", '(', 0f);
287 anns[3] = new Annotation("[", "S", '[', 0f);
288 anns[5] = new Annotation("(", "S", '(', 0f);
289 anns[7] = new Annotation(")", "S", ')', 0f);
290 anns[9] = new Annotation("{", "S", '{', 0f);
291 anns[11] = new Annotation("}", "S", '}', 0f);
292 anns[13] = new Annotation("<", "S", '>', 0f);
293 anns[15] = new Annotation("]", "S", ']', 0f);
294 anns[17] = new Annotation("D", "S", 'D', 0f);
296 expected = "(())]]))]]}}]]>>>>dd";
297 for (int i = 0; i < expected.length(); i++)
299 assertEquals("column " + i, String.valueOf(expected.charAt(i)),
300 ann.getDefaultRnaHelixSymbol(i));
304 public static Annotation newAnnotation(String ann)
309 val = Float.parseFloat(ann);
310 } catch (NumberFormatException q)
314 return new Annotation(ann, ann, '\0', val);
317 @Test(groups = { "Functional" })
318 public void testIsQuantitative()
320 AlignmentAnnotation ann = null;
322 ann = new AlignmentAnnotation("an", "some an", null);
324 .assertFalse(ann.isQuantitative(),
325 "Empty annotation set should not be quantitative.");
327 ann = new AlignmentAnnotation("an", "some an",
329 newAnnotation("4"), newAnnotation("1"), newAnnotation("1"),
330 newAnnotation("0.1"), newAnnotation("0.3") });
332 .assertTrue(ann.isQuantitative(),
333 "All numbers annotation set should be quantitative.");
335 ann = new AlignmentAnnotation("an", "some an",
337 newAnnotation("E"), newAnnotation("E"), newAnnotation("E"),
338 newAnnotation("E"), newAnnotation("E") });
340 .assertFalse(ann.isQuantitative(),
341 "All 'E' annotation set should not be quantitative.");
343 ann = new AlignmentAnnotation("an", "some an",
345 newAnnotation("E"), newAnnotation("1"), newAnnotation("2"),
346 newAnnotation("3"), newAnnotation("E") });
348 .assertTrue(ann.isQuantitative(),
349 "Mixed 'E' annotation set should be quantitative.");
352 @Test(groups = "Functional")
353 public void testMakeVisibleAnnotation()
355 HiddenColumns h = new HiddenColumns();
356 Annotation[] anns = new Annotation[] {
357 null, null, new Annotation(1), new Annotation(2), new Annotation(3),
358 null, null, new Annotation(4), new Annotation(5), new Annotation(6),
359 new Annotation(7), new Annotation(8) };
360 AlignmentAnnotation ann = new AlignmentAnnotation("an", "some an", anns);
363 AlignmentAnnotation emptyann = new AlignmentAnnotation("an", "some ann",
365 emptyann.makeVisibleAnnotation(h);
366 assertNull(emptyann.annotations);
368 emptyann.makeVisibleAnnotation(3, 4, h);
369 assertNull(emptyann.annotations);
371 // without bounds, does everything
372 ann.makeVisibleAnnotation(h);
373 assertEquals(12, ann.annotations.length);
374 assertNull(ann.annotations[0]);
375 assertNull(ann.annotations[1]);
376 assertEquals(1.0f, ann.annotations[2].value);
377 assertEquals(2.0f, ann.annotations[3].value);
378 assertEquals(3.0f, ann.annotations[4].value);
379 assertNull(ann.annotations[5]);
380 assertNull(ann.annotations[6]);
381 assertEquals(4.0f, ann.annotations[7].value);
382 assertEquals(5.0f, ann.annotations[8].value);
383 assertEquals(6.0f, ann.annotations[9].value);
384 assertEquals(7.0f, ann.annotations[10].value);
385 assertEquals(8.0f, ann.annotations[11].value);
387 // without hidden cols, just truncates
388 ann.makeVisibleAnnotation(3, 5, h);
389 assertEquals(3, ann.annotations.length);
390 assertEquals(2.0f, ann.annotations[0].value);
391 assertEquals(3.0f, ann.annotations[1].value);
392 assertNull(ann.annotations[2]);
394 anns = new Annotation[] {
395 null, null, new Annotation(1), new Annotation(2), new Annotation(3),
396 null, null, new Annotation(4), new Annotation(5), new Annotation(6),
397 new Annotation(7), new Annotation(8) };
398 ann = new AlignmentAnnotation("an", "some an", anns);
400 ann.makeVisibleAnnotation(1, 9, h);
401 assertEquals(5, ann.annotations.length);
402 assertNull(ann.annotations[0]);
403 assertEquals(1.0f, ann.annotations[1].value);
404 assertEquals(2.0f, ann.annotations[2].value);
405 assertEquals(5.0f, ann.annotations[3].value);
406 assertEquals(6.0f, ann.annotations[4].value);
408 anns = new Annotation[] {
409 null, null, new Annotation(1), new Annotation(2), new Annotation(3),
410 null, null, new Annotation(4), new Annotation(5), new Annotation(6),
411 new Annotation(7), new Annotation(8) };
412 ann = new AlignmentAnnotation("an", "some an", anns);
414 ann.makeVisibleAnnotation(1, 9, h);
415 assertEquals(3, ann.annotations.length);
416 assertEquals(2.0f, ann.annotations[0].value);
417 assertEquals(5.0f, ann.annotations[1].value);
418 assertEquals(6.0f, ann.annotations[2].value);
420 anns = new Annotation[] {
421 null, null, new Annotation(1), new Annotation(2), new Annotation(3),
422 null, null, new Annotation(4), new Annotation(5), new Annotation(6),
423 new Annotation(7), new Annotation(8), new Annotation(9),
424 new Annotation(10), new Annotation(11), new Annotation(12),
425 new Annotation(13), new Annotation(14), new Annotation(15) };
426 ann = new AlignmentAnnotation("an", "some an", anns);
427 h = new HiddenColumns();
428 h.hideColumns(5, 18);
429 h.hideColumns(20, 21);
430 ann.makeVisibleAnnotation(1, 21, h);
431 assertEquals(5, ann.annotations.length);
432 assertEquals(1.0f, ann.annotations[1].value);
433 assertEquals(2.0f, ann.annotations[2].value);
434 assertEquals(3.0f, ann.annotations[3].value);
435 assertNull(ann.annotations[0]);
436 assertNull(ann.annotations[4]);
439 @Test(groups = "Functional")
440 public void testMakeVisibleAnnotation_NullAnnotationsAndNoColsHidden()
442 AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", null);
443 HiddenColumns hc = new HiddenColumns();
444 ann.makeVisibleAnnotation(hc);
445 assertThat(ann.annotations, is(nullValue()));
448 @Test(groups = "Functional")
449 public void testMakeVisibleAnnotation_NullAnnotationsAndTrim()
451 AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", null);
452 HiddenColumns hc = new HiddenColumns();
453 ann.makeVisibleAnnotation(3, 5, hc);
454 assertThat(ann.annotations, is(nullValue()));
457 @Test(groups = "Functional")
458 public void testMakeVisibleAnnotation_NoColsHidden()
460 Annotation[] annots = new Annotation[] {
461 EMPTY_ANNOTATION, EMPTY_ANNOTATION, new Annotation(1),
462 new Annotation(2), new Annotation(3), EMPTY_ANNOTATION,
463 EMPTY_ANNOTATION, new Annotation(4), new Annotation(5),
464 EMPTY_ANNOTATION, new Annotation(6), new Annotation(7),
466 AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
467 HiddenColumns hc = new HiddenColumns();
468 ann.makeVisibleAnnotation(hc);
469 assertThat(ann.annotations, matchesAnnotations(annots));
472 @Test(groups = "Functional")
473 public void testMakeVisibleAnnotation_HideCols()
475 Annotation[] annots = new Annotation[] {
476 new Annotation(0), new Annotation(1), new Annotation(2),
477 new Annotation(3), new Annotation(4), new Annotation(5),
478 new Annotation(6), new Annotation(7), new Annotation(8) };
479 AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
480 HiddenColumns hc = new HiddenColumns();
481 hc.hideColumns(2, 6);
482 ann.makeVisibleAnnotation(hc);
483 var expected = new Annotation[] {
484 new Annotation(0), new Annotation(1), new Annotation(7),
486 assertThat(ann.annotations, matchesAnnotations(expected));
489 @Test(groups = "Functional")
490 public void testMakeVisibleAnnotation_ExplicitFullWidthAndHideCols()
492 Annotation[] annots = new Annotation[] {
493 new Annotation(0), new Annotation(1), new Annotation(2),
494 new Annotation(3), new Annotation(4), new Annotation(5),
495 new Annotation(6), new Annotation(7), new Annotation(8),
496 new Annotation(9), new Annotation(10), new Annotation(11) };
497 AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
498 HiddenColumns hc = new HiddenColumns();
499 hc.hideColumns(4, 7);
500 ann.makeVisibleAnnotation(0, 11, hc);
501 assertThat(ann.annotations,
502 matchesAnnotations(new Annotation(0), new Annotation(1),
503 new Annotation(2), new Annotation(3), new Annotation(8),
504 new Annotation(9), new Annotation(10), new Annotation(11)));
507 @Test(groups = "Functional")
508 public void testMakeVisibleAnnotation_ExplicitFullWidthAndHideCols2()
510 Annotation[] annots = new Annotation[] {
511 new Annotation(0), new Annotation(1), new Annotation(2),
512 new Annotation(3), new Annotation(4), new Annotation(5),
513 new Annotation(6), new Annotation(7), new Annotation(8), };
514 AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
515 HiddenColumns hc = new HiddenColumns();
516 hc.hideColumns(4, 7);
517 ann.makeVisibleAnnotation(0, 8, hc);
518 assertThat(ann.annotations,
519 matchesAnnotations(new Annotation(0), new Annotation(1),
520 new Annotation(2), new Annotation(3), new Annotation(8)));
523 @Test(groups = "Functional")
524 public void testMakeVisibleAnnotation_HideColsWithEmptyAnnots()
526 Annotation[] annots = new Annotation[] {
527 EMPTY_ANNOTATION, EMPTY_ANNOTATION, new Annotation(1),
528 new Annotation(2), new Annotation(3), EMPTY_ANNOTATION,
529 EMPTY_ANNOTATION, new Annotation(4), new Annotation(5),
530 EMPTY_ANNOTATION, new Annotation(6), new Annotation(7),
532 AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
533 HiddenColumns hc = new HiddenColumns();
534 hc.hideColumns(1, 3);
535 hc.hideColumns(8, 9);
536 ann.makeVisibleAnnotation(hc);
537 var expected = new Annotation[] {
538 EMPTY_ANNOTATION, new Annotation(3), EMPTY_ANNOTATION, EMPTY_ANNOTATION,
539 new Annotation(4), new Annotation(6), new Annotation(7),
541 assertThat(ann.annotations, matchesAnnotations(expected));
544 @Test(groups = "Functional")
545 public void testMakeVisibleAnnotation_HideColsWithNullAnnots()
547 Annotation[] annots = new Annotation[] {
548 null, null, new Annotation(2), null, new Annotation(4),
549 new Annotation(5), null, null };
550 AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
551 HiddenColumns hc = new HiddenColumns();
552 hc.hideColumns(2, 4);
553 ann.makeVisibleAnnotation(hc);
554 var expected = new Annotation[] {
555 null, null, new Annotation(5), null, null };
556 assertThat(ann.annotations, matchesAnnotations(expected));
559 @Test(groups = "Functional")
560 public void testMakeVisibleAnnotation_Truncate()
562 Annotation[] annots = new Annotation[] {
563 new Annotation(0), new Annotation(1), new Annotation(2),
564 new Annotation(3), new Annotation(4), new Annotation(5),
565 new Annotation(6), new Annotation(7) };
566 AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
567 ann.makeVisibleAnnotation(3, 6, new HiddenColumns());
568 assertThat(ann.annotations, matchesAnnotations(new Annotation(3),
569 new Annotation(4), new Annotation(5), new Annotation(6)));
572 @Test(groups = "Functional")
573 public void testMakeVisibleAnnotation_TruncateAndHideColumns()
575 Annotation[] annots = new Annotation[] {
576 new Annotation(0), new Annotation(1), new Annotation(2),
577 new Annotation(3), new Annotation(4), new Annotation(5),
578 new Annotation(6), new Annotation(7), new Annotation(8),
579 new Annotation(9), new Annotation(10), new Annotation(11) };
580 AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
581 HiddenColumns hc = new HiddenColumns();
582 hc.hideColumns(4, 7);
583 ann.makeVisibleAnnotation(1, 9, hc);
584 assertThat(ann.annotations,
585 matchesAnnotations(new Annotation(1), new Annotation(2),
586 new Annotation(3), new Annotation(8), new Annotation(9)));