Clover icon

Coverage Report

  1. Project Clover database Thu Aug 13 2020 12:04:21 BST
  2. Package jalview.datamodel.features

File SequenceFeatures.java

 

Coverage histogram

../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

34
99
24
1
470
281
47
0.47
4.12
24
1.96

Classes

Class Line # Actions
SequenceFeatures 45 99 47
1.0100%
 

Contributing tests

This file is covered by 468 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.datamodel.features;
22   
23    import java.util.ArrayList;
24    import java.util.Collections;
25    import java.util.HashSet;
26    import java.util.List;
27    import java.util.Map;
28    import java.util.Map.Entry;
29    import java.util.Set;
30    import java.util.TreeMap;
31   
32    import intervalstore.api.IntervalI;
33    import jalview.datamodel.SequenceFeature;
34    import jalview.io.gff.SequenceOntologyFactory;
35    import jalview.io.gff.SequenceOntologyI;
36   
37    /**
38    * A class that stores sequence features in a way that supports efficient
39    * querying by type and location (overlap). Intended for (but not limited to)
40    * storage of features for one sequence.
41    *
42    * @author gmcarstairs
43    *
44    */
 
45    public class SequenceFeatures implements SequenceFeaturesI
46    {
47    /*
48    * map from feature type to structured store of features for that type
49    * null types are permitted (but not a good idea!)
50    */
51    private Map<String, FeatureStore> featureStore;
52   
53    /**
54    * Constructor
55    */
 
56  28433 toggle public SequenceFeatures()
57    {
58    /*
59    * use a TreeMap so that features are returned in alphabetical order of type
60    * ? wrap as a synchronized map for add and delete operations
61    */
62    // featureStore = Collections
63    // .synchronizedSortedMap(new TreeMap<String, FeatureStore>());
64  28433 featureStore = new TreeMap<>();
65    }
66   
67    /**
68    * Constructor given a list of features
69    */
 
70  46 toggle public SequenceFeatures(List<SequenceFeature> features)
71    {
72  46 this();
73  46 if (features != null)
74    {
75  43 for (SequenceFeature feature : features)
76    {
77  423 add(feature);
78    }
79    }
80    }
81   
82    /**
83    * {@inheritDoc}
84    */
 
85  174267 toggle @Override
86    public boolean add(SequenceFeature sf)
87    {
88  174267 String type = sf.getType();
89  174267 if (type == null)
90    {
91  2 System.err.println("Feature type may not be null: " + sf.toString());
92  2 return false;
93    }
94   
95  174265 if (featureStore.get(type) == null)
96    {
97  2252 featureStore.put(type, new FeatureStore());
98    }
99  174265 return featureStore.get(type).addFeature(sf);
100    }
101   
102    /**
103    * {@inheritDoc}
104    */
 
105  8804 toggle @Override
106    public List<SequenceFeature> findFeatures(int from, int to,
107    String... type)
108    {
109  8804 List<SequenceFeature> result = new ArrayList<>();
110   
111  8804 for (FeatureStore featureSet : varargToTypes(type))
112    {
113  4132 result.addAll(featureSet.findOverlappingFeatures(from, to));
114    }
115   
116  8804 return result;
117    }
118   
119    /**
120    * {@inheritDoc}
121    */
 
122  5312 toggle @Override
123    public List<SequenceFeature> getAllFeatures(String... type)
124    {
125  5312 List<SequenceFeature> result = new ArrayList<>();
126   
127  5312 result.addAll(getPositionalFeatures(type));
128   
129  5312 result.addAll(getNonPositionalFeatures());
130   
131  5312 return result;
132    }
133   
134    /**
135    * {@inheritDoc}
136    */
 
137  34 toggle @Override
138    public List<SequenceFeature> getFeaturesByOntology(String... ontologyTerm)
139    {
140  34 if (ontologyTerm == null || ontologyTerm.length == 0)
141    {
142  3 return new ArrayList<>();
143    }
144   
145  31 Set<String> featureTypes = getFeatureTypes(ontologyTerm);
146  31 if (featureTypes.isEmpty())
147    {
148    /*
149    * no features of the specified type or any sub-type
150    */
151  7 return new ArrayList<>();
152    }
153   
154  24 return getAllFeatures(featureTypes.toArray(new String[featureTypes
155    .size()]));
156    }
157   
158    /**
159    * {@inheritDoc}
160    */
 
161  35 toggle @Override
162    public int getFeatureCount(boolean positional, String... type)
163    {
164  35 int result = 0;
165   
166  35 for (FeatureStore featureSet : varargToTypes(type))
167    {
168  55 result += featureSet.getFeatureCount(positional);
169    }
170  35 return result;
171    }
172   
173    /**
174    * {@inheritDoc}
175    */
 
176  22 toggle @Override
177    public int getTotalFeatureLength(String... type)
178    {
179  22 int result = 0;
180   
181  22 for (FeatureStore featureSet : varargToTypes(type))
182    {
183  33 result += featureSet.getTotalFeatureLength();
184    }
185  22 return result;
186    }
187   
188    /**
189    * {@inheritDoc}
190    */
 
191  5450 toggle @Override
192    public List<SequenceFeature> getPositionalFeatures(String... type)
193    {
194  5450 List<SequenceFeature> result = new ArrayList<>();
195   
196  5450 for (FeatureStore featureSet : varargToTypes(type))
197    {
198  3541 result.addAll(featureSet.getPositionalFeatures());
199    }
200  5450 return result;
201    }
202   
203    /**
204    * A convenience method that converts a vararg for feature types to an
205    * Iterable over matched feature sets. If no types are specified, all feature
206    * sets are returned. If one or more types are specified, feature sets for
207    * those types are returned, preserving the order of the types.
208    *
209    * @param type
210    * @return
211    */
 
212  20547 toggle protected Iterable<FeatureStore> varargToTypes(String... type)
213    {
214  20547 if (type == null || type.length == 0)
215    {
216    /*
217    * no vararg parameter supplied - return all
218    */
219  11209 return featureStore.values();
220    }
221   
222  9338 List<FeatureStore> types = new ArrayList<>();
223  9338 for (String theType : type)
224    {
225  9852 if (theType != null && featureStore.containsKey(theType))
226    {
227  4242 types.add(featureStore.get(theType));
228    }
229    }
230  9338 return types;
231    }
232   
233    /**
234    * {@inheritDoc}
235    */
 
236  25 toggle @Override
237    public List<SequenceFeature> getContactFeatures(String... type)
238    {
239  25 List<SequenceFeature> result = new ArrayList<>();
240   
241  25 for (FeatureStore featureSet : varargToTypes(type))
242    {
243  19 result.addAll(featureSet.getContactFeatures());
244    }
245  25 return result;
246    }
247   
248    /**
249    * {@inheritDoc}
250    */
 
251  5378 toggle @Override
252    public List<SequenceFeature> getNonPositionalFeatures(String... type)
253    {
254  5378 List<SequenceFeature> result = new ArrayList<>();
255   
256  5378 for (FeatureStore featureSet : varargToTypes(type))
257    {
258  3545 result.addAll(featureSet.getNonPositionalFeatures());
259    }
260  5378 return result;
261    }
262   
263    /**
264    * {@inheritDoc}
265    */
 
266  225 toggle @Override
267    public boolean delete(SequenceFeature sf)
268    {
269  225 for (FeatureStore featureSet : featureStore.values())
270    {
271  317 if (featureSet.delete(sf))
272    {
273  223 return true;
274    }
275    }
276  2 return false;
277    }
278   
279    /**
280    * {@inheritDoc}
281    */
 
282  1038 toggle @Override
283    public boolean hasFeatures()
284    {
285  1038 for (FeatureStore featureSet : featureStore.values())
286    {
287  1035 if (!featureSet.isEmpty())
288    {
289  1027 return true;
290    }
291    }
292  11 return false;
293    }
294   
295    /**
296    * {@inheritDoc}
297    */
 
298  328 toggle @Override
299    public Set<String> getFeatureGroups(boolean positionalFeatures,
300    String... type)
301    {
302  328 Set<String> groups = new HashSet<>();
303   
304  328 for (FeatureStore featureSet : varargToTypes(type))
305    {
306  772 groups.addAll(featureSet.getFeatureGroups(positionalFeatures));
307    }
308   
309  328 return groups;
310    }
311   
312    /**
313    * {@inheritDoc}
314    */
 
315  491 toggle @Override
316    public Set<String> getFeatureTypesForGroups(boolean positionalFeatures,
317    String... groups)
318    {
319  491 Set<String> result = new HashSet<>();
320   
321  491 for (Entry<String, FeatureStore> featureType : featureStore.entrySet())
322    {
323  1386 Set<String> featureGroups = featureType.getValue().getFeatureGroups(
324    positionalFeatures);
325  1386 for (String group : groups)
326    {
327  1390 if (featureGroups.contains(group))
328    {
329    /*
330    * yes this feature type includes one of the query groups
331    */
332  720 result.add(featureType.getKey());
333  720 break;
334    }
335    }
336    }
337   
338  491 return result;
339    }
340   
341    /**
342    * {@inheritDoc}
343    */
 
344  42 toggle @Override
345    public Set<String> getFeatureTypes(String... soTerm)
346    {
347  42 Set<String> types = new HashSet<>();
348  42 for (Entry<String, FeatureStore> entry : featureStore.entrySet())
349    {
350  88 String type = entry.getKey();
351  88 if (!entry.getValue().isEmpty() && isOntologyTerm(type, soTerm))
352    {
353  60 types.add(type);
354    }
355    }
356  42 return types;
357    }
358   
359    /**
360    * Answers true if the given type matches one of the specified terms (or is a
361    * sub-type of one in the Sequence Ontology), or if no terms are supplied.
362    * Answers false if filter terms are specified and the given term does not
363    * match any of them.
364    *
365    * @param type
366    * @param soTerm
367    * @return
368    */
 
369  94 toggle protected boolean isOntologyTerm(String type, String... soTerm)
370    {
371  94 if (soTerm == null || soTerm.length == 0)
372    {
373  18 return true;
374    }
375  76 SequenceOntologyI so = SequenceOntologyFactory.getInstance();
376  76 for (String term : soTerm)
377    {
378  85 if (type.equals(term) || so.isA(type, term))
379    {
380  48 return true;
381    }
382    }
383  28 return false;
384    }
385   
386    /**
387    * {@inheritDoc}
388    */
 
389  710 toggle @Override
390    public float getMinimumScore(String type, boolean positional)
391    {
392  710 return featureStore.containsKey(type) ? featureStore.get(type)
393    .getMinimumScore(positional) : Float.NaN;
394    }
395   
396    /**
397    * {@inheritDoc}
398    */
 
399  684 toggle @Override
400    public float getMaximumScore(String type, boolean positional)
401    {
402  684 return featureStore.containsKey(type) ? featureStore.get(type)
403    .getMaximumScore(positional) : Float.NaN;
404    }
405   
406    /**
407    * A convenience method to sort features by start position ascending (if on
408    * forward strand), or end position descending (if on reverse strand)
409    *
410    * @param features
411    * @param forwardStrand
412    */
 
413  2066 toggle public static void sortFeatures(List<? extends IntervalI> features,
414    final boolean forwardStrand)
415    {
416  2066 Collections.sort(features,
417  2066 forwardStrand
418    ? IntervalI.COMPARE_BEGIN_ASC_END_DESC
419    : IntervalI.COMPARE_END_DESC);
420    }
421   
422    /**
423    * {@inheritDoc} This method is 'semi-optimised': it only inspects features
424    * for types that include the specified group, but has to inspect every
425    * feature of those types for matching feature group. This is efficient unless
426    * a sequence has features that share the same type but are in different
427    * groups - an unlikely case.
428    * <p>
429    * For example, if RESNUM feature is created with group = PDBID, then features
430    * would only be retrieved for those sequences associated with the target
431    * PDBID (group).
432    */
 
433  498 toggle @Override
434    public List<SequenceFeature> getFeaturesForGroup(boolean positional,
435    String group, String... type)
436    {
437  498 List<SequenceFeature> result = new ArrayList<>();
438  498 for (FeatureStore featureSet : varargToTypes(type))
439    {
440  122 if (featureSet.getFeatureGroups(positional).contains(group))
441    {
442  36 result.addAll(featureSet.getFeaturesForGroup(positional, group));
443    }
444    }
445  498 return result;
446    }
447   
448    /**
449    * {@inheritDoc}
450    */
 
451  39 toggle @Override
452    public boolean shiftFeatures(int fromPosition, int shiftBy)
453    {
454  39 boolean modified = false;
455  39 for (FeatureStore fs : featureStore.values())
456    {
457  40 modified |= fs.shiftFeatures(fromPosition, shiftBy);
458    }
459  39 return modified;
460    }
461   
462    /**
463    * {@inheritDoc}
464    */
 
465  2 toggle @Override
466    public void deleteAll()
467    {
468  2 featureStore.clear();
469    }
470    }