1. Project Clover database Fri Dec 6 2024 13:47:14 GMT
  2. Package jalview.analysis

File AlignmentAnnotationUtils.java

 

Coverage histogram

../../img/srcFileCovDistChart9.png
12% of files have more coverage

Code metrics

46
66
4
1
322
184
40
0.61
16.5
4
10

Classes

Class
Line #
Actions
AlignmentAnnotationUtils 38 66 40
0.810344881%
 

Contributing tests

This file is covered by 13 tests. .

Source view

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.SequenceGroup;
25    import jalview.datamodel.SequenceI;
26    import jalview.renderer.AnnotationRenderer;
27    import jalview.util.Constants;
28   
29    import java.util.ArrayList;
30    import java.util.Arrays;
31    import java.util.BitSet;
32    import java.util.Collections;
33    import java.util.HashMap;
34    import java.util.List;
35    import java.util.Map;
36    import java.util.Optional;
37   
 
38    public class AlignmentAnnotationUtils
39    {
40   
41    /**
42    * Helper method to populate lists of annotation types for the Show/Hide
43    * Annotations menus. If sequenceGroup is not null, this is restricted to
44    * annotations which are associated with sequences in the selection group.
45    * <p/>
46    * If an annotation row is currently visible, its type (label) is added (once
47    * only per type), to the shownTypes list. If it is currently hidden, it is
48    * added to the hiddenTypesList.
49    * <p/>
50    * For rows that belong to a line graph group, so are always rendered
51    * together:
52    * <ul>
53    * <li>Treat all rows in the group as visible, if at least one of them is</li>
54    * <li>Build a list of all the annotation types that belong to the group</li>
55    * </ul>
56    *
57    * @param shownTypes
58    * a map, keyed by calcId (annotation source), whose entries are the
59    * lists of annotation types found for the calcId; each annotation
60    * type in turn may be a list (in the case of grouped annotations)
61    * @param hiddenTypes
62    * a map, similar to shownTypes, but for hidden annotation types
63    * @param annotations
64    * the annotations on the alignment to scan
65    * @param forSequences
66    * the sequences to restrict search to
67    */
 
68  47 toggle public static void getShownHiddenTypes(
69    Map<String, List<List<String>>> shownTypes,
70    Map<String, List<List<String>>> hiddenTypes,
71    List<AlignmentAnnotation> annotations,
72    List<SequenceI> forSequences)
73    {
74  47 BitSet visibleGraphGroups = AlignmentAnnotationUtils
75    .getVisibleLineGraphGroups(annotations);
76   
77    /*
78    * Build a lookup, by calcId (annotation source), of all annotation types in
79    * each graph group.
80    */
81  47 Map<String, Map<Integer, List<String>>> groupLabels = new HashMap<String, Map<Integer, List<String>>>();
82   
83    // trackers for which calcId!label combinations we have dealt with
84  47 List<String> addedToShown = new ArrayList<String>();
85  47 List<String> addedToHidden = new ArrayList<String>();
86   
87  47 for (AlignmentAnnotation aa : annotations)
88    {
89    /*
90    * Ignore non-positional annotations, can't render these against an
91    * alignment
92    */
93  224 if (aa.annotations == null)
94    {
95  0 continue;
96    }
97  224 if (forSequences != null && (aa.sequenceRef != null
98    && forSequences.contains(aa.sequenceRef)))
99    {
100  22 String calcId = aa.getCalcId();
101   
102    /*
103    * Build a 'composite label' for types in line graph groups.
104    */
105  22 final List<String> labelAsList = new ArrayList<String>();
106  22 final String displayLabel = aa.label;
107  22 labelAsList.add(displayLabel);
108  22 if (aa.graph == AlignmentAnnotation.LINE_GRAPH
109    && aa.graphGroup > -1)
110    {
111  8 if (!groupLabels.containsKey(calcId))
112    {
113  2 groupLabels.put(calcId, new HashMap<Integer, List<String>>());
114    }
115  8 Map<Integer, List<String>> groupLabelsForCalcId = groupLabels
116    .get(calcId);
117  8 if (groupLabelsForCalcId.containsKey(aa.graphGroup))
118    {
119  4 if (!groupLabelsForCalcId.get(aa.graphGroup)
120    .contains(displayLabel))
121    {
122  4 groupLabelsForCalcId.get(aa.graphGroup).add(displayLabel);
123    }
124    }
125    else
126    {
127  4 groupLabelsForCalcId.put(aa.graphGroup, labelAsList);
128    }
129    }
130    else
131    /*
132    * 'Simple case' - not a grouped annotation type - list of one label
133    * only
134    */
135    {
136  14 String rememberAs = calcId + "!" + displayLabel;
137  14 if (aa.visible && !addedToShown.contains(rememberAs))
138    {
139  6 if (!shownTypes.containsKey(calcId))
140    {
141  4 shownTypes.put(calcId, new ArrayList<List<String>>());
142    }
143  6 shownTypes.get(calcId).add(labelAsList);
144  6 addedToShown.add(rememberAs);
145    }
146    else
147    {
148  8 if (!aa.visible && !addedToHidden.contains(rememberAs))
149    {
150  8 if (!hiddenTypes.containsKey(calcId))
151    {
152  7 hiddenTypes.put(calcId, new ArrayList<List<String>>());
153    }
154  8 hiddenTypes.get(calcId).add(labelAsList);
155  8 addedToHidden.add(rememberAs);
156    }
157    }
158    }
159    }
160    }
161    /*
162    * Finally add the 'composite group labels' to the appropriate lists,
163    * depending on whether the group is identified as visible or hidden. Don't
164    * add the same label more than once (there may be many graph groups that
165    * generate it).
166    */
167  47 for (String calcId : groupLabels.keySet())
168    {
169  2 for (int group : groupLabels.get(calcId).keySet())
170    {
171  4 final List<String> groupLabel = groupLabels.get(calcId).get(group);
172    // don't want to duplicate 'same types in different order'
173  4 Collections.sort(groupLabel);
174  4 if (visibleGraphGroups.get(group))
175    {
176  2 if (!shownTypes.containsKey(calcId))
177    {
178  1 shownTypes.put(calcId, new ArrayList<List<String>>());
179    }
180  2 if (!shownTypes.get(calcId).contains(groupLabel))
181    {
182  1 shownTypes.get(calcId).add(groupLabel);
183    }
184    }
185    else
186    {
187  2 if (!hiddenTypes.containsKey(calcId))
188    {
189  1 hiddenTypes.put(calcId, new ArrayList<List<String>>());
190    }
191  2 if (!hiddenTypes.get(calcId).contains(groupLabel))
192    {
193  1 hiddenTypes.get(calcId).add(groupLabel);
194    }
195    }
196    }
197    }
198    }
199   
200    /**
201    * Updates the lists of shown and hidden secondary structure types based on
202    * the selected sequence group.
203    *
204    * @param shownTypes
205    * A list that will be populated with the providers of secondary
206    * structures that are shown.
207    * @param hiddenTypes
208    * A list that will be populated with the providers of secondary
209    * structures that are hidden.
210    * @param annotations
211    * A list of AlignmentAnnotation objects.
212    * @param selectedSequenceGroup
213    * The sequence group selected by the user.
214    */
 
215  4 toggle public static void getShownHiddenSecondaryStructureProvidersForGroup(
216    List<String> shownTypes, List<String> hiddenTypes,
217    List<AlignmentAnnotation> annotations,
218    SequenceGroup selectedSequenceGroup)
219    {
220    // Return if the selected sequence group or annotations are null
221  4 if (selectedSequenceGroup == null || annotations == null)
222    {
223  0 return;
224    }
225   
226    // Get the secondary structure sources of the selected sequence group
227  4 List<String> ssSourcesForSelectedGroup = selectedSequenceGroup
228    .getSecondaryStructureSources();
229   
230    // Return if there are no secondary structure sources for the selected group
231  4 if (ssSourcesForSelectedGroup == null
232    || ssSourcesForSelectedGroup.isEmpty())
233    {
234  4 return;
235    }
236   
237    // Iterate through each annotation
238  0 for (AlignmentAnnotation aa : annotations)
239    {
240    /* Skip to the next annotation if the annotation, the annotation's group
241    * reference is null, or the annotation's group reference does not match
242    * the selected group
243    */
244  0 if (aa.annotations == null || aa.groupRef == null
245    || selectedSequenceGroup != aa.groupRef
246    || !aa.label.startsWith(
247    Constants.SECONDARY_STRUCTURE_CONSENSUS_LABEL))
248    {
249  0 continue;
250    }
251   
252    /* Find a provider from the secondary structure sources that matches
253    * the annotation's label. This is to exclude secondary structure
254    * providers which has no secondary structure data for the selected group.
255    */
256  0 Optional<String> provider = ssSourcesForSelectedGroup.stream()
257    .filter(aa.label::contains).findFirst()
258    .map(substring -> aa.label.substring(0,
259    aa.label.indexOf(substring) + substring.length()));
260   
261    // If a matching provider is found and the annotation is visible, add
262    // the provider to the shown types list (if not already in shownTypes).
263    // If the annotation is not visible, add it to hiddenTypes list.
264  0 provider.ifPresent(p -> {
265  0 if (aa.visible && !shownTypes.contains(p))
266    {
267  0 shownTypes.add(p);
268    }
269  0 else if (!aa.visible && !shownTypes.contains(p))
270    {
271  0 hiddenTypes.add(p);
272    }
273    });
274    }
275    }
276   
277    /**
278    * Returns a BitSet (possibly empty) of those graphGroups for line graph
279    * annotations, which have at least one member annotation row marked visible.
280    * <p/>
281    * Only one row in each visible group is marked visible, but when it is drawn,
282    * so are all the other rows in the same group.
283    * <p/>
284    * This lookup set allows us to check whether rows apparently marked not
285    * visible are in fact shown.
286    *
287    * @see AnnotationRenderer#drawComponent
288    * @param annotations
289    * @return
290    */
 
291  48 toggle public static BitSet getVisibleLineGraphGroups(
292    List<AlignmentAnnotation> annotations)
293    {
294  48 BitSet result = new BitSet();
295  48 for (AlignmentAnnotation ann : annotations)
296    {
297  236 if (ann.graph == AlignmentAnnotation.LINE_GRAPH && ann.visible)
298    {
299  6 int gg = ann.graphGroup;
300  6 if (gg > -1)
301    {
302  5 result.set(gg);
303    }
304    }
305    }
306  48 return result;
307    }
308   
309    /**
310    * Converts an array of AlignmentAnnotation into a List of
311    * AlignmentAnnotation. A null array is converted to an empty list.
312    *
313    * @param anns
314    * @return
315    */
 
316  55 toggle public static List<AlignmentAnnotation> asList(AlignmentAnnotation[] anns)
317    {
318    // TODO use AlignmentAnnotationI instead when it exists
319  55 return (anns == null ? Collections.<AlignmentAnnotation> emptyList()
320    : Arrays.asList(anns));
321    }
322    }