Skip to content

Commit

Permalink
Merge pull request #1193 from ontodev/extend-drop-annotation-assertio…
Browse files Browse the repository at this point in the history
…n-selector

Add --drop-axiom-annotations feature with value constraints
  • Loading branch information
jamesaoverton authored May 2, 2024
2 parents 62e0d3d + d332928 commit fcc06fc
Show file tree
Hide file tree
Showing 8 changed files with 2,656 additions and 31 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed
- Updated `duplicate_exact_syonym` [`report`] query to be case-insensitive and ignore synoyms annotated as abbreviation or acronym synonym types [#1179]
- Extend `--drop-axiom-annotations` option to support value-specific removal of axiom annotations [#1193]
- Add `--enforce-obo-format`, `--exclude-named-classes` and `--include-subclass-of` features to relax command [#1060, #1183]

### Fixed
Expand Down
2,526 changes: 2,526 additions & 0 deletions docs/examples/filter_annotations_drop_axioms.owl

Large diffs are not rendered by default.

14 changes: 6 additions & 8 deletions docs/remove.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,11 @@ Create a "base" subset by removing external axioms (alternatively, use `filter -
--signature true \
--output results/filter_annotations.owl

Create a "base" subset in which axiom annotations involving IAO:0000117 and IAO:0000119 are removed:
Extracts a base module, then removing _all_ `oboInOwl:hasDbXref` annotations on the remaining axioms, and all `oboInOwl:hasDbXref` axiom annotations whose value matches the regular expression `GO.*`:

robot remove --input template.owl \
--base-iri http://example.com/ \
robot remove --input uberon_module.owl \
--base-iri http://purl.obolibrary.org/obo/UBERON_ \
--axioms external \
--drop-axiom-annotations IAO:0000117 \
--drop-axiom-annotations IAO:0000119 \
--output results/template-drop-axiom-remove.owl

--drop-axiom-annotations oboInOwl:source=~'GO.*' \
--drop-axiom-annotations oboInOwl:hasDbXref \
--output results/filter_annotations_drop_axioms.owl
Original file line number Diff line number Diff line change
Expand Up @@ -1121,4 +1121,36 @@ public static List<OWLOntology> getInputOntologies(
}
return inputOntologies;
}

/**
* Given an IOHelper and a list of unparsed patterns to select annotation assertions to be dropped
* build a Map of property IRIs, and value patterns for further processing.
*
* @param ioHelper the IOHelper to load the ontology with
* @param dropParameters The list of unparsed command line parameters describing the annotations
* to select
* @return A map of IRI to annotation value to drop
*/
public static Map<IRI, String> createAnnotationToDropMap(
IOHelper ioHelper, List<String> dropParameters) throws IOException {
Map<IRI, String> annotationsToDrop = new HashMap<>();

for (String dropParameter : dropParameters) {
if (dropParameter.equalsIgnoreCase("all")) {
// ignore, we communicate this through the dropParameters list
} else if (dropParameter.contains("=")) {
String[] parts = dropParameter.split("=");
String annotationIRI = parts[0];
String annotationValue = parts[1];
IRI iri =
CommandLineHelper.maybeCreateIRI(ioHelper, annotationIRI, "drop-axiom-annotations");
annotationsToDrop.put(iri, annotationValue);
} else {
IRI iri =
CommandLineHelper.maybeCreateIRI(ioHelper, dropParameter, "drop-axiom-annotations");
annotationsToDrop.put(iri, null);
}
}
return annotationsToDrop;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.semanticweb.owlapi.apibinding.OWLManager;
Expand Down Expand Up @@ -167,13 +167,9 @@ public CommandState execute(CommandState state, String[] args) throws Exception

List<String> dropParameters =
CommandLineHelper.getOptionalValues(line, "drop-axiom-annotations");
List<IRI> annotationsToDrop =
dropParameters.stream()
.filter(s -> !s.equalsIgnoreCase("all"))
.map(
curie ->
CommandLineHelper.maybeCreateIRI(ioHelper, curie, "drop-axiom-annotations"))
.collect(Collectors.toList());

Map<IRI, String> annotationsToDrop =
CommandLineHelper.createAnnotationToDropMap(ioHelper, dropParameters);

// Use the select statements to get a set of objects to filter
Set<OWLObject> relatedObjects =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.obolibrary.robot;

import java.util.*;
import java.util.stream.Collectors;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.semanticweb.owlapi.apibinding.OWLManager;
Expand Down Expand Up @@ -157,13 +156,9 @@ public CommandState execute(CommandState state, String[] args) throws Exception

List<String> dropParameters =
CommandLineHelper.getOptionalValues(line, "drop-axiom-annotations");
List<IRI> annotationsToDrop =
dropParameters.stream()
.filter(s -> !s.equalsIgnoreCase("all"))
.map(
curie ->
CommandLineHelper.maybeCreateIRI(ioHelper, curie, "drop-axiom-annotations"))
.collect(Collectors.toList());

Map<IRI, String> annotationsToDrop =
CommandLineHelper.createAnnotationToDropMap(ioHelper, dropParameters);

// Get the objects to remove
Set<OWLObject> relatedObjects = getObjects(line, ioHelper, ontology, selectGroups);
Expand Down
89 changes: 83 additions & 6 deletions robot-core/src/main/java/org/obolibrary/robot/OntologyHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import java.io.StringWriter;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.obolibrary.robot.checks.InvalidReferenceChecker;
import org.obolibrary.robot.export.RendererType;
import org.obolibrary.robot.providers.QuotedAnnotationValueShortFormProvider;
Expand Down Expand Up @@ -1658,13 +1660,29 @@ public static void trimOntology(OWLOntology ontology) {
* Removes all of the axiom annotations for the given annotation properties.
*
* @param ontology OWLOntology to remove axiom annotations
* @param properties Annotation property IRIs to remove related axiom annotations.
* @param properties List of annotation property IRIs to remove related axiom annotations.
*/
public static void removeAxiomAnnotations(OWLOntology ontology, List<IRI> properties) {
Map<IRI, String> annotationsToDrop = new HashMap<>();
properties.forEach(iri -> annotationsToDrop.put(iri, null));
removeAxiomAnnotations(ontology, annotationsToDrop);
}

/**
* Removes all of the axiom annotations for the given annotation properties.
*
* @param ontology OWLOntology to remove axiom annotations
* @param properties Annotation property IRIs to remove related axiom annotations.
*/
public static void removeAxiomAnnotations(
OWLOntology ontology, Map<IRI, String> annotationsToDrop) {
OWLDataFactory owlDataFactory = ontology.getOWLOntologyManager().getOWLDataFactory();
properties.stream()
.map(iri -> owlDataFactory.getOWLAnnotationProperty(iri))
.forEach(p -> OntologyHelper.removeAxiomAnnotations(ontology, p));

for (IRI iri : annotationsToDrop.keySet()) {
OWLAnnotationProperty property = owlDataFactory.getOWLAnnotationProperty(iri);
String value = annotationsToDrop.get(iri);
OntologyHelper.removeAxiomAnnotations(ontology, property, value);
}
}

/**
Expand All @@ -1674,11 +1692,57 @@ public static void removeAxiomAnnotations(OWLOntology ontology, List<IRI> proper
* @param property Annotation property to remove related axiom annotations.
*/
public static void removeAxiomAnnotations(OWLOntology ontology, OWLAnnotationProperty property) {
removeAxiomAnnotations(ontology, property, null);
}

/**
* Removes all of the axiom annotations for the given annotation property and an optional value
* pattern The value pattern should follow
* https://robot.obolibrary.org/remove#pattern-subset-selectors
*
* @param ontology OWLOntology to remove axiom annotations
* @param property Annotation property to remove related axiom annotations.
* @param value a value or value pattern the restrict what is deleted. Can be null.
*/
public static void removeAxiomAnnotations(
OWLOntology ontology, OWLAnnotationProperty property, String value) {
OWLOntologyManager manager = ontology.getOWLOntologyManager();
for (OWLAxiom axiom : ontology.getAxioms(Imports.EXCLUDED)) {
Set<OWLAnnotation> annotationsToRemove = axiom.getAnnotations(property);
Set<OWLAnnotation> annotationsToRemove = new HashSet<>();
Set<OWLAnnotation> allAxiomAnnotations = axiom.getAnnotations();
for (OWLAnnotation annotation : allAxiomAnnotations) {
if (annotation.getProperty().equals(property)) {
String annotationValue = getAnnotationValueAsStringOrNull(annotation);
if (value == null) {
// If there is no value set, we assume all annotations for the property should be
// removed
annotationsToRemove.add(annotation);
} else if (value.startsWith("~")) {
// If a value is set, and it starts with ~, we assume it is a regex pattern
String patternString = value.substring(1).replace("'", "");
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(annotationValue);
if (matcher.find()) {
annotationsToRemove.add(annotation);
}
} else {
// If a value is set, and it does not start with ~, we assume its an exact value
String processed_value = value.replace("'", "");
if (annotationValue.equals(processed_value)) {
annotationsToRemove.add(annotation);
} else {
logger.warn(
"Annotation assertion value pattern must start with ~' to indicate a regex pattern"
+ "or else correspond to the exact value. "
+ "The value is: "
+ value
+ ". Other patterns are not supported.");
}
}
}
}
if (!annotationsToRemove.isEmpty()) {
Set<OWLAnnotation> axiomAnnotations = axiom.getAnnotations();
Set<OWLAnnotation> axiomAnnotations = new HashSet<>(allAxiomAnnotations);
axiomAnnotations.removeAll(annotationsToRemove);
OWLAxiom cleanedAxiom =
axiom.getAxiomWithoutAnnotations().getAnnotatedAxiom(axiomAnnotations);
Expand All @@ -1689,6 +1753,19 @@ public static void removeAxiomAnnotations(OWLOntology ontology, OWLAnnotationPro
}
}

private static String getAnnotationValueAsStringOrNull(OWLAnnotation annotation) {
OWLAnnotationValue v = annotation.getValue();
if (v.isIRI()) {
return v.asIRI().get().toString();
} else if (v.isLiteral()) {
return v.asLiteral().get().getLiteral().toString();
} else if (v.isIndividual()) {
return v.asAnonymousIndividual().get().toString();
} else {
return null;
}
}

/**
* Removes all axiom annotations from the given ontology.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2409,7 +2409,7 @@ private static void spanGapsHelper(
* @param dropParameters list of drop-axiom-annotations parameters
*/
public static void dropAxiomAnnotations(
OWLOntology ontology, List<IRI> annotationsToDrop, List<String> dropParameters) {
OWLOntology ontology, Map<IRI, String> annotationsToDrop, List<String> dropParameters) {
if (dropParameters.stream().anyMatch(x -> x.equalsIgnoreCase("all"))) {
OntologyHelper.removeAllAxiomAnnotations(ontology);
} else {
Expand Down

0 comments on commit fcc06fc

Please sign in to comment.