Skip to content

Commit 689dc0e

Browse files
author
hdietze
committed
GAF to lego all individual OWL
* re-implement the GAF/GeneAnnotation translation into an all-individual OWL model * add command-line method to run translation * see issue #117
1 parent 27909e3 commit 689dc0e

File tree

2 files changed

+480
-0
lines changed

2 files changed

+480
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
package owltools.gaf.lego;
2+
3+
import java.util.Collection;
4+
import java.util.Collections;
5+
import java.util.HashSet;
6+
import java.util.List;
7+
import java.util.Map;
8+
import java.util.Set;
9+
import java.util.UUID;
10+
11+
import org.apache.commons.lang3.StringUtils;
12+
import org.apache.log4j.Logger;
13+
import org.semanticweb.owlapi.model.AddImport;
14+
import org.semanticweb.owlapi.model.IRI;
15+
import org.semanticweb.owlapi.model.OWLAnnotation;
16+
import org.semanticweb.owlapi.model.OWLAnnotationProperty;
17+
import org.semanticweb.owlapi.model.OWLAxiom;
18+
import org.semanticweb.owlapi.model.OWLClass;
19+
import org.semanticweb.owlapi.model.OWLClassExpression;
20+
import org.semanticweb.owlapi.model.OWLDataFactory;
21+
import org.semanticweb.owlapi.model.OWLException;
22+
import org.semanticweb.owlapi.model.OWLImportsDeclaration;
23+
import org.semanticweb.owlapi.model.OWLNamedIndividual;
24+
import org.semanticweb.owlapi.model.OWLObject;
25+
import org.semanticweb.owlapi.model.OWLObjectProperty;
26+
import org.semanticweb.owlapi.model.OWLOntology;
27+
import org.semanticweb.owlapi.model.OWLOntologyID;
28+
import org.semanticweb.owlapi.model.OWLOntologyManager;
29+
30+
import owltools.gaf.Bioentity;
31+
import owltools.gaf.ExtensionExpression;
32+
import owltools.gaf.GafDocument;
33+
import owltools.gaf.GeneAnnotation;
34+
import owltools.graph.OWLGraphWrapper;
35+
import owltools.vocab.OBOUpperVocabulary;
36+
37+
38+
/**
39+
* Simple translation of {@link GeneAnnotation} to the all individual lego annotation model.
40+
*
41+
*/
42+
public class GafToLegoIndividualTranslator {
43+
44+
private static Logger logger = Logger.getLogger(GafToLegoIndividualTranslator.class);
45+
46+
private final OWLGraphWrapper graph;
47+
private final OWLObjectProperty partOf;
48+
private final OWLObjectProperty occursIn;
49+
private final OWLObjectProperty inTaxon;
50+
private OWLClass mf;
51+
private OWLObjectProperty enabledBy;
52+
53+
private Map<String, OWLObject> allOWLObjectsByAltId;
54+
55+
private final boolean addLineNumber;
56+
57+
public GafToLegoIndividualTranslator(OWLGraphWrapper graph, boolean addLineNumber) {
58+
this.graph = graph;
59+
this.addLineNumber = addLineNumber;
60+
allOWLObjectsByAltId = graph.getAllOWLObjectsByAltId();
61+
OWLDataFactory df = graph.getDataFactory();
62+
partOf = OBOUpperVocabulary.BFO_part_of.getObjectProperty(df);
63+
occursIn = OBOUpperVocabulary.BFO_occurs_in.getObjectProperty(df);
64+
65+
mf = OBOUpperVocabulary.GO_molecular_function.getOWLClass(df);
66+
enabledBy = OBOUpperVocabulary.GOREL_enabled_by.getObjectProperty(df);
67+
inTaxon = graph.getOWLObjectPropertyByIdentifier("RO:0002162"); // in taxon
68+
}
69+
70+
protected void reportError(String error, GeneAnnotation annotation) {
71+
logger.error(error+" \t Annotation: "+annotation.toString());
72+
}
73+
74+
protected void reportWarn(String warning, GeneAnnotation annotation) {
75+
logger.warn(warning+" \t Annotation: "+annotation.toString());
76+
}
77+
78+
/**
79+
* Translate the given {@link GafDocument} into an OWL representation of the LEGO model.
80+
*
81+
* @param gaf
82+
* @return lego ontology
83+
* @throws OWLException
84+
*/
85+
public OWLOntology translate(GafDocument gaf) throws OWLException {
86+
final OWLOntologyManager m = graph.getManager();
87+
OWLOntology lego = m.createOntology(IRI.generateDocumentIRI());
88+
OWLOntology sourceOntology = graph.getSourceOntology();
89+
OWLOntologyID ontologyID = sourceOntology.getOntologyID();
90+
if (ontologyID != null) {
91+
IRI ontologyIRI = ontologyID.getOntologyIRI();
92+
if (ontologyIRI != null) {
93+
OWLDataFactory f = m.getOWLDataFactory();
94+
OWLImportsDeclaration importDeclaration = f.getOWLImportsDeclaration(ontologyIRI);
95+
m.applyChange(new AddImport(lego, importDeclaration ));
96+
}
97+
}
98+
translate(gaf.getGeneAnnotations(), lego);
99+
return lego;
100+
}
101+
102+
/**
103+
* Translate the given annotations ({@link GeneAnnotation}) into an OWL representation of the LEGO model.
104+
*
105+
* @param annotations
106+
* @param lego
107+
* @throws OWLException
108+
*/
109+
public void translate(Collection<GeneAnnotation> annotations, final OWLOntology lego) throws OWLException {
110+
final OWLOntologyManager m = graph.getManager();
111+
112+
Set<OWLAxiom> axioms = new HashSet<OWLAxiom>();
113+
for(GeneAnnotation annotation : annotations) {
114+
translate(annotation, axioms);
115+
}
116+
m.addAxioms(lego, axioms);
117+
}
118+
119+
/**
120+
* Translate theGeneAnnotation into an OWL representation of the LEGO model.
121+
*
122+
* @param annotation
123+
* @param axioms
124+
* @throws OWLException
125+
*/
126+
public void translate(GeneAnnotation annotation, Set<OWLAxiom> axioms) throws OWLException {
127+
// skip ND annotations
128+
if ("ND".equals(annotation.getShortEvidence())) {
129+
reportWarn("Skipping ND annotation", annotation);
130+
return;
131+
}
132+
// skip annotation using a qualifier
133+
String rel = StringUtils.trimToNull(annotation.getRelation());
134+
if (rel != null) {
135+
if ("enables".equals(rel) == false && "part_of".equals(rel) == false && "involved_in".equals(rel) == false) {
136+
reportWarn("Skipping annotation with unsupported relation: "+annotation.getRelation(), annotation);
137+
return;
138+
}
139+
}
140+
141+
final OWLDataFactory f = graph.getDataFactory();
142+
143+
144+
final String annotationClsString = annotation.getCls();
145+
final OWLClass c = getOwlClass(annotationClsString);
146+
if (c == null) {
147+
reportError("Could not find a class for the given identifier: "+annotationClsString, annotation);
148+
return;
149+
}
150+
151+
List<List<ExtensionExpression>> extensionExpressionGroups = annotation.getExtensionExpressions();
152+
if (extensionExpressionGroups != null && !extensionExpressionGroups.isEmpty()) {
153+
Set<OWLClassExpression> parsedGroups = new HashSet<OWLClassExpression>();
154+
for(List<ExtensionExpression> group : extensionExpressionGroups) {
155+
Set<OWLClassExpression> operands = new HashSet<OWLClassExpression>();
156+
for(ExtensionExpression extension : group) {
157+
final String extensionClsString = extension.getCls();
158+
final String extensionRelationString = extension.getRelation();
159+
OWLClass extensionCls = getOwlClass(extensionClsString);
160+
if (extensionCls == null) {
161+
IRI extensionIRI = IdStringManager.getIRI(extensionClsString);
162+
extensionCls = f.getOWLClass(extensionIRI);
163+
}
164+
final OWLObjectProperty extensionRelation = graph.getOWLObjectPropertyByIdentifier(extensionRelationString);
165+
if (extensionRelation == null) {
166+
reportError("Could not find a class for the given extension relation identifier: "+extensionRelationString, annotation);
167+
continue;
168+
}
169+
operands.add(f.getOWLObjectSomeValuesFrom(extensionRelation, extensionCls));
170+
}
171+
operands.add(c);
172+
parsedGroups.add(f.getOWLObjectIntersectionOf(operands));
173+
}
174+
if (annotation.isNegated()) {
175+
OWLClassExpression union = f.getOWLObjectUnionOf(parsedGroups);
176+
translate(annotation, union, axioms);
177+
}
178+
else {
179+
for(OWLClassExpression ce : parsedGroups) {
180+
translate(annotation, ce, axioms);
181+
}
182+
}
183+
}
184+
else {
185+
translate(annotation, c, axioms);
186+
}
187+
}
188+
189+
190+
private void translate(GeneAnnotation annotation, OWLClassExpression ce, Set<OWLAxiom> axioms) throws OWLException {
191+
final OWLDataFactory f = graph.getDataFactory();
192+
193+
// # STEP 1 - Bioentity instance
194+
final Bioentity bioentity = annotation.getBioentityObject();
195+
final String isoForm = StringUtils.trimToNull(annotation.getGeneProductForm());
196+
197+
final OWLClass bioentityClass;
198+
if (isoForm == null) {
199+
// option #1: default bioentity id
200+
bioentityClass = addBioentityCls(bioentity.getId(), bioentity.getSymbol(), bioentity.getNcbiTaxonId(), axioms, f);
201+
}
202+
else {
203+
// option #2: ISO-form as subclass of bioentity
204+
bioentityClass = addBioentityCls(isoForm, bioentity.getSymbol()+" ISO Form "+isoForm, bioentity.getNcbiTaxonId(), axioms, f);
205+
OWLClass bioentityClassSuper = addBioentityCls(bioentity.getId(), bioentity.getSymbol(), bioentity.getNcbiTaxonId(), axioms, f);
206+
axioms.add(f.getOWLDeclarationAxiom(bioentityClassSuper));
207+
axioms.add(f.getOWLSubClassOfAxiom(bioentityClass, bioentityClassSuper));
208+
}
209+
210+
IRI bioentityInstanceIRI = generateNewIRI("bioentity", bioentityClass);
211+
OWLNamedIndividual bioentityInstance = f.getOWLNamedIndividual(bioentityInstanceIRI);
212+
axioms.add(f.getOWLDeclarationAxiom(bioentityInstance));
213+
axioms.add(f.getOWLClassAssertionAxiom(bioentityClass, bioentityInstance));
214+
215+
// # STEP 2 - create instance:
216+
217+
// use Aspect to switch between the three options: P == BP, C == CC, F = MF
218+
String aspect = annotation.getAspect();
219+
if (aspect == null) {
220+
reportError("Error, no aspect defined.", annotation);
221+
return;
222+
}
223+
224+
// TODO evidence
225+
Set<OWLAnnotation> annotations = Collections.emptySet();
226+
if (addLineNumber) {
227+
int lineNumber = annotation.getSource().getLineNumber();
228+
OWLAnnotation source = f.getOWLAnnotation(getLineNumberProperty(axioms, f), f.getOWLLiteral(lineNumber));
229+
annotations = Collections.singleton(source);
230+
}
231+
boolean negated = annotation.isNegated();
232+
if (negated) {
233+
handleNegated(bioentityClass, aspect, annotations, ce, axioms, f);
234+
return;
235+
}
236+
237+
//List<String> sources = annotation.getReferenceIds();
238+
if ("F".equals(aspect)) {
239+
// create individual
240+
OWLNamedIndividual individual = f.getOWLNamedIndividual(generateNewIRI("mf", ce));
241+
axioms.add(f.getOWLDeclarationAxiom(individual));
242+
243+
// types
244+
axioms.add(f.getOWLClassAssertionAxiom(ce, individual));
245+
246+
// link instances
247+
248+
axioms.add(f.getOWLObjectPropertyAssertionAxiom(enabledBy, individual, bioentityInstance, annotations));
249+
}
250+
else if ("C".equals(aspect)) {
251+
// generic mf instance
252+
OWLNamedIndividual mfIndividual = f.getOWLNamedIndividual(generateNewIRI("mf", mf));
253+
axioms.add(f.getOWLDeclarationAxiom(mfIndividual));
254+
255+
// generic mf type
256+
axioms.add(f.getOWLClassAssertionAxiom(mf, mfIndividual));
257+
258+
// link mf to bioentity
259+
axioms.add(f.getOWLObjectPropertyAssertionAxiom(enabledBy, mfIndividual, bioentityInstance));
260+
261+
// cc instance
262+
OWLNamedIndividual ccIndividual = f.getOWLNamedIndividual(generateNewIRI("cc", ce));
263+
axioms.add(f.getOWLDeclarationAxiom(ccIndividual));
264+
265+
// cc type
266+
axioms.add(f.getOWLClassAssertionAxiom(ce, ccIndividual));
267+
268+
// link cc and mf
269+
axioms.add(f.getOWLObjectPropertyAssertionAxiom(occursIn, ccIndividual, mfIndividual, annotations));
270+
271+
272+
}
273+
else if ("P".equals(aspect)) {
274+
// generic mf instance
275+
OWLNamedIndividual mfIndividual = f.getOWLNamedIndividual(generateNewIRI("mf", mf));
276+
axioms.add(f.getOWLDeclarationAxiom(mfIndividual));
277+
278+
// generic mf type
279+
axioms.add(f.getOWLClassAssertionAxiom(mf, mfIndividual));
280+
281+
// link mf to bioentity
282+
axioms.add(f.getOWLObjectPropertyAssertionAxiom(enabledBy, mfIndividual, bioentityInstance));
283+
284+
// cc instance
285+
OWLNamedIndividual bpIndividual = f.getOWLNamedIndividual(generateNewIRI("bp", ce));
286+
axioms.add(f.getOWLDeclarationAxiom(bpIndividual));
287+
288+
// cc type
289+
axioms.add(f.getOWLClassAssertionAxiom(ce, bpIndividual));
290+
291+
// link cc and mf
292+
axioms.add(f.getOWLObjectPropertyAssertionAxiom(partOf, bpIndividual, mfIndividual, annotations));
293+
}
294+
}
295+
296+
private void handleNegated(OWLClass bioentityClass, String aspect, Set<OWLAnnotation> annotations,
297+
OWLClassExpression ce, Set<OWLAxiom> axioms, OWLDataFactory f) {
298+
if ("F".equals(aspect)) {
299+
OWLClassExpression notCE = f.getOWLObjectComplementOf(f.getOWLObjectSomeValuesFrom(enabledBy, ce));
300+
axioms.add(f.getOWLSubClassOfAxiom(bioentityClass, notCE, annotations));
301+
}
302+
else if ("C".equals(aspect)) {
303+
OWLClassExpression notCE = f.getOWLObjectComplementOf(f.getOWLObjectSomeValuesFrom(occursIn, ce));
304+
axioms.add(f.getOWLSubClassOfAxiom(bioentityClass, notCE, annotations));
305+
}
306+
else if ("P".equals(aspect)) {
307+
OWLClassExpression notCE = f.getOWLObjectComplementOf(f.getOWLObjectSomeValuesFrom(partOf, ce));
308+
axioms.add(f.getOWLSubClassOfAxiom(bioentityClass, notCE, annotations));
309+
}
310+
}
311+
312+
private OWLClass addBioentityCls(String id, String lbl, String taxon, Set<OWLAxiom> axioms, OWLDataFactory f) {
313+
IRI iri = IdStringManager.getIRI(id);
314+
OWLClass cls = f.getOWLClass(iri);
315+
boolean add = axioms.add(f.getOWLDeclarationAxiom(cls));
316+
if (add) {
317+
OWLAnnotation annotation = f.getOWLAnnotation(f.getRDFSLabel(), f.getOWLLiteral(lbl));
318+
axioms.add(f.getOWLAnnotationAssertionAxiom(iri, annotation));
319+
if (taxon != null) {
320+
OWLClass taxonClass = f.getOWLClass(IdStringManager.getIRI(taxon));
321+
axioms.add(f.getOWLDeclarationAxiom(taxonClass));
322+
axioms.add(f.getOWLSubClassOfAxiom(cls,
323+
f.getOWLObjectSomeValuesFrom(inTaxon, taxonClass)));
324+
}
325+
}
326+
return cls;
327+
}
328+
329+
/**
330+
* @param id
331+
* @return cls or null
332+
*/
333+
private OWLClass getOwlClass(String id) {
334+
OWLClass cls = graph.getOWLClassByIdentifier(id);
335+
if (cls == null) {
336+
// check alt ids
337+
OWLObject owlObject = allOWLObjectsByAltId.get(id);
338+
if (owlObject != null && owlObject instanceof OWLClass) {
339+
cls = (OWLClass) owlObject;
340+
}
341+
}
342+
return cls;
343+
}
344+
345+
346+
private static final IRI GAF_LINE_NUMBER = IRI.create("http://gaf/line_number");
347+
348+
private OWLAnnotationProperty getLineNumberProperty(Set<OWLAxiom> axioms, OWLDataFactory f) {
349+
OWLAnnotationProperty p = f.getOWLAnnotationProperty(GAF_LINE_NUMBER);
350+
axioms.add(f.getOWLDeclarationAxiom(p));
351+
return p;
352+
}
353+
354+
private IRI generateNewIRI(String type, OWLClassExpression ce) {
355+
if( ce.isAnonymous() == false) {
356+
OWLClass c = ce.asOWLClass();
357+
String id = StringUtils.replaceOnce(IdStringManager.getId(c.getIRI()), ":", "_");
358+
type = type + "-" + id;
359+
}
360+
return IRI.create("http://geneontology.org/lego/"+type+"-"+UUID.randomUUID().toString());
361+
362+
}
363+
364+
}

0 commit comments

Comments
 (0)