1 package jalview.analysis;
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.BitSet;
6 import java.util.Collections;
7 import java.util.HashMap;
11 import jalview.datamodel.AlignmentAnnotation;
12 import jalview.datamodel.SequenceI;
13 import jalview.renderer.AnnotationRenderer;
15 public class AlignmentAnnotationUtils
19 * Helper method to populate lists of annotation types for the Show/Hide
20 * Annotations menus. If sequenceGroup is not null, this is restricted to
21 * annotations which are associated with sequences in the selection group.
23 * If an annotation row is currently visible, its type (label) is added (once
24 * only per type), to the shownTypes list. If it is currently hidden, it is
25 * added to the hiddenTypesList.
27 * For rows that belong to a line graph group, so are always rendered
30 * <li>Treat all rows in the group as visible, if at least one of them is</li>
31 * <li>Build a list of all the annotation types that belong to the group</li>
35 * a map, keyed by calcId (annotation source), whose entries are the
36 * lists of annotation types found for the calcId; each annotation
37 * type in turn may be a list (in the case of grouped annotations)
39 * a map, similar to shownTypes, but for hidden annotation types
41 * the annotations on the alignment to scan
43 * the sequences to restrict search to
45 public static void getShownHiddenTypes(
46 Map<String, List<List<String>>> shownTypes,
47 Map<String, List<List<String>>> hiddenTypes,
48 List<AlignmentAnnotation> annotations,
49 List<SequenceI> forSequences)
51 BitSet visibleGraphGroups = AlignmentAnnotationUtils
52 .getVisibleLineGraphGroups(annotations);
55 * Build a lookup, by calcId (annotation source), of all annotation types in
58 Map<String, Map<Integer, List<String>>> groupLabels = new HashMap<String, Map<Integer, List<String>>>();
60 // trackers for which calcId!label combinations we have dealt with
61 List<String> addedToShown = new ArrayList<String>();
62 List<String> addedToHidden = new ArrayList<String>();
64 for (AlignmentAnnotation aa : annotations)
67 * Ignore non-positional annotations, can't render these against an
70 if (aa.annotations == null)
74 if (forSequences != null
75 && (aa.sequenceRef != null && forSequences
76 .contains(aa.sequenceRef)))
78 String calcId = aa.getCalcId();
81 * Build a 'composite label' for types in line graph groups.
83 final List<String> labelAsList = new ArrayList<String>();
84 final String displayLabel = aa.label;
85 labelAsList.add(displayLabel);
86 if (aa.graph == AlignmentAnnotation.LINE_GRAPH
87 && aa.graphGroup > -1)
89 if (!groupLabels.containsKey(calcId))
91 groupLabels.put(calcId, new HashMap<Integer, List<String>>());
93 Map<Integer, List<String>> groupLabelsForCalcId = groupLabels
95 if (groupLabelsForCalcId.containsKey(aa.graphGroup))
97 if (!groupLabelsForCalcId.get(aa.graphGroup).contains(
100 groupLabelsForCalcId.get(aa.graphGroup).add(displayLabel);
105 groupLabelsForCalcId.put(aa.graphGroup, labelAsList);
110 * 'Simple case' - not a grouped annotation type - list of one label
114 String rememberAs = calcId + "!" + displayLabel;
115 if (aa.visible && !addedToShown.contains(rememberAs))
117 if (!shownTypes.containsKey(calcId))
119 shownTypes.put(calcId, new ArrayList<List<String>>());
121 shownTypes.get(calcId).add(labelAsList);
122 addedToShown.add(rememberAs);
126 if (!aa.visible && !addedToHidden.contains(rememberAs))
128 if (!hiddenTypes.containsKey(calcId))
130 hiddenTypes.put(calcId, new ArrayList<List<String>>());
132 hiddenTypes.get(calcId).add(labelAsList);
133 addedToHidden.add(rememberAs);
140 * Finally add the 'composite group labels' to the appropriate lists,
141 * depending on whether the group is identified as visible or hidden. Don't
142 * add the same label more than once (there may be many graph groups that
145 for (String calcId : groupLabels.keySet())
147 for (int group : groupLabels.get(calcId).keySet())
149 final List<String> groupLabel = groupLabels.get(calcId).get(group);
150 // don't want to duplicate 'same types in different order'
151 Collections.sort(groupLabel);
152 if (visibleGraphGroups.get(group))
154 if (!shownTypes.containsKey(calcId))
156 shownTypes.put(calcId, new ArrayList<List<String>>());
158 if (!shownTypes.get(calcId).contains(groupLabel))
160 shownTypes.get(calcId).add(groupLabel);
165 if (!hiddenTypes.containsKey(calcId))
167 hiddenTypes.put(calcId, new ArrayList<List<String>>());
169 if (!hiddenTypes.get(calcId).contains(groupLabel))
171 hiddenTypes.get(calcId).add(groupLabel);
179 * Returns a BitSet (possibly empty) of those graphGroups for line graph
180 * annotations, which have at least one member annotation row marked visible.
182 * Only one row in each visible group is marked visible, but when it is drawn,
183 * so are all the other rows in the same group.
185 * This lookup set allows us to check whether rows apparently marked not
186 * visible are in fact shown.
188 * @see AnnotationRenderer#drawComponent
192 public static BitSet getVisibleLineGraphGroups(
193 List<AlignmentAnnotation> annotations)
195 BitSet result = new BitSet();
196 for (AlignmentAnnotation ann : annotations)
198 if (ann.graph == AlignmentAnnotation.LINE_GRAPH && ann.visible)
200 int gg = ann.graphGroup;
211 * Converts an array of AlignmentAnnotation into a List of
212 * AlignmentAnnotation. A null array is converted to an empty list.
217 public static List<AlignmentAnnotation> asList(AlignmentAnnotation[] anns)
219 // TODO use AlignmentAnnotationI instead when it exists
220 return (anns == null ? Collections.<AlignmentAnnotation> emptyList()
221 : Arrays.asList(anns));