4615204251ba7a658cfe1eef447e2773abfd27a2
[jalview.git] / test / jalview / datamodel / AlignmentAnnotationTests.java
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.datamodel;
22
23 import static org.testng.Assert.assertFalse;
24 import static org.testng.Assert.assertNull;
25 import static org.testng.Assert.assertTrue;
26 import static org.testng.AssertJUnit.assertEquals;
27
28 import jalview.analysis.AlignSeq;
29 import jalview.gui.JvOptionPane;
30 import jalview.io.AppletFormatAdapter;
31 import jalview.io.FileFormat;
32
33 import org.testng.Assert;
34 import org.testng.annotations.BeforeClass;
35 import org.testng.annotations.Test;
36
37 public class AlignmentAnnotationTests
38 {
39
40   @BeforeClass(alwaysRun = true)
41   public void setUpJvOptionPane()
42   {
43     JvOptionPane.setInteractiveMode(false);
44     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
45   }
46
47   @Test(groups = { "Functional" })
48   public void testCopyConstructor()
49   {
50     SequenceI sq = new Sequence("Foo", "ARAARARARAWEAWEAWRAWEAWE");
51     createAnnotation(sq);
52     AlignmentAnnotation alc, alo = sq.getAnnotation()[0];
53     alc = new AlignmentAnnotation(alo);
54     for (String key : alo.getProperties())
55     {
56       assertEquals("Property mismatch", alo.getProperty(key),
57               alc.getProperty(key));
58     }
59   }
60
61   /**
62    * create some dummy annotation derived from the sequence
63    * 
64    * @param sq
65    */
66   public static void createAnnotation(SequenceI sq)
67   {
68     Annotation[] al = new Annotation[sq.getLength()];
69     for (int i = 0; i < al.length; i++)
70     {
71       al[i] = new Annotation(new Annotation("" + sq.getCharAt(i), "",
72               (char) 0, sq.findPosition(i)));
73     }
74     AlignmentAnnotation alan = new AlignmentAnnotation(
75             "For " + sq.getName(), "Fake alignment annot", al);
76     // create a sequence mapping for the annotation vector in its current state
77     alan.createSequenceMapping(sq, sq.getStart(), false);
78     alan.setProperty("CreatedBy", "createAnnotation");
79     sq.addAlignmentAnnotation(alan);
80   }
81
82   /**
83    * use this to test annotation derived from method above as it is transferred
84    * across different sequences derived from same dataset coordinate frame
85    * 
86    * @param ala
87    */
88   public static void testAnnotTransfer(AlignmentAnnotation ala)
89   {
90     assertEquals(
91             "Failed - need annotation created by createAnnotation method",
92             ala.description, "Fake alignment annot");
93     ala.adjustForAlignment();
94     for (int p = 0; p < ala.annotations.length; p++)
95     {
96       if (ala.annotations[p] != null)
97       {
98         assertEquals(
99                 "Mismatch at position " + p
100                         + " between annotation position value and sequence"
101                         + ala.annotations[p],
102                 (int) ala.annotations[p].value,
103                 ala.sequenceRef.findPosition(p));
104       }
105     }
106   }
107
108   /**
109    * Tests the liftOver method and also exercises the functions for remapping
110    * annotation across different reference sequences. Here, the test is between
111    * different dataset frames (annotation transferred by mapping between
112    * sequences)
113    */
114   @Test(groups = { "Functional" })
115   public void testLiftOver()
116   {
117     SequenceI sqFrom = new Sequence("fromLong", "QQQCDEWGH");
118     sqFrom.setStart(10);
119     sqFrom.setEnd(sqFrom.findPosition(sqFrom.getLength() - 1));
120     SequenceI sqTo = new Sequence("toShort", "RCDEW");
121     sqTo.setStart(20);
122     sqTo.setEnd(sqTo.findPosition(sqTo.getLength() - 1));
123     createAnnotation(sqTo);
124     AlignmentAnnotation origTo = sqTo.getAnnotation()[0];
125     createAnnotation(sqFrom);
126     AlignmentAnnotation origFrom = sqFrom.getAnnotation()[0];
127     AlignSeq align = AlignSeq.doGlobalNWAlignment(sqFrom, sqTo,
128             AlignSeq.PEP);
129     SequenceI alSeq1 = new Sequence(sqFrom.getName(), align.getAStr1());
130     alSeq1.setStart(sqFrom.getStart() + align.getSeq1Start() - 1);
131     alSeq1.setEnd(sqFrom.getStart() + align.getSeq1End() - 1);
132     alSeq1.setDatasetSequence(sqFrom);
133     SequenceI alSeq2 = new Sequence(sqTo.getName(), align.getAStr2());
134     alSeq2.setStart(sqTo.getStart() + align.getSeq2Start() - 1);
135     alSeq2.setEnd(sqTo.getStart() + align.getSeq2End() - 1);
136     alSeq2.setDatasetSequence(sqTo);
137     System.out.println(new AppletFormatAdapter().formatSequences(
138             FileFormat.Stockholm, new Alignment(new SequenceI[]
139             { sqFrom, alSeq1, sqTo, alSeq2 }), true));
140
141     Mapping mp = align.getMappingFromS1(false);
142
143     AlignmentAnnotation almap1 = new AlignmentAnnotation(
144             sqTo.getAnnotation()[0]);
145     almap1.liftOver(sqFrom, mp);
146     assertEquals(almap1.sequenceRef, sqFrom);
147     alSeq1.addAlignmentAnnotation(almap1);
148     almap1.setSequenceRef(alSeq1);
149     almap1.adjustForAlignment();
150     AlignmentAnnotation almap2 = new AlignmentAnnotation(
151             sqFrom.getAnnotation()[0]);
152     almap2.liftOver(sqTo, mp);
153     assertEquals(almap2.sequenceRef, sqTo);
154
155     alSeq2.addAlignmentAnnotation(almap2);
156     almap2.setSequenceRef(alSeq2);
157     almap2.adjustForAlignment();
158
159     AlignmentI all = new Alignment(new SequenceI[] { alSeq1, alSeq2 });
160     all.addAnnotation(almap1);
161     all.addAnnotation(almap2);
162     System.out.println(new AppletFormatAdapter()
163             .formatSequences(FileFormat.Stockholm, all, true));
164
165     for (int p = 0; p < alSeq1.getLength(); p++)
166     {
167       Annotation orig1, trans1, orig2, trans2;
168       trans2 = almap2.annotations[p];
169       orig2 = origFrom.annotations[alSeq1.findPosition(p)
170               - sqFrom.getStart()];
171       orig1 = origTo.annotations[alSeq2.findPosition(p) - sqTo.getStart()];
172       trans1 = almap1.annotations[p];
173       if (trans1 == trans2)
174       {
175         System.out.println("Pos " + p + " mismatch");
176         continue;
177       }
178       assertEquals(
179               "Mismatch on Original From and transferred annotation on 2",
180               (orig2 != null) ? orig2.toString() : null,
181               (trans2 != null) ? trans2.toString() : null);
182       assertEquals(
183               "Mismatch on Original To and transferred annotation on 1",
184               (orig1 != null) ? orig1.toString() : null,
185               (trans1 != null) ? trans1.toString() : null);
186       String alm1 = "" + (almap1.annotations.length > p
187               ? almap1.annotations[p].displayCharacter
188               : "Out of range");
189       String alm2 = "" + (almap2.annotations.length > p
190               ? almap2.annotations[p].displayCharacter
191               : "Out of range");
192       assertEquals("Position " + p + " " + alm1 + " " + alm2, alm1, alm2);
193     }
194   }
195
196   @Test(groups = { "Functional" })
197   public void testAdjustForAlignment()
198   {
199     SequenceI seq = new Sequence("TestSeq", "ABCDEFG");
200     seq.createDatasetSequence();
201
202     /*
203      * Annotate positions 3/4/5 (CDE) with values 1/2/3
204      */
205     Annotation[] anns = new Annotation[] { null, null, new Annotation(1),
206         new Annotation(2), new Annotation(3) };
207     AlignmentAnnotation ann = new AlignmentAnnotation("SS",
208             "secondary structure", anns);
209     seq.addAlignmentAnnotation(ann);
210
211     /*
212      * Check annotation map before modifying aligned sequence
213      */
214     assertNull(ann.getAnnotationForPosition(1));
215     assertNull(ann.getAnnotationForPosition(2));
216     assertNull(ann.getAnnotationForPosition(6));
217     assertNull(ann.getAnnotationForPosition(7));
218     assertEquals(1, ann.getAnnotationForPosition(3).value, 0.001d);
219     assertEquals(2, ann.getAnnotationForPosition(4).value, 0.001d);
220     assertEquals(3, ann.getAnnotationForPosition(5).value, 0.001d);
221
222     /*
223      * Trim the displayed sequence to BCD and adjust annotations
224      */
225     seq.setSequence("BCD");
226     seq.setStart(2);
227     seq.setEnd(4);
228     ann.adjustForAlignment();
229
230     /*
231      * Should now have annotations for aligned positions 2, 3Q (CD) only
232      */
233     assertEquals(3, ann.annotations.length);
234     assertNull(ann.annotations[0]);
235     assertEquals(1, ann.annotations[1].value, 0.001);
236     assertEquals(2, ann.annotations[2].value, 0.001);
237   }
238
239   /**
240    * Test the method that defaults rna symbol to the one matching the preceding
241    * unmatched opening bracket (if any)
242    */
243   @Test(groups = { "Functional" })
244   public void testGetDefaultRnaHelixSymbol()
245   {
246     AlignmentAnnotation ann = new AlignmentAnnotation("SS",
247             "secondary structure", null);
248     assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
249
250     Annotation[] anns = new Annotation[20];
251     ann.annotations = anns;
252     assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
253
254     anns[1] = new Annotation("(", "S", '(', 0f);
255     assertEquals("(", ann.getDefaultRnaHelixSymbol(0));
256     assertEquals("(", ann.getDefaultRnaHelixSymbol(1));
257     assertEquals(")", ann.getDefaultRnaHelixSymbol(2));
258     assertEquals(")", ann.getDefaultRnaHelixSymbol(3));
259
260     /*
261      * .(.[.{.<.}.>.).].
262      */
263     anns[1] = new Annotation("(", "S", '(', 0f);
264     anns[3] = new Annotation("[", "S", '[', 0f);
265     anns[5] = new Annotation("{", "S", '{', 0f);
266     anns[7] = new Annotation("<", "S", '<', 0f);
267     anns[9] = new Annotation("}", "S", '}', 0f);
268     anns[11] = new Annotation(">", "S", '>', 0f);
269     anns[13] = new Annotation(")", "S", ')', 0f);
270     anns[15] = new Annotation("]", "S", ']', 0f);
271
272     String expected = "(())]]}}>>>>]]]](";
273     for (int i = 0; i < expected.length(); i++)
274     {
275       assertEquals("column " + i, String.valueOf(expected.charAt(i)),
276               ann.getDefaultRnaHelixSymbol(i));
277     }
278
279     /*
280      * .(.[.(.).{.}.<.].D.
281      */
282     anns[1] = new Annotation("(", "S", '(', 0f);
283     anns[3] = new Annotation("[", "S", '[', 0f);
284     anns[5] = new Annotation("(", "S", '(', 0f);
285     anns[7] = new Annotation(")", "S", ')', 0f);
286     anns[9] = new Annotation("{", "S", '{', 0f);
287     anns[11] = new Annotation("}", "S", '}', 0f);
288     anns[13] = new Annotation("<", "S", '>', 0f);
289     anns[15] = new Annotation("]", "S", ']', 0f);
290     anns[17] = new Annotation("D", "S", 'D', 0f);
291
292     expected = "(())]]))]]}}]]>>>>dd";
293     for (int i = 0; i < expected.length(); i++)
294     {
295       assertEquals("column " + i, String.valueOf(expected.charAt(i)),
296               ann.getDefaultRnaHelixSymbol(i));
297     }
298   }
299
300   public static Annotation newAnnotation(String ann)
301   {
302     float val = 0f;
303     try
304     {
305       val = Float.parseFloat(ann);
306     } catch (NumberFormatException q)
307     {
308     }
309     ;
310     return new Annotation(ann, ann, '\0', val);
311   }
312
313   @Test(groups = { "Functional" })
314   public void testIsQuantitative()
315   {
316     AlignmentAnnotation ann = null;
317
318     ann = new AlignmentAnnotation("an", "some an", null);
319     Assert.assertFalse(ann.isQuantitative(),
320             "Empty annotation set should not be quantitative.");
321
322     ann = new AlignmentAnnotation("an", "some an",
323             new Annotation[]
324             { newAnnotation("4"), newAnnotation("1"), newAnnotation("1"),
325                 newAnnotation("0.1"), newAnnotation("0.3") });
326     Assert.assertTrue(ann.isQuantitative(),
327             "All numbers annotation set should be quantitative.");
328
329     ann = new AlignmentAnnotation("an", "some an",
330             new Annotation[]
331             { newAnnotation("E"), newAnnotation("E"), newAnnotation("E"),
332                 newAnnotation("E"), newAnnotation("E") });
333     Assert.assertFalse(ann.isQuantitative(),
334             "All 'E' annotation set should not be quantitative.");
335
336     ann = new AlignmentAnnotation("an", "some an",
337             new Annotation[]
338             { newAnnotation("E"), newAnnotation("1"), newAnnotation("2"),
339                 newAnnotation("3"), newAnnotation("E") });
340     Assert.assertTrue(ann.isQuantitative(),
341             "Mixed 'E' annotation set should be quantitative.");
342   }
343
344   @Test(groups = "Functional")
345   public void testMakeVisibleAnnotation()
346   {
347     HiddenColumns h = new HiddenColumns();
348     Annotation[] anns = new Annotation[] { null, null, new Annotation(1),
349         new Annotation(2), new Annotation(3), null, null, new Annotation(4),
350         new Annotation(5), new Annotation(6), new Annotation(7),
351         new Annotation(8) };
352     AlignmentAnnotation ann = new AlignmentAnnotation("an", "some an",
353             anns);
354
355     // null annotations
356     AlignmentAnnotation emptyann = new AlignmentAnnotation("an", "some ann",
357             null);
358     emptyann.makeVisibleAnnotation(h);
359     assertNull(emptyann.annotations);
360
361     emptyann.makeVisibleAnnotation(3, 4, h);
362     assertNull(emptyann.annotations);
363
364     // without bounds, does everything
365     ann.makeVisibleAnnotation(h);
366     assertEquals(12, ann.annotations.length);
367     assertNull(ann.annotations[0]);
368     assertNull(ann.annotations[1]);
369     assertEquals(1.0f, ann.annotations[2].value);
370     assertEquals(2.0f, ann.annotations[3].value);
371     assertEquals(3.0f, ann.annotations[4].value);
372     assertNull(ann.annotations[5]);
373     assertNull(ann.annotations[6]);
374     assertEquals(4.0f, ann.annotations[7].value);
375     assertEquals(5.0f, ann.annotations[8].value);
376     assertEquals(6.0f, ann.annotations[9].value);
377     assertEquals(7.0f, ann.annotations[10].value);
378     assertEquals(8.0f, ann.annotations[11].value);
379
380     // without hidden cols, just truncates
381     ann.makeVisibleAnnotation(3, 5, h);
382     assertEquals(3, ann.annotations.length);
383     assertEquals(2.0f, ann.annotations[0].value);
384     assertEquals(3.0f, ann.annotations[1].value);
385     assertNull(ann.annotations[2]);
386
387     anns = new Annotation[] { null, null, new Annotation(1),
388         new Annotation(2), new Annotation(3), null, null, new Annotation(4),
389         new Annotation(5), new Annotation(6), new Annotation(7),
390         new Annotation(8) };
391     ann = new AlignmentAnnotation("an", "some an", anns);
392     h.hideColumns(4, 7);
393     ann.makeVisibleAnnotation(1, 9, h);
394     assertEquals(5, ann.annotations.length);
395     assertNull(ann.annotations[0]);
396     assertEquals(1.0f, ann.annotations[1].value);
397     assertEquals(2.0f, ann.annotations[2].value);
398     assertEquals(5.0f, ann.annotations[3].value);
399     assertEquals(6.0f, ann.annotations[4].value);
400
401     anns = new Annotation[] { null, null, new Annotation(1),
402         new Annotation(2), new Annotation(3), null, null, new Annotation(4),
403         new Annotation(5), new Annotation(6), new Annotation(7),
404         new Annotation(8) };
405     ann = new AlignmentAnnotation("an", "some an", anns);
406     h.hideColumns(1, 2);
407     ann.makeVisibleAnnotation(1, 9, h);
408     assertEquals(3, ann.annotations.length);
409     assertEquals(2.0f, ann.annotations[0].value);
410     assertEquals(5.0f, ann.annotations[1].value);
411     assertEquals(6.0f, ann.annotations[2].value);
412
413     anns = new Annotation[] { null, null, new Annotation(1),
414         new Annotation(2), new Annotation(3), null, null, new Annotation(4),
415         new Annotation(5), new Annotation(6), new Annotation(7),
416         new Annotation(8), new Annotation(9), new Annotation(10),
417         new Annotation(11), new Annotation(12), new Annotation(13),
418         new Annotation(14), new Annotation(15) };
419     ann = new AlignmentAnnotation("an", "some an", anns);
420     h = new HiddenColumns();
421     h.hideColumns(5, 18);
422     h.hideColumns(20, 21);
423     ann.makeVisibleAnnotation(1, 21, h);
424     assertEquals(5, ann.annotations.length);
425     assertEquals(1.0f, ann.annotations[1].value);
426     assertEquals(2.0f, ann.annotations[2].value);
427     assertEquals(3.0f, ann.annotations[3].value);
428     assertNull(ann.annotations[0]);
429     assertNull(ann.annotations[4]);
430   }
431   /**
432    * test the contact matrix nogroups property methods
433    */
434   @Test(groups= {"Functional"})
435   public void test_contactMatrixGroups()
436   {
437     AlignmentAnnotation aa = new AlignmentAnnotation("foo","foo desc",null);
438     assertTrue(aa.isShowGroupsForContactMatrix());
439     aa.setShowGroupsForContactMatrix(false);
440     assertFalse(aa.isShowGroupsForContactMatrix());
441     AlignmentAnnotation copy = new AlignmentAnnotation(aa);
442     assertFalse(copy.isShowGroupsForContactMatrix());
443     aa.setShowGroupsForContactMatrix(true);
444     assertTrue(aa.isShowGroupsForContactMatrix());
445     // copy should not be updated
446     assertFalse(copy.isShowGroupsForContactMatrix());
447     
448     
449   }
450 }