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;
24 import static org.testng.AssertJUnit.assertFalse;
25 import static org.testng.AssertJUnit.assertTrue;
27 import jalview.datamodel.AlignmentAnnotation;
28 import jalview.datamodel.AlignmentI;
29 import jalview.datamodel.Annotation;
30 import jalview.datamodel.SequenceI;
31 import jalview.gui.JvOptionPane;
32 import jalview.io.AppletFormatAdapter;
34 import java.io.IOException;
35 import java.util.ArrayList;
36 import java.util.BitSet;
37 import java.util.Collection;
38 import java.util.HashMap;
39 import java.util.List;
42 import org.testng.annotations.BeforeClass;
43 import org.testng.annotations.BeforeMethod;
44 import org.testng.annotations.Test;
46 public class AlignmentAnnotationUtilsTest
49 @BeforeClass(alwaysRun = true)
50 public void setUpJvOptionPane()
52 JvOptionPane.setInteractiveMode(false);
53 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
56 // 4 sequences x 13 positions
57 final static String EOL = "\n";
60 final static String TEST_DATA =
61 ">FER_CAPAA Ferredoxin" + EOL +
62 "TIETHKEAELVG-" + EOL +
63 ">FER_CAPAN Ferredoxin, chloroplast precursor" + EOL +
64 "TIETHKEAELVG-" + EOL +
65 ">FER1_SOLLC Ferredoxin-1, chloroplast precursor" + EOL +
66 "TIETHKEEELTA-" + EOL +
67 ">Q93XJ9_SOLTU Ferredoxin I precursor" + EOL +
68 "TIETHKEEELTA-" + EOL;
71 private static final int SEQ_ANN_COUNT = 12;
73 private AlignmentI alignment;
76 * Test method that converts a (possibly null) array to a list.
78 @Test(groups = { "Functional" })
79 public void testAsList()
82 Collection<AlignmentAnnotation> c1 = AlignmentAnnotationUtils
84 assertTrue(c1.isEmpty());
87 AlignmentAnnotation[] anns = new AlignmentAnnotation[0];
88 c1 = AlignmentAnnotationUtils.asList(anns);
89 assertTrue(c1.isEmpty());
92 anns = new AlignmentAnnotation[2];
93 anns[0] = new AlignmentAnnotation("label0", "desc0", 0.0f);
94 anns[1] = new AlignmentAnnotation("label1", "desc1", 1.0f);
95 c1 = AlignmentAnnotationUtils.asList(anns);
96 assertEquals(2, c1.size());
97 assertTrue(c1.contains(anns[0]));
98 assertTrue(c1.contains(anns[1]));
102 * This output is not part of the test but may help make sense of it...
107 protected void consoleDebug(Map<String, List<List<String>>> shownTypes,
108 Map<String, List<List<String>>> hiddenTypes)
110 for (String calcId : shownTypes.keySet())
112 System.out.println("Visible annotation types for calcId=" + calcId);
113 for (List<String> type : shownTypes.get(calcId))
115 System.out.println(" " + type);
118 for (String calcId : hiddenTypes.keySet())
120 System.out.println("Hidden annotation types for calcId=" + calcId);
121 for (List<String> type : hiddenTypes.get(calcId))
123 System.out.println(" " + type);
129 * Add a sequence group to the alignment with the specified sequences (base 0)
135 private List<SequenceI> selectSequences(int... selected)
137 List<SequenceI> result = new ArrayList<SequenceI>();
138 SequenceI[] seqs = alignment.getSequencesArray();
139 for (int i : selected)
147 * Load the test alignment and generate annotations on it
149 * @throws IOException
151 @BeforeMethod(alwaysRun = true)
152 public void setUp() throws IOException
154 alignment = new jalview.io.FormatAdapter().readFile(TEST_DATA,
155 AppletFormatAdapter.PASTE, "FASTA");
157 AlignmentAnnotation[] anns = new AlignmentAnnotation[SEQ_ANN_COUNT];
158 for (int i = 0; i < anns.length; i++)
161 * Use the constructor for a positional annotation (with an Annotation
164 anns[i] = new AlignmentAnnotation("Label" + i, "Desc " + i,
165 new Annotation[] {});
166 anns[i].setCalcId("CalcId" + i);
167 anns[i].visible = true;
168 alignment.addAnnotation(anns[i]);
173 * Test a mixture of show/hidden annotations in/outside selection group.
175 @Test(groups = { "Functional" })
176 public void testGetShownHiddenTypes_forSelectionGroup()
178 Map<String, List<List<String>>> shownTypes = new HashMap<String, List<List<String>>>();
179 Map<String, List<List<String>>> hiddenTypes = new HashMap<String, List<List<String>>>();
180 AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation();
181 SequenceI[] seqs = alignment.getSequencesArray();
184 * Configure annotation properties for test
186 // not in selection group (should be ignored):
187 // hidden annotation Label4 not in selection group
188 anns[4].sequenceRef = seqs[2];
189 anns[4].visible = false;
190 anns[7].sequenceRef = seqs[1];
191 anns[7].visible = true;
194 * in selection group, hidden:
196 anns[2].sequenceRef = seqs[3]; // CalcId2/Label2
197 anns[2].visible = false;
198 anns[3].sequenceRef = seqs[3]; // CalcId3/Label2
199 anns[3].visible = false;
200 anns[3].label = "Label2";
201 anns[4].sequenceRef = seqs[3]; // CalcId2/Label3
202 anns[4].visible = false;
203 anns[4].label = "Label3";
204 anns[4].setCalcId("CalcId2");
205 anns[8].sequenceRef = seqs[0]; // CalcId9/Label9
206 anns[8].visible = false;
207 anns[8].label = "Label9";
208 anns[8].setCalcId("CalcId9");
210 * in selection group, visible
212 anns[6].sequenceRef = seqs[0]; // CalcId6/Label6
213 anns[6].visible = true;
214 anns[9].sequenceRef = seqs[3]; // CalcId9/Label9
215 anns[9].visible = true;
217 List<SequenceI> selected = selectSequences(0, 3);
218 AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes,
219 AlignmentAnnotationUtils.asList(anns), selected);
221 // check results; note CalcId9/Label9 is both hidden and shown (for
222 // different sequences) so should be in both
223 // shown: CalcId6/Label6 and CalcId9/Label9
224 assertEquals(2, shownTypes.size());
225 assertEquals(1, shownTypes.get("CalcId6").size());
226 assertEquals(1, shownTypes.get("CalcId6").get(0).size());
227 assertEquals("Label6", shownTypes.get("CalcId6").get(0).get(0));
228 assertEquals(1, shownTypes.get("CalcId9").size());
229 assertEquals(1, shownTypes.get("CalcId9").get(0).size());
230 assertEquals("Label9", shownTypes.get("CalcId9").get(0).get(0));
232 // hidden: CalcId2/Label2, CalcId2/Label3, CalcId3/Label2, CalcId9/Label9
233 assertEquals(3, hiddenTypes.size());
234 assertEquals(2, hiddenTypes.get("CalcId2").size());
235 assertEquals(1, hiddenTypes.get("CalcId2").get(0).size());
236 assertEquals("Label2", hiddenTypes.get("CalcId2").get(0).get(0));
237 assertEquals(1, hiddenTypes.get("CalcId2").get(1).size());
238 assertEquals("Label3", hiddenTypes.get("CalcId2").get(1).get(0));
239 assertEquals(1, hiddenTypes.get("CalcId3").size());
240 assertEquals(1, hiddenTypes.get("CalcId3").get(0).size());
241 assertEquals("Label2", hiddenTypes.get("CalcId3").get(0).get(0));
242 assertEquals(1, hiddenTypes.get("CalcId9").size());
243 assertEquals(1, hiddenTypes.get("CalcId9").get(0).size());
244 assertEquals("Label9", hiddenTypes.get("CalcId9").get(0).get(0));
246 consoleDebug(shownTypes, hiddenTypes);
250 * Test case where there are 'grouped' annotations, visible and hidden, within
251 * and without the selection group.
253 @Test(groups = { "Functional" })
254 public void testGetShownHiddenTypes_withGraphGroups()
256 final int GROUP_3 = 3;
257 final int GROUP_4 = 4;
258 final int GROUP_5 = 5;
259 final int GROUP_6 = 6;
261 Map<String, List<List<String>>> shownTypes = new HashMap<String, List<List<String>>>();
262 Map<String, List<List<String>>> hiddenTypes = new HashMap<String, List<List<String>>>();
263 AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation();
264 SequenceI[] seqs = alignment.getSequencesArray();
267 * Annotations for selection group and graph group
269 * Hidden annotations Label2, Label3, in (hidden) group 5
271 anns[2].sequenceRef = seqs[3];
272 anns[2].visible = false;
273 anns[2].graph = AlignmentAnnotation.LINE_GRAPH;
274 anns[2].graphGroup = GROUP_5; // not a visible group
275 anns[3].sequenceRef = seqs[0];
276 anns[3].visible = false;
277 anns[3].graph = AlignmentAnnotation.LINE_GRAPH;
278 anns[3].graphGroup = GROUP_5;
279 // need to ensure annotations have the same calcId as well
280 anns[3].setCalcId("CalcId2");
281 // annotations for a different hidden group generating the same group label
282 anns[10].sequenceRef = seqs[0];
283 anns[10].visible = false;
284 anns[10].graph = AlignmentAnnotation.LINE_GRAPH;
285 anns[10].graphGroup = GROUP_3;
286 anns[10].label = "Label3";
287 anns[10].setCalcId("CalcId2");
288 anns[11].sequenceRef = seqs[3];
289 anns[11].visible = false;
290 anns[11].graph = AlignmentAnnotation.LINE_GRAPH;
291 anns[11].graphGroup = GROUP_3;
292 anns[11].label = "Label2";
293 anns[11].setCalcId("CalcId2");
295 // annotations Label1 (hidden), Label5 (visible) in group 6 (visible)
296 anns[1].sequenceRef = seqs[3];
297 // being in a visible group should take precedence over this visibility
298 anns[1].visible = false;
299 anns[1].graph = AlignmentAnnotation.LINE_GRAPH;
300 anns[1].graphGroup = GROUP_6;
301 anns[5].sequenceRef = seqs[0];
302 anns[5].visible = true;
303 anns[5].graph = AlignmentAnnotation.LINE_GRAPH;
304 anns[5].graphGroup = GROUP_6;
305 anns[5].setCalcId("CalcId1");
307 * Annotations 0 and 4 are visible, for a different CalcId and graph group.
308 * They produce the same label as annotations 1 and 5, which should not be
309 * duplicated in the results. This case corresponds to (e.g.) many
310 * occurrences of an IUPred Short/Long annotation group, one per sequence.
312 anns[4].sequenceRef = seqs[0];
313 anns[4].visible = false;
314 anns[4].graph = AlignmentAnnotation.LINE_GRAPH;
315 anns[4].graphGroup = GROUP_4;
316 anns[4].label = "Label1";
317 anns[4].setCalcId("CalcId1");
318 anns[0].sequenceRef = seqs[0];
319 anns[0].visible = true;
320 anns[0].graph = AlignmentAnnotation.LINE_GRAPH;
321 anns[0].graphGroup = GROUP_4;
322 anns[0].label = "Label5";
323 anns[0].setCalcId("CalcId1");
326 * Annotations outwith selection group - should be ignored.
328 // Hidden grouped annotations
329 anns[6].sequenceRef = seqs[2];
330 anns[6].visible = false;
331 anns[6].graph = AlignmentAnnotation.LINE_GRAPH;
332 anns[6].graphGroup = GROUP_4;
333 anns[8].sequenceRef = seqs[1];
334 anns[8].visible = false;
335 anns[8].graph = AlignmentAnnotation.LINE_GRAPH;
336 anns[8].graphGroup = GROUP_4;
338 // visible grouped annotations Label7, Label9
339 anns[7].sequenceRef = seqs[2];
340 anns[7].visible = true;
341 anns[7].graph = AlignmentAnnotation.LINE_GRAPH;
342 anns[7].graphGroup = GROUP_4;
343 anns[9].sequenceRef = seqs[1];
344 anns[9].visible = true;
345 anns[9].graph = AlignmentAnnotation.LINE_GRAPH;
346 anns[9].graphGroup = GROUP_4;
349 * Generate annotations[] arrays to match aligned columns
351 // adjustForAlignment(anns);
353 List<SequenceI> selected = selectSequences(0, 3);
354 AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes,
355 AlignmentAnnotationUtils.asList(anns), selected);
357 consoleDebug(shownTypes, hiddenTypes);
359 // CalcId1 / Label1, Label5 (only) should be 'shown', once, as a compound
361 assertEquals(1, shownTypes.size());
362 assertEquals(1, shownTypes.get("CalcId1").size());
363 assertEquals(2, shownTypes.get("CalcId1").get(0).size());
364 assertEquals("Label1", shownTypes.get("CalcId1").get(0).get(0));
365 assertEquals("Label5", shownTypes.get("CalcId1").get(0).get(1));
367 // CalcId2 / Label2, Label3 (only) should be 'hidden'
368 assertEquals(1, hiddenTypes.size());
369 assertEquals(1, hiddenTypes.get("CalcId2").size());
370 assertEquals(2, hiddenTypes.get("CalcId2").get(0).size());
371 assertEquals("Label2", hiddenTypes.get("CalcId2").get(0).get(0));
372 assertEquals("Label3", hiddenTypes.get("CalcId2").get(0).get(1));
376 * Test method that determines visible graph groups.
378 @Test(groups = { "Functional" })
379 public void testGetVisibleGraphGroups()
381 AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation();
383 * a bar graph group is not included
385 anns[0].graph = AlignmentAnnotation.BAR_GRAPH;
386 anns[0].graphGroup = 1;
387 anns[0].visible = true;
390 * a line graph group is included as long as one of its members is visible
392 anns[1].graph = AlignmentAnnotation.LINE_GRAPH;
393 anns[1].graphGroup = 5;
394 anns[1].visible = false;
395 anns[2].graph = AlignmentAnnotation.LINE_GRAPH;
396 anns[2].graphGroup = 5;
397 anns[2].visible = true;
400 * a line graph group with no visible rows is not included
402 anns[3].graph = AlignmentAnnotation.LINE_GRAPH;
403 anns[3].graphGroup = 3;
404 anns[3].visible = false;
406 // a visible line graph with no graph group is not included
407 anns[4].graph = AlignmentAnnotation.LINE_GRAPH;
408 anns[4].graphGroup = -1;
409 anns[4].visible = true;
411 BitSet result = AlignmentAnnotationUtils
412 .getVisibleLineGraphGroups(AlignmentAnnotationUtils
414 assertTrue(result.get(5));
415 assertFalse(result.get(0));
416 assertFalse(result.get(1));
417 assertFalse(result.get(2));
418 assertFalse(result.get(3));
422 * Test for case where no sequence is selected. Shouldn't normally arise but
423 * check it handles it gracefully.
425 @Test(groups = { "Functional" })
426 public void testGetShownHiddenTypes_noSequenceSelected()
428 Map<String, List<List<String>>> shownTypes = new HashMap<String, List<List<String>>>();
429 Map<String, List<List<String>>> hiddenTypes = new HashMap<String, List<List<String>>>();
430 AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation();
431 // selected sequences null
432 AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes,
433 AlignmentAnnotationUtils.asList(anns), null);
434 assertTrue(shownTypes.isEmpty());
435 assertTrue(hiddenTypes.isEmpty());
437 List<SequenceI> sequences = new ArrayList<SequenceI>();
438 // selected sequences empty list
439 AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes,
440 AlignmentAnnotationUtils.asList(anns), sequences);
441 assertTrue(shownTypes.isEmpty());
442 assertTrue(hiddenTypes.isEmpty());