Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package jalview.datamodel.features

File SequenceFeatures.java

 

Coverage histogram

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

Code metrics

34
101
25
1
483
292
46
0.46
4.04
25
1.84

Classes

Class Line # Actions
SequenceFeatures 47 101 46 0
1.0100%
 

Contributing tests

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