Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
AlignmentAnnotationUtils | 35 | 52 | 27 |
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.analysis; | |
22 | ||
23 | import jalview.datamodel.AlignmentAnnotation; | |
24 | import jalview.datamodel.SequenceI; | |
25 | import jalview.renderer.AnnotationRenderer; | |
26 | ||
27 | import java.util.ArrayList; | |
28 | import java.util.Arrays; | |
29 | import java.util.BitSet; | |
30 | import java.util.Collections; | |
31 | import java.util.HashMap; | |
32 | import java.util.List; | |
33 | import java.util.Map; | |
34 | ||
35 | public class AlignmentAnnotationUtils | |
36 | { | |
37 | ||
38 | /** | |
39 | * Helper method to populate lists of annotation types for the Show/Hide | |
40 | * Annotations menus. If sequenceGroup is not null, this is restricted to | |
41 | * annotations which are associated with sequences in the selection group. | |
42 | * <p/> | |
43 | * If an annotation row is currently visible, its type (label) is added (once | |
44 | * only per type), to the shownTypes list. If it is currently hidden, it is | |
45 | * added to the hiddenTypesList. | |
46 | * <p/> | |
47 | * For rows that belong to a line graph group, so are always rendered | |
48 | * together: | |
49 | * <ul> | |
50 | * <li>Treat all rows in the group as visible, if at least one of them is</li> | |
51 | * <li>Build a list of all the annotation types that belong to the group</li> | |
52 | * </ul> | |
53 | * | |
54 | * @param shownTypes | |
55 | * a map, keyed by calcId (annotation source), whose entries are the | |
56 | * lists of annotation types found for the calcId; each annotation | |
57 | * type in turn may be a list (in the case of grouped annotations) | |
58 | * @param hiddenTypes | |
59 | * a map, similar to shownTypes, but for hidden annotation types | |
60 | * @param annotations | |
61 | * the annotations on the alignment to scan | |
62 | * @param forSequences | |
63 | * the sequences to restrict search to | |
64 | */ | |
65 | 47 | public static void getShownHiddenTypes( |
66 | Map<String, List<List<String>>> shownTypes, | |
67 | Map<String, List<List<String>>> hiddenTypes, | |
68 | List<AlignmentAnnotation> annotations, | |
69 | List<SequenceI> forSequences) | |
70 | { | |
71 | 47 | BitSet visibleGraphGroups = AlignmentAnnotationUtils |
72 | .getVisibleLineGraphGroups(annotations); | |
73 | ||
74 | /* | |
75 | * Build a lookup, by calcId (annotation source), of all annotation types in | |
76 | * each graph group. | |
77 | */ | |
78 | 47 | Map<String, Map<Integer, List<String>>> groupLabels = new HashMap<String, Map<Integer, List<String>>>(); |
79 | ||
80 | // trackers for which calcId!label combinations we have dealt with | |
81 | 47 | List<String> addedToShown = new ArrayList<String>(); |
82 | 47 | List<String> addedToHidden = new ArrayList<String>(); |
83 | ||
84 | 47 | for (AlignmentAnnotation aa : annotations) |
85 | { | |
86 | /* | |
87 | * Ignore non-positional annotations, can't render these against an | |
88 | * alignment | |
89 | */ | |
90 | 224 | if (aa.annotations == null) |
91 | { | |
92 | 0 | continue; |
93 | } | |
94 | 224 | if (forSequences != null && (aa.sequenceRef != null |
95 | && forSequences.contains(aa.sequenceRef))) | |
96 | { | |
97 | 22 | String calcId = aa.getCalcId(); |
98 | ||
99 | /* | |
100 | * Build a 'composite label' for types in line graph groups. | |
101 | */ | |
102 | 22 | final List<String> labelAsList = new ArrayList<String>(); |
103 | 22 | final String displayLabel = aa.label; |
104 | 22 | labelAsList.add(displayLabel); |
105 | 22 | if (aa.graph == AlignmentAnnotation.LINE_GRAPH |
106 | && aa.graphGroup > -1) | |
107 | { | |
108 | 8 | if (!groupLabels.containsKey(calcId)) |
109 | { | |
110 | 2 | groupLabels.put(calcId, new HashMap<Integer, List<String>>()); |
111 | } | |
112 | 8 | Map<Integer, List<String>> groupLabelsForCalcId = groupLabels |
113 | .get(calcId); | |
114 | 8 | if (groupLabelsForCalcId.containsKey(aa.graphGroup)) |
115 | { | |
116 | 4 | if (!groupLabelsForCalcId.get(aa.graphGroup) |
117 | .contains(displayLabel)) | |
118 | { | |
119 | 4 | groupLabelsForCalcId.get(aa.graphGroup).add(displayLabel); |
120 | } | |
121 | } | |
122 | else | |
123 | { | |
124 | 4 | groupLabelsForCalcId.put(aa.graphGroup, labelAsList); |
125 | } | |
126 | } | |
127 | else | |
128 | /* | |
129 | * 'Simple case' - not a grouped annotation type - list of one label | |
130 | * only | |
131 | */ | |
132 | { | |
133 | 14 | String rememberAs = calcId + "!" + displayLabel; |
134 | 14 | if (aa.isForDisplay() && !addedToShown.contains(rememberAs)) // exclude noData annotations |
135 | { | |
136 | 6 | if (!shownTypes.containsKey(calcId)) |
137 | { | |
138 | 4 | shownTypes.put(calcId, new ArrayList<List<String>>()); |
139 | } | |
140 | 6 | shownTypes.get(calcId).add(labelAsList); |
141 | 6 | addedToShown.add(rememberAs); |
142 | } | |
143 | else | |
144 | { | |
145 | 8 | if (!aa.visible && !addedToHidden.contains(rememberAs)) |
146 | { | |
147 | 8 | if (!hiddenTypes.containsKey(calcId)) |
148 | { | |
149 | 7 | hiddenTypes.put(calcId, new ArrayList<List<String>>()); |
150 | } | |
151 | 8 | hiddenTypes.get(calcId).add(labelAsList); |
152 | 8 | addedToHidden.add(rememberAs); |
153 | } | |
154 | } | |
155 | } | |
156 | } | |
157 | } | |
158 | /* | |
159 | * Finally add the 'composite group labels' to the appropriate lists, | |
160 | * depending on whether the group is identified as visible or hidden. Don't | |
161 | * add the same label more than once (there may be many graph groups that | |
162 | * generate it). | |
163 | */ | |
164 | 47 | for (String calcId : groupLabels.keySet()) |
165 | { | |
166 | 2 | for (int group : groupLabels.get(calcId).keySet()) |
167 | { | |
168 | 4 | final List<String> groupLabel = groupLabels.get(calcId).get(group); |
169 | // don't want to duplicate 'same types in different order' | |
170 | 4 | Collections.sort(groupLabel); |
171 | 4 | if (visibleGraphGroups.get(group)) |
172 | { | |
173 | 2 | if (!shownTypes.containsKey(calcId)) |
174 | { | |
175 | 1 | shownTypes.put(calcId, new ArrayList<List<String>>()); |
176 | } | |
177 | 2 | if (!shownTypes.get(calcId).contains(groupLabel)) |
178 | { | |
179 | 1 | shownTypes.get(calcId).add(groupLabel); |
180 | } | |
181 | } | |
182 | else | |
183 | { | |
184 | 2 | if (!hiddenTypes.containsKey(calcId)) |
185 | { | |
186 | 1 | hiddenTypes.put(calcId, new ArrayList<List<String>>()); |
187 | } | |
188 | 2 | if (!hiddenTypes.get(calcId).contains(groupLabel)) |
189 | { | |
190 | 1 | hiddenTypes.get(calcId).add(groupLabel); |
191 | } | |
192 | } | |
193 | } | |
194 | } | |
195 | } | |
196 | ||
197 | /** | |
198 | * Returns a BitSet (possibly empty) of those graphGroups for line graph | |
199 | * annotations, which have at least one member annotation row marked visible. | |
200 | * <p/> | |
201 | * Only one row in each visible group is marked visible, but when it is drawn, | |
202 | * so are all the other rows in the same group. | |
203 | * <p/> | |
204 | * This lookup set allows us to check whether rows apparently marked not | |
205 | * visible are in fact shown. | |
206 | * | |
207 | * @see AnnotationRenderer#drawComponent | |
208 | * @param annotations | |
209 | * @return | |
210 | */ | |
211 | 48 | public static BitSet getVisibleLineGraphGroups( |
212 | List<AlignmentAnnotation> annotations) | |
213 | { | |
214 | 48 | BitSet result = new BitSet(); |
215 | 48 | for (AlignmentAnnotation ann : annotations) |
216 | { | |
217 | 236 | if (ann.graph == AlignmentAnnotation.LINE_GRAPH && ann.visible) |
218 | { | |
219 | 6 | int gg = ann.graphGroup; |
220 | 6 | if (gg > -1) |
221 | { | |
222 | 5 | result.set(gg); |
223 | } | |
224 | } | |
225 | } | |
226 | 48 | return result; |
227 | } | |
228 | ||
229 | /** | |
230 | * Converts an array of AlignmentAnnotation into a List of | |
231 | * AlignmentAnnotation. A null array is converted to an empty list. | |
232 | * | |
233 | * @param anns | |
234 | * @return | |
235 | */ | |
236 | 51 | public static List<AlignmentAnnotation> asList(AlignmentAnnotation[] anns) |
237 | { | |
238 | // TODO use AlignmentAnnotationI instead when it exists | |
239 | 51 | return (anns == null ? Collections.<AlignmentAnnotation> emptyList() |
240 | : Arrays.asList(anns)); | |
241 | } | |
242 | } |