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.analysis;
23 import static org.testng.AssertJUnit.assertEquals;
25 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
26 import jalview.api.AlignViewportI;
27 import jalview.bin.Cache;
28 import jalview.datamodel.Alignment;
29 import jalview.datamodel.AlignmentAnnotation;
30 import jalview.datamodel.AlignmentI;
31 import jalview.datamodel.Sequence;
32 import jalview.datamodel.SequenceI;
33 import jalview.gui.AlignViewport;
34 import jalview.gui.JvOptionPane;
36 import java.util.Random;
38 import org.testng.annotations.BeforeClass;
39 import org.testng.annotations.BeforeMethod;
40 import org.testng.annotations.Test;
42 public class AnnotationSorterTest
45 @BeforeClass(alwaysRun = true)
46 public void setUpJvOptionPane()
48 JvOptionPane.setInteractiveMode(false);
49 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
52 private static final int NUM_SEQS = 6;
54 private static final int NUM_ANNS = 7;
56 private static final String SS = "secondary structure";
58 AlignViewportI av = null;
61 * Configure so that the viewport does not create autocalculated annotation -
62 * test methods flag selected annotation as autocalculated instead
64 @BeforeClass(alwaysRun = true)
65 public void setUpBeforeClass()
67 Cache.loadProperties("test/jalview/io/testProps.jvprops");
68 Cache.setProperty("SHOW_QUALITY", "false");
69 Cache.setProperty("SHOW_CONSERVATION", "false");
70 Cache.setProperty("SHOW_IDENTITY", "false");
71 Cache.setProperty("SHOW_OCCUPANCY", "false");
75 * Set up 6 sequences and 7 annotations.
77 @BeforeMethod(alwaysRun = true)
80 av = buildAlignment(NUM_SEQS, NUM_ANNS);
84 * Make an alignment viewport with numSeqs sequences and numAnns annotations
92 private AlignViewportI buildAlignment(int numSeqs, int numAnns)
94 SequenceI[] seqs = new Sequence[numSeqs];
95 for (int i = 0; i < numSeqs; i++)
97 seqs[i] = new Sequence("Sequence" + i, "axrdkfp");
99 Alignment al = new Alignment(seqs);
101 for (int i = 0; i < numAnns; i++)
103 AlignmentAnnotation ann = new AlignmentAnnotation(SS + i, "", 0);
104 al.addAnnotation(ann);
107 return new AlignViewport(al);
111 * Test sorting by annotation type (label) within sequence order, including
113 * <li>annotations with no sequence reference - sort to end keeping mutual
115 * <li>annotations with sequence ref = sort in sequence order</li>
116 * <li>multiple annotations for same sequence ref - sort by label
117 * non-case-specific</li>
118 * <li>annotations with reference to sequence not in alignment - treat like no
122 @Test(groups = { "Functional" })
123 public void testSortBySequenceAndLabel_autocalcLast()
125 AlignmentI al = av.getAlignment();
126 AlignmentAnnotation[] anns = al.getAlignmentAnnotation();
129 anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
130 anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
131 anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
132 anns[3].autoCalculated = true; anns[3].label = "Quality";
133 anns[4].autoCalculated = true; anns[4].label = "Consensus";
134 anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "label5";
135 anns[6].sequenceRef = al.getSequenceAt(3); anns[6].label = "IRP";
138 av.setShowAutocalculatedAbove(false);
139 AnnotationSorter testee = new AnnotationSorter(av);
140 testee.sort(SequenceAnnotationOrder.SEQUENCE_AND_LABEL, false);
141 assertEquals("label5", anns[0].label); // for sequence 0
142 assertEquals("label0", anns[1].label); // for sequence 1
143 assertEquals("iron", anns[2].label); // sequence 3 /iron
144 assertEquals("IRP", anns[3].label); // sequence 3/IRP
145 assertEquals("structure", anns[4].label); // sequence 3/structure
146 assertEquals("Quality", anns[5].label); // autocalc annotations
147 assertEquals("Consensus", anns[6].label); // retain ordering
151 * Variant with autocalculated annotations sorting to front
153 @Test(groups = { "Functional" })
154 public void testSortBySequenceAndLabel_autocalcFirst()
156 AlignmentI al = av.getAlignment();
157 AlignmentAnnotation[] anns = al.getAlignmentAnnotation();
160 anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
161 anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
162 anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
163 anns[3].autoCalculated = true; anns[3].label = "Quality";
164 anns[4].autoCalculated = true; anns[4].label = "Consensus";
165 anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "label5";
166 anns[6].sequenceRef = al.getSequenceAt(3); anns[6].label = "IRP";
169 av.setShowAutocalculatedAbove(true);
170 AnnotationSorter testee = new AnnotationSorter(av);
171 testee.sort(SequenceAnnotationOrder.SEQUENCE_AND_LABEL, false);
172 assertEquals("Quality", anns[0].label); // autocalc annotations
173 assertEquals("Consensus", anns[1].label); // retain ordering
174 assertEquals("label5", anns[2].label); // for sequence 0
175 assertEquals("label0", anns[3].label); // for sequence 1
176 assertEquals("iron", anns[4].label); // sequence 3 /iron
177 assertEquals("IRP", anns[5].label); // sequence 3/IRP
178 assertEquals("structure", anns[6].label); // sequence 3/structure
182 * Test sorting by annotation type (label) within sequence order, including
184 * <li>annotations with no sequence reference - sort to end keeping mutual
186 * <li>annotations with sequence ref = sort in sequence order</li>
187 * <li>multiple annotations for same sequence ref - sort by label
188 * non-case-specific</li>
189 * <li>annotations with reference to sequence not in alignment - treat like no
193 @Test(groups = { "Functional" })
194 public void testSortByLabelAndSequence_autocalcLast()
196 AlignmentI al = av.getAlignment();
197 AlignmentAnnotation[] anns = al.getAlignmentAnnotation();
200 anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
201 anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
202 anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
203 anns[3].autoCalculated = true; anns[3].label = "Quality";
204 anns[4].autoCalculated = true; anns[4].label = "Consensus";
205 anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "IRON";
206 anns[6].sequenceRef = al.getSequenceAt(2); anns[6].label = "Structure";
209 av.setShowAutocalculatedAbove(false);
210 AnnotationSorter testee = new AnnotationSorter(av);
211 testee.sort(SequenceAnnotationOrder.LABEL_AND_SEQUENCE, false);
212 assertEquals("IRON", anns[0].label); // IRON / sequence 0
213 assertEquals("iron", anns[1].label); // iron / sequence 3
214 assertEquals("label0", anns[2].label); // label0 / sequence 1
215 assertEquals("Structure", anns[3].label); // Structure / sequence 2
216 assertEquals("structure", anns[4].label); // structure / sequence 3
217 assertEquals("Quality", anns[5].label); // autocalc annotations
218 assertEquals("Consensus", anns[6].label); // retain ordering
222 * Variant of test with autocalculated annotations sorted to front
224 @Test(groups = { "Functional" })
225 public void testSortByLabelAndSequence_autocalcFirst()
227 AlignmentI al = av.getAlignment();
228 AlignmentAnnotation[] anns = al.getAlignmentAnnotation();
231 anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
232 anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
233 anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
234 anns[3].autoCalculated = true; anns[3].label = "Quality";
235 anns[4].autoCalculated = true; anns[4].label = "Consensus";
236 anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "IRON";
237 anns[6].sequenceRef = al.getSequenceAt(2); anns[6].label = "Structure";
240 av.setShowAutocalculatedAbove(true);
241 AnnotationSorter testee = new AnnotationSorter(av);
242 testee.sort(SequenceAnnotationOrder.LABEL_AND_SEQUENCE, false);
243 assertEquals("Quality", anns[0].label); // autocalc annotations
244 assertEquals("Consensus", anns[1].label); // retain ordering
245 assertEquals("IRON", anns[2].label); // IRON / sequence 0
246 assertEquals("iron", anns[3].label); // iron / sequence 3
247 assertEquals("label0", anns[4].label); // label0 / sequence 1
248 assertEquals("Structure", anns[5].label); // Structure / sequence 2
249 assertEquals("structure", anns[6].label); // structure / sequence 3
253 * Variant of test with autocalculated annotations sorted to front but
254 * otherwise no change.
256 @Test(groups = { "Functional" })
257 public void testNoSort_autocalcFirst()
259 AlignmentI al = av.getAlignment();
260 AlignmentAnnotation[] anns = al.getAlignmentAnnotation();
263 anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
264 anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
265 anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
266 anns[3].autoCalculated = true; anns[3].label = "Quality";
267 anns[4].autoCalculated = true; anns[4].label = "Consensus";
268 anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "IRON";
269 anns[6].sequenceRef = al.getSequenceAt(2); anns[6].label = "Structure";
272 av.setShowAutocalculatedAbove(true);
273 AnnotationSorter testee = new AnnotationSorter(av);
274 testee.sort(SequenceAnnotationOrder.NONE, false);
275 assertEquals("Quality", anns[0].label); // autocalc annotations
276 assertEquals("Consensus", anns[1].label); // retain ordering
277 assertEquals("label0", anns[2].label);
278 assertEquals("structure", anns[3].label);
279 assertEquals("iron", anns[4].label);
280 assertEquals("IRON", anns[5].label);
281 assertEquals("Structure", anns[6].label);
284 @Test(groups = { "Functional" })
285 public void testSort_timingPresorted()
287 testTiming_presorted(50, 100);
288 testTiming_presorted(500, 1000);
289 testTiming_presorted(5000, 10000);
293 * Test timing to sort annotations already in the sort order.
298 private void testTiming_presorted(final int numSeqs, final int numAnns)
300 AlignViewportI viewport = buildAlignment(numSeqs, numAnns);
301 AlignmentI alignment = viewport.getAlignment();
302 AlignmentAnnotation[] annotations = alignment.getAlignmentAnnotation();
305 * Set the annotations presorted by label
307 Random r = new Random();
308 final SequenceI[] sequences = alignment.getSequencesArray();
309 for (int i = 0; i < annotations.length; i++)
311 SequenceI randomSequenceRef = sequences[r.nextInt(sequences.length)];
312 annotations[i].sequenceRef = randomSequenceRef;
313 annotations[i].label = "label" + i;
315 long startTime = System.currentTimeMillis();
316 viewport.setShowAutocalculatedAbove(false);
317 AnnotationSorter testee = new AnnotationSorter(viewport);
318 testee.sort(SequenceAnnotationOrder.LABEL_AND_SEQUENCE, false);
319 long endTime = System.currentTimeMillis();
320 final long elapsed = endTime - startTime;
321 System.out.println("Timing test for presorted " + numSeqs
322 + " sequences and " + numAnns + " annotations took " + elapsed
327 * Timing tests for sorting randomly sorted annotations for various sizes.
329 @Test(groups = { "Functional" })
330 public void testSort_timingUnsorted()
332 testTiming_unsorted(50, 100);
333 testTiming_unsorted(500, 1000);
334 testTiming_unsorted(5000, 10000);
338 * Generate annotations randomly sorted with respect to sequences, and time
344 private void testTiming_unsorted(final int numSeqs, final int numAnns)
346 AlignViewportI viewport = buildAlignment(numSeqs, numAnns);
347 AlignmentI alignment = viewport.getAlignment();
348 AlignmentAnnotation[] annotations = alignment.getAlignmentAnnotation();
351 * Set the annotations in random order with respect to the sequences
353 Random r = new Random();
354 final SequenceI[] sequences = alignment.getSequencesArray();
355 for (int i = 0; i < annotations.length; i++)
357 SequenceI randomSequenceRef = sequences[r.nextInt(sequences.length)];
358 annotations[i].sequenceRef = randomSequenceRef;
359 annotations[i].label = "label" + i;
361 long startTime = System.currentTimeMillis();
362 av.setShowAutocalculatedAbove(false);
363 AnnotationSorter testee = new AnnotationSorter(av);
364 testee.sort(SequenceAnnotationOrder.SEQUENCE_AND_LABEL, false);
365 long endTime = System.currentTimeMillis();
366 final long elapsed = endTime - startTime;
367 System.out.println("Timing test for unsorted " + numSeqs
368 + " sequences and " + numAnns + " annotations took " + elapsed
373 * Timing test for sorting annotations with a limited range of types (labels).
375 @Test(groups = { "Functional" })
376 public void testSort_timingSemisorted()
378 testTiming_semiSorted(50, 100);
379 testTiming_semiSorted(500, 1000);
380 testTiming_semiSorted(5000, 10000);
384 * Mimic 'semi-sorted' annotations:
386 * <li>set up in sequence order, with randomly assigned labels from a limited
388 * <li>sort by label and sequence order, report timing</li>
389 * <li>resort by sequence and label, report timing</li>
390 * <li>resort by label and sequence, report timing</li>
396 private void testTiming_semiSorted(final int numSeqs, final int numAnns)
398 AlignViewportI viewport = buildAlignment(numSeqs, numAnns);
399 AlignmentI alignment = viewport.getAlignment();
400 AlignmentAnnotation[] annotations = alignment.getAlignmentAnnotation();
402 String[] labels = new String[] { "label1", "label2", "label3",
403 "label4", "label5", "label6" };
406 * Set the annotations in sequence order with randomly assigned labels.
408 Random r = new Random();
409 final SequenceI[] sequences = alignment.getSequencesArray();
410 for (int i = 0; i < annotations.length; i++)
412 SequenceI sequenceRef = sequences[i % sequences.length];
413 annotations[i].sequenceRef = sequenceRef;
414 annotations[i].label = labels[r.nextInt(labels.length)];
416 long startTime = System.currentTimeMillis();
417 av.setShowAutocalculatedAbove(false);
418 AnnotationSorter testee = new AnnotationSorter(av);
419 testee.sort(SequenceAnnotationOrder.LABEL_AND_SEQUENCE, false);
420 long endTime = System.currentTimeMillis();
421 long elapsed = endTime - startTime;
422 System.out.println("Sort by label for semisorted " + numSeqs
423 + " sequences and " + numAnns + " annotations took " + elapsed
426 // now resort by sequence
427 startTime = System.currentTimeMillis();
428 testee.sort(SequenceAnnotationOrder.SEQUENCE_AND_LABEL, false);
429 endTime = System.currentTimeMillis();
430 elapsed = endTime - startTime;
431 System.out.println("Resort by sequence for semisorted " + numSeqs
432 + " sequences and " + numAnns + " annotations took " + elapsed
435 // now resort by label
436 startTime = System.currentTimeMillis();
437 testee.sort(SequenceAnnotationOrder.LABEL_AND_SEQUENCE, false);
438 endTime = System.currentTimeMillis();
439 elapsed = endTime - startTime;
440 System.out.println("Resort by label for semisorted " + numSeqs
441 + " sequences and " + numAnns + " annotations took " + elapsed
446 * Test that sort does nothing if sort order is CUSTOM (manually ordered
449 @Test(groups = { "Functional" })
450 public void testSort_custom()
452 AlignmentI al = av.getAlignment();
453 AlignmentAnnotation[] anns = al.getAlignmentAnnotation();
456 anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
457 anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
458 anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
459 anns[3].autoCalculated = true; anns[3].label = "Quality";
460 anns[4].autoCalculated = true; anns[4].label = "Consensus";
461 anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "label5";
462 anns[6].sequenceRef = al.getSequenceAt(3); anns[6].label = "IRP";
466 * showAutocalcAbove=true ignored if CUSTOM ordering
468 av.setShowAutocalculatedAbove(true);
469 AnnotationSorter testee = new AnnotationSorter(av);
470 testee.sort(SequenceAnnotationOrder.CUSTOM, false);
471 assertEquals("label0", anns[0].label); // all unchanged
472 assertEquals("structure", anns[1].label);
473 assertEquals("iron", anns[2].label);
474 assertEquals("Quality", anns[3].label);
475 assertEquals("Consensus", anns[4].label);
476 assertEquals("label5", anns[5].label);
477 assertEquals("IRP", anns[6].label);
481 * Test of sorting only autocalculated annotations
483 @Test(groups = { "Functional" })
484 public void testSort_autocalcOnly()
486 AlignmentI al = av.getAlignment();
487 AlignmentAnnotation[] anns = al.getAlignmentAnnotation();
490 anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
491 anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
492 anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
493 anns[3].autoCalculated = true; anns[3].label = "Quality";
494 anns[4].autoCalculated = true; anns[4].label = "Consensus";
495 anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "label5";
496 anns[6].sequenceRef = al.getSequenceAt(3); anns[6].label = "IRP";
500 * showAutocalcAbove=true, autocalcOnly=true
502 av.setShowAutocalculatedAbove(true);
503 AnnotationSorter testee = new AnnotationSorter(av);
504 testee.sort(SequenceAnnotationOrder.LABEL_AND_SEQUENCE, true);
505 assertEquals("Quality", anns[0].label); // moved to top
506 assertEquals("Consensus", anns[1].label); // moved to top
507 assertEquals("label0", anns[2].label); // the rest unchanged
508 assertEquals("structure", anns[3].label);
509 assertEquals("iron", anns[4].label);
510 assertEquals("label5", anns[5].label);
511 assertEquals("IRP", anns[6].label);
514 * showAutocalcAbove=false, autocalcOnly=true
516 av.setShowAutocalculatedAbove(false);
517 testee = new AnnotationSorter(av);
518 testee.sort(SequenceAnnotationOrder.LABEL_AND_SEQUENCE, true);
519 assertEquals("label0", anns[0].label); // unchanged
520 assertEquals("structure", anns[1].label);
521 assertEquals("iron", anns[2].label);
522 assertEquals("label5", anns[3].label);
523 assertEquals("IRP", anns[4].label);
524 assertEquals("Quality", anns[5].label); // moved to bottom
525 assertEquals("Consensus", anns[6].label); // moved to bottom