Skip to content

Commit

Permalink
OWL 2 completeness (#644)
Browse files Browse the repository at this point in the history
* Fix missing class on qualified restrictions (#566)

* Update issue templates

Removed "outdated ontology" tag from Bug report.

* Update issue templates

Template for documentation related issues.

* - Update build widget script

* - Add README.md

* - Update package version

* - Update README.md

* Add routing support for ebi-lookup service (#631)

* - Add routing for ebi lookup service

* - Fix URL routing with env variable

* - Add console log
- Try diff caddy config

* - REVERT - Add console log
- REVERT - Try diff caddy config

* Add biolink (#632)

* Add biolink

* fix typo

* Owl2 completeness (#635)

* Union of constructors were not rendered on frontend.

* Self references should not be bold or a link. Fixed inconsistent ontology.

* UnionOf only applies to classes. Aligned examples with OWL2 Primer.

* implement datatypes

---------

Co-authored-by: James McLaughlin <james@mclgh.net>

* Add DCAT

* Testcases for stackoverflow and nesting issue introduced by efe665c. Main failing ontology on dev is genepio with minimal-genepio as example. This causes stackoverflow which causes nesting-error for subsequent ontologies processed.

* Recognise datatype leaf nodes to fix stackoverflow.

* Changed check for leaf node to just check for any builtin XML data type.

* Alignment of dev branch with stable branch.

---------

Co-authored-by: James McLaughlin <james@mclgh.net>
Co-authored-by: haider <haideriqbal1@hotmail.com>
Co-authored-by: Haider Iqbal <haideri@ebi.ac.uk>
  • Loading branch information
4 people authored Apr 10, 2024
1 parent 7e1b1d3 commit 3ce8a64
Show file tree
Hide file tree
Showing 29 changed files with 116,888 additions and 66 deletions.
2 changes: 2 additions & 0 deletions dataload/json2neo/src/main/java/OntologyScanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ private static void visitValue(String predicate, Object value, Set<String> outPr

visitValue(predicate, mapValue.get("value"), outProps, outEdgeProps);

} else if(types.contains("datatype")) {

} else {
throw new RuntimeException("???");
}
Expand Down
2 changes: 2 additions & 0 deletions dataload/json2solr/src/main/java/JSON2Solr.java
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ public static Object discardMetadata(Object obj) {
// (4) reification
return discardMetadata(dict.get("value"));

} else if(types.contains("datatype")) {
return null;
} else {
throw new RuntimeException("???");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,9 @@ public void writePropertyValue(JsonWriter writer, PropertyValue value, Set<Strin

}

private boolean isXMLBuiltinDatatype(String uri) {
return uri.startsWith("http://www.w3.org/2001/XMLSchema#");
}
public void writeValue(JsonWriter writer, PropertyValue value) throws IOException {
assert (value.axioms == null);

Expand Down Expand Up @@ -511,7 +514,14 @@ public void writeValue(JsonWriter writer, PropertyValue value) throws IOExceptio
writer.endObject();
break;
case URI:
writer.value(((PropertyValueURI) value).getUri());
String uri = ((PropertyValueURI) value).getUri();
OntologyNode uriNode = nodes.get(uri);
if(uriNode != null && !isXMLBuiltinDatatype(uri) && uriNode.types.contains(OntologyNode.NodeType.DATATYPE)) {
// special case for rdfs:Datatype; nest it as with a bnode instead of referencing
writeNode(writer, uriNode, Set.of("datatype"));
} else {
writer.value(uri);
}
break;
case RELATED:
writer.beginObject();
Expand Down Expand Up @@ -694,6 +704,10 @@ public void handleType(OntologyNode subjNode, Node type) {
case "http://www.w3.org/2002/07/owl#NegativePropertyAssertion":
subjNode.types.add(OntologyNode.NodeType.NEGATIVE_PROPERTY_ASSERTION);
break;

case "http://www.w3.org/2000/01/rdf-schema#Datatype":
subjNode.types.add(OntologyNode.NodeType.DATATYPE);
break;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ public enum NodeType {
ALL_DISJOINT_CLASSES("allDisjointClasses"),
ALL_DIFFERENT("allDifferent"),
ALL_DISJOINT_PROPERTIES("allDisjointProperties"),
NEGATIVE_PROPERTY_ASSERTION("negativePropertyAssertion");
NEGATIVE_PROPERTY_ASSERTION("negativePropertyAssertion"),
DATATYPE("datatype");

public final String name;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ public static void annotateShortForms(OntologyGraph graph) {
OntologyNode c = graph.nodes.get(id);
if (c.types.contains(OntologyNode.NodeType.CLASS) ||
c.types.contains(OntologyNode.NodeType.PROPERTY) ||
c.types.contains(OntologyNode.NodeType.INDIVIDUAL)) {
c.types.contains(OntologyNode.NodeType.INDIVIDUAL) ||
c.types.contains(OntologyNode.NodeType.DATATYPE)
) {

// skip bnodes
if(c.uri == null)
Expand Down
4 changes: 4 additions & 0 deletions ebi_ontologies.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"ontologies": [
{
"id": "dcat",
"ontology_purl": "https://www.w3.org/ns/dcat.ttl"
},
{
"id": "biolink",
"ontology_purl": "https://github.com/biolink/biolink-model/raw/master/project/owl/biolink_model.owl.ttl",
Expand Down
152 changes: 97 additions & 55 deletions frontend/src/components/ClassExpression.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,20 @@ export default function ClassExpression({

linkedEntities = linkedEntities.mergeWith(expr.linkedEntities)

const types = asArray(expr['type'])

if(types && types.indexOf('datatype') !== -1) {
// rdfs:Datatype
let equivClass = expr['http://www.w3.org/2002/07/owl#equivalentClass'];
if(equivClass) {
return <Fragment>
{ expr['label'] && <span>{expr['label']} </span> }
<ClassExpression currentEntity={currentEntity} ontologyId={ontologyId} entityType={'properties'} expr={equivClass} linkedEntities={linkedEntities} />
</Fragment>
}
}


///
/// 1. owl:Class expressions
///
Expand Down Expand Up @@ -312,43 +326,6 @@ export default function ClassExpression({
</span>
);
}

let minQualifiedCardinality = asArray(
expr["http://www.w3.org/2002/07/owl#minQualifiedCardinality"]
)[0];
if (minQualifiedCardinality) {
return (
<span>
<ClassExpression ontologyId={ontologyId} currentEntity={currentEntity} entityType={'properties'} expr={onProperty} linkedEntities={linkedEntities} />
<span className="px-1 text-embl-purple-default italic">min</span>
<ClassExpression
currentEntity={currentEntity}
ontologyId={ontologyId} entityType={'classes'}
expr={minQualifiedCardinality}
linkedEntities={linkedEntities}
/>
</span>
);
}

let maxQualifiedCardinality = asArray(
expr["http://www.w3.org/2002/07/owl#maxQualifiedCardinality"]
)[0];
if (maxQualifiedCardinality) {
return (
<span>
<ClassExpression ontologyId={ontologyId} currentEntity={currentEntity} entityType={'properties'} expr={onProperty} linkedEntities={linkedEntities} />
<span className="px-1 text-embl-purple-default italic">max</span>
<ClassExpression
currentEntity={currentEntity}
ontologyId={ontologyId} entityType={'classes'}
expr={maxQualifiedCardinality}
linkedEntities={linkedEntities}
/>
</span>
);
}

let exactCardinality = asArray(
expr["http://www.w3.org/2002/07/owl#cardinality"]
)[0];
Expand All @@ -362,24 +339,6 @@ export default function ClassExpression({
);
}

let exactQualifiedCardinality = asArray(
expr["http://www.w3.org/2002/07/owl#qualifiedCardinality"]
)[0];
if (exactQualifiedCardinality) {
return (
<span>
<ClassExpression ontologyId={ontologyId} currentEntity={currentEntity} entityType={'properties'} expr={onProperty} linkedEntities={linkedEntities} />
<span className="px-1 text-embl-purple-default italic">exactly</span>
<ClassExpression
ontologyId={ontologyId} entityType={'classes'}
currentEntity={currentEntity}
expr={exactQualifiedCardinality}
linkedEntities={linkedEntities}
/>
</span>
);
}

let hasSelf = asArray(expr["http://www.w3.org/2002/07/owl#hasSelf"])[0];
if (hasSelf) {
return (
Expand All @@ -391,6 +350,89 @@ export default function ClassExpression({
}


///
/// 4. owl:Restriction qualified cardinalities (property and class)
///
const onClass = expr["http://www.w3.org/2002/07/owl#onClass"];

if(onClass) {
let minQualifiedCardinality = asArray(
expr["http://www.w3.org/2002/07/owl#minQualifiedCardinality"]
)[0];
if (minQualifiedCardinality) {
return (
<span>
<ClassExpression ontologyId={ontologyId} currentEntity={currentEntity} entityType={'properties'} expr={onProperty} linkedEntities={linkedEntities} />
<span className="px-1 text-embl-purple-default italic">min</span>
<ClassExpression
currentEntity={currentEntity}
ontologyId={ontologyId} entityType={'classes'}
expr={minQualifiedCardinality}
linkedEntities={linkedEntities}
/>
&nbsp;
<ClassExpression
currentEntity={currentEntity}
ontologyId={ontologyId} entityType={'classes'}
expr={onClass}
linkedEntities={linkedEntities}
/>
</span>
);
}

let maxQualifiedCardinality = asArray(
expr["http://www.w3.org/2002/07/owl#maxQualifiedCardinality"]
)[0];
if (maxQualifiedCardinality) {
return (
<span>
<ClassExpression ontologyId={ontologyId} currentEntity={currentEntity} entityType={'properties'} expr={onProperty} linkedEntities={linkedEntities} />
<span className="px-1 text-embl-purple-default italic">max</span>
<ClassExpression
currentEntity={currentEntity}
ontologyId={ontologyId} entityType={'classes'}
expr={maxQualifiedCardinality}
linkedEntities={linkedEntities}
/>
&nbsp;
<ClassExpression
currentEntity={currentEntity}
ontologyId={ontologyId} entityType={'classes'}
expr={onClass}
linkedEntities={linkedEntities}
/>
</span>
);
}

let exactQualifiedCardinality = asArray(
expr["http://www.w3.org/2002/07/owl#qualifiedCardinality"]
)[0];
if (exactQualifiedCardinality) {
return (
<span>
<ClassExpression ontologyId={ontologyId} currentEntity={currentEntity} entityType={'properties'} expr={onProperty} linkedEntities={linkedEntities} />
<span className="px-1 text-embl-purple-default italic">exactly</span>
<ClassExpression
ontologyId={ontologyId} entityType={'classes'}
currentEntity={currentEntity}
expr={exactQualifiedCardinality}
linkedEntities={linkedEntities}
/>
&nbsp;
<ClassExpression
currentEntity={currentEntity}
ontologyId={ontologyId} entityType={'classes'}
expr={onClass}
linkedEntities={linkedEntities}
/>
</span>
);
}
}


return (
<span className="text-embl-red-default italic">
unknown class expression
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/EntityLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default function EntityLink({

// reference to self; just display label bc we are already on that page
if (currentEntity && iri === currentEntity.getIri()) {
return <b>{currentEntity.getName()}</b>;
return <span>{currentEntity.getName()}</span>;
}

const label =
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/model/Class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export default class Class extends Entity {
return asArray(this.properties['http://www.w3.org/2002/07/owl#disjointWith'])
}

getUnionOf() {
return asArray(this.properties['http://www.w3.org/2002/07/owl#unionOf'])
}

getHasKey() {
return asArray(this.properties['http://www.w3.org/2002/07/owl#hasKey'])
}
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/pages/ontologies/entities/EntityPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import DomainSection from "./entityPageSections/DomainSection";
import EntityAnnotationsSection from "./entityPageSections/EntityAnnotationsSection";
import EntityDescriptionSection from "./entityPageSections/EntityDescriptionSection";
import EntityEquivalentsSection from "./entityPageSections/EntityEquivalentsSection";
import UnionOfSection from "./entityPageSections/UnionOfSection";
import EntityImagesSection from "./entityPageSections/EntityImagesSection";
import EntityParentsSection from "./entityPageSections/EntityParentsSection";
import EntityRelatedFromSection from "./entityPageSections/EntityRelatedFromSection";
Expand Down Expand Up @@ -462,6 +463,10 @@ export default function EntityPage({
entity={entity}
linkedEntities={linkedEntities}
/>
<UnionOfSection
entity={entity}
linkedEntities={linkedEntities}
/>
<PropertyInverseOfSection
entity={entity}
linkedEntities={linkedEntities}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Fragment } from "react";
import { randomString } from "../../../../app/util";
import ClassExpression from "../../../../components/ClassExpression";
import EntityLink from "../../../../components/EntityLink";
import Entity from "../../../../model/Entity";
import Class from "../../../../model/Class";
import LinkedEntities from "../../../../model/LinkedEntities";
import Property from "../../../../model/Property";

export default function UnionOfSection({
entity,
linkedEntities,
}: {
entity: Entity;
linkedEntities: LinkedEntities;
}) {
if (!(entity instanceof Class)) {
return <Fragment />;
}

let unionOfs = entity.getUnionOf();

if (!unionOfs || unionOfs.length === 0) {
return <Fragment />;
}

return (
<div>
<div className="font-bold">Union of</div>
{unionOfs.length === 1 ? (
<p>
{typeof unionOfs[0] === "object" &&
!Array.isArray(unionOfs[0]) ? (
<ClassExpression
ontologyId={entity.getOntologyId()}
currentEntity={entity}
expr={unionOfs[0]}
linkedEntities={linkedEntities}
/>
) : (
<EntityLink
ontologyId={entity.getOntologyId()}
currentEntity={entity}
entityType={
entity.getType() === "property" ? "properties" : "classes"
}
iri={unionOfs[0]}
linkedEntities={linkedEntities}
/>
)}
</p>
) : (
<ul className="list-disc list-inside">
{unionOfs.map((disjointWith) => {
return (
<li key={randomString()}>
{typeof disjointWith === "object" &&
!Array.isArray(disjointWith) ? (
<ClassExpression
ontologyId={entity.getOntologyId()}
currentEntity={entity}
expr={disjointWith}
linkedEntities={linkedEntities}
/>
) : (
<EntityLink
ontologyId={entity.getOntologyId()}
currentEntity={entity}
entityType={
entity.getType() === "property" ? "properties" : "classes"
}
iri={disjointWith}
linkedEntities={linkedEntities}
/>
)}
</li>
);
})}
</ul>
)}
</div>
);
}
9 changes: 9 additions & 0 deletions testcases/datatypes/nesting-issue/datatype-enumeration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"ontologies": [
{
"id": "owl2primer-datatype-enumeration",
"preferredPrefix": "owl2primer-datatype-enumeration",
"ontology_purl": "./testcases/owl2-primer/datatype-enumeration.owl"
}
]
}
Loading

0 comments on commit 3ce8a64

Please sign in to comment.