JAL-3010 relocated ontology search method to OntologyBase
[jalview.git] / src / jalview / datamodel / ontology / OntologyBase.java
index 8bdebbd..22dc37e 100644 (file)
@@ -1,6 +1,10 @@
 package jalview.datamodel.ontology;
 
+import jalview.io.gff.SequenceOntologyFactory;
+import jalview.io.gff.SequenceOntologyI;
+
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -74,4 +78,59 @@ public abstract class OntologyBase implements OntologyI
     }
     return children;
   }
+
+  /**
+   * Answers a (possibly empty) map of any Ontology terms (from the given term
+   * and its parents) which subsume one or more of the target terms. The map key
+   * is an ontology term, and the entry is the list of target terms that are
+   * sub-terms of the key.
+   * <p>
+   * For example if {@code stop_gained} and {@code stop_lost} are known feature
+   * types, then SO term {@ nonsynonymous_variant} is the first common parent of
+   * both terms
+   * 
+   * @param givenTerm
+   *          the term to search from
+   * @param targetTerms
+   *          candidate terms to 'capture' in ontology groupings
+   * @return
+   */
+  public Map<String, List<String>> findSequenceOntologyGroupings(
+          String givenTerm, List<String> targetTerms)
+  {
+    List<String> sortedTypes = new ArrayList<>(targetTerms);
+    Collections.sort(sortedTypes);
+  
+    Map<String, List<String>> parents = new HashMap<>();
+  
+    /*
+     * method: 
+     * walk up featureType and all of its parents
+     * find other feature types which are subsumed by each term
+     * add each distinct aggregation of included feature types to the map
+     */
+    List<String> candidates = new ArrayList<>();
+    SequenceOntologyI so = SequenceOntologyFactory.getInstance();
+    candidates.add(givenTerm);
+    while (!candidates.isEmpty())
+    {
+      String term = candidates.remove(0);
+      List<String> includedFeatures = new ArrayList<>();
+      for (String type : sortedTypes)
+      {
+        if (!type.equals(givenTerm) && so.isA(type, term))
+        {
+          includedFeatures.add(type);
+        }
+      }
+      if (!includedFeatures.isEmpty()
+              && !parents.containsValue(includedFeatures))
+      {
+        parents.put(term, includedFeatures);
+      }
+      candidates.addAll(so.getParents(term));
+    }
+  
+    return parents;
+  }
 }